Skip to content

Commit

Permalink
Breaking change: Change the function name so that IDEs can properly s…
Browse files Browse the repository at this point in the history
…uggest it. (#7)

* Change the function name to be able to be more easily imported (some IDEs actively avoid suggesting importing something named "main")

* Wordsmithing.

* Wordsmithing #2
  • Loading branch information
flipbit03 authored Dec 7, 2024
1 parent 5b10273 commit ebc2cf1
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 15 deletions.
41 changes: 34 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
# @main
# @python_main

[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/python-main)](https://pypi.org/project/python-main/)
[![PyPI - Version](https://img.shields.io/pypi/v/python-main)](https://pypi.org/project/python-main/)


`@main` decorator which runs the tagged function if the current module is being executed as a script.
`@python_main` is a decorator which:
- Automatically calls the function(s) tagged with it, if the current module is being **executed as a script**.
- Does nothing if the current module is being **imported**.

No more `if __name__ == "__main__":` all over the place.
It is, essentially, equivalent to the `if __name__ == "__main__":` construct, but as a decorator.

That's it!
That's all it does.

### Installation

Expand All @@ -20,14 +22,39 @@ poetry add python-main # ...
### Usage

```python
from python_main import main
from python_main import python_main

A = 10
B = 20


@main
@python_main
def do_print():
"""This will run if this module is executed."""
print(A + B)
```

You can also tag multiple functions with `@python_main` and they will all run if the module is executed, in the order they are defined.

```python
from python_main import python_main

A = 10
B = 20
C = 0

@python_main
def add_a_to_c():
global C
C += A

# ... other functions/ definitions ...

@python_main
def add_b_to_c():
global C
C += B

# At this point:
# - C will be 30 if this module is executed as a script.
# - C will be untouched if this module is imported.
```
15 changes: 10 additions & 5 deletions python_main/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@
__MAIN_RETURN_TYPE = TypeVar("__MAIN_RETURN_TYPE")


def main(f: Callable[[], __MAIN_RETURN_TYPE]) -> Callable[[], __MAIN_RETURN_TYPE]:
if getattr(f, __CALLABLE_MODULE_PROP) == __RAN_AS_SCRIPT_MODULE:
f()
return f
def python_main(
main_function_to_be_called: Callable[[], __MAIN_RETURN_TYPE]
) -> Callable[[], __MAIN_RETURN_TYPE]:
if (
getattr(main_function_to_be_called, __CALLABLE_MODULE_PROP)
== __RAN_AS_SCRIPT_MODULE
):
main_function_to_be_called()
return main_function_to_be_called


# Only export the main function
__all__ = ["main"]
__all__ = ["python_main"]
6 changes: 3 additions & 3 deletions tests/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import pytest

from python_main import main
from python_main import python_main

EXIT_CODE_RECEIVED = -1

Expand Down Expand Up @@ -44,7 +44,7 @@ def test_assert_function_actually_gets_called(mock_exit):
__my_main_func.__module__ = "__main__"

# Decorate it
main(__my_main_func)
python_main(__my_main_func)

# Ensure that our main function was able to call mock_exit with the expected value.
global EXIT_CODE_RECEIVED
Expand All @@ -60,7 +60,7 @@ def test_assert_function_does_not_get_called(mock_exit):
"""

# Call the function, which is coming from a pytest execution and being imported as a module
function_returned = main(__my_main_func)
function_returned = python_main(__my_main_func)

# Exit code will not have been set.
global EXIT_CODE_RECEIVED
Expand Down

0 comments on commit ebc2cf1

Please sign in to comment.