Misc ==== This is a catch-all section for general notes on PyPIConGPU. Python Concepts --------------- Some common concepts recurr throughout the code and are not explained in detail when used. This aims to give a non-exhaustive list of such patterns. They are as close to “standard python” as possible, so using a search engine/asking a python expert should also help you understand them. Type Checking with Typeguard ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use as defined in `PEP 484 “Type Hints” `_. Briefly: .. code:: python def greeting(name: str) -> str: return 'Hello ' + name Note that these type annotations are **not checked by python** on their own. Typechecks are enabled through `typeguard `__, mostly using the annotation ``@typeguard.typechecked`` for classes. **This does not check attribute type annotations, see next section.** Typesafe Class Attributes ^^^^^^^^^^^^^^^^^^^^^^^^^ Class attributes can use type annotations according to PEP 484, but this is not enforced by typeguard. The solution is to use `properties `_. In the code you will see: .. code:: python class SomeObject: attr = util.build_typesafe_property(int) Now the following hold: 1. Accessing ``attr`` before it has been set will **raise an exception** 2. Assigning ``attr`` anything other than an ``int`` will raise a ``TypeError`` .. Note: instead of types you can use specifications provided by ``import typing``, e.g. ``typing.Optional[int]``. Optional vars still have **no default**, so you have to set them to ``None`` explicitly if you don’t want to provide them. Internally the declaration above is expanded to the equivalent of: .. code:: python @typeguard.typechecked def getter(self) -> int: if not hasattr(self, "actual_name_for_var__attr"): raise AttributeError("variable is not initialized") return getattr(self, "actual_name_for_var__attr") @typeguard.typechecked def setter(self, value: int) -> None: setattr(self, "actual_name_for_var__attr", value) class SomeObject: attr = property(getter, setter) Map-Filter-Reduce ^^^^^^^^^^^^^^^^^ ``map()``, ``filter()``, and ``reduce()`` are “higher-order functions” and a basis of the functional programming paradigm (as opposed to loops for iterative processing). You can find an an introduction `here `_ (but any other intro is probably fine too). Boils down to: .. code:: python [2, 4, 6] == list(map(lambda x: 2*x, [1, 2, 3])) .. ``map()`` does not return a list directly and must be cast again. (Python, why?) ``map()`` does not work on dictionaries, to for this the dictionary is cast to a set of key-value tuples: .. code:: python {"a": 3, "b": 0} == dict(map( lambda kv_pair: (kv_pair[0], len(kv_pair[1])), {"a": [0, 0, 0], "b": []}.items())) .. Note: Do not feel obliged to follow this pattern. It is commonly used, because it allows a concise notation, yet it is very much **not** mandatory. .. _pypicongpu-misc-toolsupport: Tool Support ------------ This is a short list of tools to aid you with development. Formatting ^^^^^^^^^^ `PEP 8 `_ (formatting guidelines) compliance: run from repo root ``flake8 lib/python/ test/python/`` Note: Please obey the line length from PEP 8 even if that is annoying at times, this makes viewing files side-by-side much simpler. Run Tests ^^^^^^^^^ go into ``test/python/picongpu``, execute ``python -m quick`` (for tests with compilation ``python -m compiling``) Test Coverage ^^^^^^^^^^^^^ 0. install `coverage.py `_: ``pip install coverage`` 1. go to tests: ``cd test/python/picongpu`` 2. execute tests, record coverage: ``coverage run --branch -m quick`` 3. view reports - for PyPIConGPU: ``find ../../../lib/python/picongpu/pypicongpu/ -name '*.py' | xargs coverage report -m`` - for PICMI: ``find ../../../lib/python/picongpu/picmi/ -name '*.py' | xargs coverage report -m`` - Goal is 100% coverage (missing sections are printed) For further options see `the coverage.py doc `_. .. _pypicongpu-misc-apidoc: API Documentation ----------------- Document the API using docstrings, which will be rendered by `Sphinx AutoAPI `_ automatically. The result is available from the TOC, although the name is generated to be the python module name: :doc:`autoapi/picongpu/pypicongpu/index`. The configuration is placed in Sphinx's ``conf.py``, all classes are traversed by using ``__all__`` defined in **every** ``__init__.py``. Additional checks (completeness etc.) are **NOT** employed (and not even possible). So pay attention that you document everything you need. As everything is passed to Sphinx, **docstring should be valid** `reStructuredText `_. (`reStructuredText quick guide from Sphinx `_) You may use `Sphinx-exclusive directives `_ too, e.g. ``:ref:`MARK```. To document parameters, return values etc. make them compatible with Sphinx's autodoc. For details please refer to `the respective documentation section `_. .. note:: If there is an reStructuredText syntax error during generation (printed as warning after sphinx invocation ``make html``) to debug: 1. visit the respective page 2. click *View page source* at the top of the page (This might be only availble **locally**, the online version displays *Edit on GitHub* instead) An example can be found in `the official documentation `_. The types are implictly given by the `type hints `_, so these can be omitted: .. literalinclude:: ./doc_example.py :language: python Note that ``:raises TypeError:`` is omitted too, because all functions are checked for types anyways. This produces the following code section: .. autofunction:: doc_example.my_func