From ebc2cf1cb49e5e44e544b3bfb64ea54a85c13ef0 Mon Sep 17 00:00:00 2001 From: Cadu Date: Sat, 7 Dec 2024 17:45:57 -0300 Subject: [PATCH] Breaking change: Change the function name so that IDEs can properly suggest 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 --- README.md | 41 ++++++++++++++++++++++++++++++++++------- python_main/__init__.py | 15 ++++++++++----- tests/test_basic.py | 6 +++--- 3 files changed, 47 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index e205973..8756322 100644 --- a/README.md +++ b/README.md @@ -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 @@ -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. +``` diff --git a/python_main/__init__.py b/python_main/__init__.py index 2b00fe9..9e42b3c 100644 --- a/python_main/__init__.py +++ b/python_main/__init__.py @@ -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"] diff --git a/tests/test_basic.py b/tests/test_basic.py index 21ae8d7..5fbab06 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -2,7 +2,7 @@ import pytest -from python_main import main +from python_main import python_main EXIT_CODE_RECEIVED = -1 @@ -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 @@ -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