From 2955dac302ef6525013aceb5320ef22f32a68285 Mon Sep 17 00:00:00 2001 From: Jorge Martinez Date: Wed, 18 May 2022 10:56:36 +0200 Subject: [PATCH 01/18] Move coding_style/ -> coding-style/ --- doc/source/{coding_style => coding-style}/beyond_pep8.rst | 0 doc/source/{coding_style => coding-style}/flake8.rst | 0 doc/source/{coding_style => coding-style}/index.rst | 0 doc/source/{coding_style => coding-style}/pep8_best_practices.rst | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename doc/source/{coding_style => coding-style}/beyond_pep8.rst (100%) rename doc/source/{coding_style => coding-style}/flake8.rst (100%) rename doc/source/{coding_style => coding-style}/index.rst (100%) rename doc/source/{coding_style => coding-style}/pep8_best_practices.rst (100%) diff --git a/doc/source/coding_style/beyond_pep8.rst b/doc/source/coding-style/beyond_pep8.rst similarity index 100% rename from doc/source/coding_style/beyond_pep8.rst rename to doc/source/coding-style/beyond_pep8.rst diff --git a/doc/source/coding_style/flake8.rst b/doc/source/coding-style/flake8.rst similarity index 100% rename from doc/source/coding_style/flake8.rst rename to doc/source/coding-style/flake8.rst diff --git a/doc/source/coding_style/index.rst b/doc/source/coding-style/index.rst similarity index 100% rename from doc/source/coding_style/index.rst rename to doc/source/coding-style/index.rst diff --git a/doc/source/coding_style/pep8_best_practices.rst b/doc/source/coding-style/pep8_best_practices.rst similarity index 100% rename from doc/source/coding_style/pep8_best_practices.rst rename to doc/source/coding-style/pep8_best_practices.rst From 3ebd904d56bbe248df31e2f18d516cd18aba52b1 Mon Sep 17 00:00:00 2001 From: Jorge Martinez Date: Wed, 18 May 2022 10:57:31 +0200 Subject: [PATCH 02/18] Remove beyond_pep8.rst and flake8.rst --- doc/source/coding-style/beyond_pep8.rst | 306 ------------------------ doc/source/coding-style/flake8.rst | 252 ------------------- 2 files changed, 558 deletions(-) delete mode 100644 doc/source/coding-style/beyond_pep8.rst delete mode 100644 doc/source/coding-style/flake8.rst diff --git a/doc/source/coding-style/beyond_pep8.rst b/doc/source/coding-style/beyond_pep8.rst deleted file mode 100644 index b334d0d9..00000000 --- a/doc/source/coding-style/beyond_pep8.rst +++ /dev/null @@ -1,306 +0,0 @@ -Beyond PEP8 -########### -This topic describes any delineations, clarifications, or additional procedures above and -beyond `PEP8 `__. - -For example, `Stack Overflow Answer `_ -outlines deprecation best practices and a `Deprecation library `_ -already exists. However, there is no official guidance regarding deprecating features -in an API within Python. This page seeks to clarify this issue and others. - -Aside from the following PyAnsys-specific directives, the best coding practice is to -follow established guidelines from `PEP8 `__. - - -Deprecation Best Practice -------------------------- -Whenever a method, class, or function is deprecated, you must provide -an old method that both calls the new method and raises a warning. Or, -if the method has been removed, you must raise an ``AttributeError``. - -In the docstring of the older method, provide a `Sphinx Deprecated Directive -`_ -and a link to the newer method. This way, users are notified that an API change -has occurred and are given an opportunity to change their code. Otherwise, -stability concerns can cause users to stop upgrading, or worse, stop using -Ansys APIs. For this reason, it's best to use a warning first and then use -an error after a minor release or two. - - -.. code:: python - - class FieldAnalysis2D(): - """Class docstring""" - - def assignmaterial(self, obj, mat): - """Assign a material to one or more objects. - - .. deprecated:: 0.4.0 - Use :func:`FieldAnalysis2D.assign_material` instead. - - """ - # one of the following: - - # raise a DeprecationWarning. User won't have to change anything. - warnings.warn('assignmaterial is deprecated. Use assign_material instead.', - DeprecationWarning) - self.assign_material(obj, mat) - - # or raise an AttributeError (could also make a custom DeprecationError) - raise AttributeError('assignmaterial is deprecated. Use assign_material instead.') - - def assign_material(self, obj, mat): - """Assign a material to one or more objects. - ... - - -If a method is removed entirely, there's no reason to provide a link -to the old method. If the method is part of a class, raise an -``AttributeError``. Otherwise, raise an ``Exception``. - -This example raises an ``Exception``: - -.. code:: python - - def hello_world(): - """Print ``"hello_world"`` - - .. deprecated:: 0.4.0 - This function has been deprecated. - - """ - raise Exception('`my_function` has been deprecated.') - -Because there is no built-in deprecation error within -Python, an alternative is to create a custom ``DeprecationError``. - -.. code:: python - - class DeprecationError(RuntimeError): - """Used for depreciated methods and functions.""" - - def __init__(self, message='This feature has been depreciated.'): - """Empty init.""" - RuntimeError.__init__(self, message) - -You can then use this custom ``DeprecationError`` in place of an ``Exception``. - -.. code:: python - - def hello_world(): - """Print ``"hello_world"`` - - .. deprecated:: 0.4.0 - This function has been deprecated. - - """ - raise DeprecationError('`my_function` has been deprecated') - - -Semantic Versioning and API Changes ------------------------------------ -According to `Semantic Versioning `_, you should -increment the MAJOR version when you make incompatible changes. -However, adding or eliminating methods should not be considered -incompatible changes to a code base but rather incremental changes -that are backwards-compatible (to a degree). Therefore, whenever a -method or feature is added, changed, or removed, the minor version -should be bumped. - -To avoid constantly bumping the minor version, one approach to -source-control branching is to create release branches where only -patch fixes are pushed and API changes occur between minor -releases. See `Trunk Based Development -`_. - -In summary, the mainline branch (commonly named ``main`` or ``master``) -must always be ready to release, and developers should create -release branches to maintain at least one prior minor version. - -The reason behind this is if a user wants to use API 0.4.0 instead of -0.5.0 due to some pressing deadline where they want to avoid a code -refactor, the maintainers of the API can back-port a bug-fix via ``git -cherry-pick ``. This gives users some time to update any -projects dependent on the API while still treating them as -"first-class" users. - -Note that due to the complexity of maintaining multiple "release branches" -in a repository, the number of active release branches should be between -one and three. - -Docstring Examples Best Practice --------------------------------- -Defining docstring examples for methods and classes is extremely -useful. The examples give users an easy place to start when trying -out the API, showing them exactly how to operate on a method or -class. By using ``doctest`` through ``pytest``, docstring examples can -also be used to perform regression testing to verify that the code is -executing as expected. - -This is an important feature of maintainable documentation as examples -must always match the API they are documenting. When using ``doctest`` -through ``pytest``, any changes within the API without corresponding -changes in the documentation will trigger doctest failures. - -Setting Up ``doctest`` -~~~~~~~~~~~~~~~~~~~~~~ -First, install ``pytest``. - -.. code:: - - pip install pytest - -Now, run ``doctest`` on any Python file. - -.. code:: - - pytest --doctest-modules file.py - -``doctest`` searches for examples in the docstrings and executes them -to verify that they function as written. - -Using ``pytest`` Fixtures -~~~~~~~~~~~~~~~~~~~~~~~~~ -To define a setup sequence before the ``doctest`` run or before a given -module is tested, you use ``pytest`` fixtures. Because fixtures allow -docstring examples to access shared objects, there is no need to repeat -the setup in each example. - -``pytest`` fixtures can be defined in a ``conftest.py`` file next to the source -code. The following example shows a fixture that is run automatically for -each ``doctest`` session. - -.. code:: python - - import pytest - - from pyaedt import Desktop - - - @pytest.fixture(autouse=True, scope="session") - def start_aedt(): - desktop = Desktop("2021.1", NG=True) - desktop.disable_autosave() - - # Wait to run doctest on docstrings - yield desktop - desktop.force_close_desktop() - -Fixtures can also be defined in a separate Python file from -``conftest.py``. This may help keep the fixtures more organized. Fixtures -from other files need to be imported in the main ``conftest.py`` file. - -This example shows how to import fixtures defined in an -``icepak_fixtures.py`` file under the ``doctest_fixtures`` folder. - -.. code:: python - - import pytest - - from pyaedt import Desktop - from pyaedt.doctest_fixtures import * - - # Import fixtures from other files - pytest_plugins = [ - "pyaedt.doctest_fixtures.icepak_fixtures", - ] - - - @pytest.fixture(autouse=True, scope="session") - def start_aedt(): - desktop = Desktop("2021.1", NG=True) - desktop.disable_autosave() - - # Wait to run doctest on docstrings - yield desktop - desktop.force_close_desktop() - -The ``doctest_namespace`` fixture built into ``doctest`` allows injecting -items from a fixture into the context of the ``doctest`` run. To use this -feature, the fixture needs to accept the ``doctest_namespace`` dictionary -as an argument. Then, objects can be added to the ``doctest_namespace`` -dictionary and used directly in a docstring example. - -This examples shows how the ``Icepak`` object can be stored in the -``doctest_namespace`` dictionary by adding the key ``icepak`` with the -``Icepak`` object as the value. - -.. code:: python - - import pytest - from pyaedt import Icepak - - - @pytest.fixture(autouse=True, scope="module") - def create_icepak(doctest_namespace): - doctest_namespace["icepak"] = Icepak(projectname="Project1", designname="IcepakDesign1") - -The ``Icepak`` object can then be used directly inside a docstring -example by referencing the key ``icepak``. - -.. code:: python - - def assign_openings(self, air_faces): - """Assign openings to a list of faces. - - Parameters - ---------- - air_faces : list - List of face names. - - Returns - ------- - :class:`pyaedt.modules.Boundary.BoundaryObject` - Boundary object when successful or ``None`` when failed. - - Examples - -------- - - Create an opening boundary for the faces of the "USB_GND" object. - - >>> faces = icepak.modeler.primitives["USB_GND"].faces - >>> face_names = [face.id for face in faces] - >>> boundary = icepak.assign_openings(face_names) - pyaedt Info: Face List boundary_faces created - pyaedt Info: Opening Assigned - - """ - -Useful ``doctest`` Features -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Ellipses for Random Output -************************** -If the output of some operation in an example cannot be verified exactly, -an ellipsis (``...``) can be used in the expected output. This allows it -to match any substring in the actual output. - -.. code :: - - Examples - -------- - - >>> desktop = Desktop("2021.1") - pyaedt Info: pyaedt v... - pyaedt Info: Python version ... - -To support this, ``doctest`` must be run with the option set to allow ellipses. - -.. code :: - - pytest --doctest-modules -o ELLIPSIS file.py - -``doctest`` Skip -**************** -The directive ``# doctest: +SKIP`` can be added to any line of a -docstring example so that it is not executed in ``doctest-modules``. -This is useful for examples that cannot run within ``pytest`` or have -side effects that will affect the other tests if they are run during -the ``doctest`` session. - -.. code :: python - - Examples - -------- - - >>> desktop = Desktop("2021.1") # doctest: +SKIP diff --git a/doc/source/coding-style/flake8.rst b/doc/source/coding-style/flake8.rst deleted file mode 100644 index 1780f642..00000000 --- a/doc/source/coding-style/flake8.rst +++ /dev/null @@ -1,252 +0,0 @@ -.. _style-guide-enforcement: - -Style Guide Enforcement -======================= -This topic describes the use of `Flake8`_ for `PEP8`_ style -enforcement and the minimum standards expected. PyAnsys libraries -are expected to be consistent with these guidelines. - -.. _PEP8: https://www.python.org/dev/peps/pep-0008/ - -Flake8 -~~~~~~ -`Flake8`_ is a Python tool for enforcing code styling. It is a wrapper -around the following three tools: `PyFlakes`_, `pycodestyle`_, and -`Ned Batchelder's McCabe script for complexity`_. Flake8 runs all three tools at once, -checking the code against a variety of style rules, such as line length, -code complexity, and whitespace. - -.. _Flake8: https://flake8.pycqa.org/en/latest/index.html -.. _PyFlakes: https://pypi.org/project/pyflakes/ -.. _pycodestyle: https://pypi.org/project/pycodestyle/ -.. _`Ned Batchelder's McCabe script for complexity`: https://github.com/PyCQA/mccabe -.. _configuring-flake8: - -Configuring Flake8 ------------------- -Flake8 supports configuring a specific set of style rules to -enforce. This configuration can be stored in your library in a -``setup.cfg``, ``tox.ini``, or ``.flake8`` file. PyAnsys libraries -store the Flake8 configuration in a ``.flake8`` file at the root of the -repository. - -Here is an example of a ``.flake8`` configuration file from a PyAnsys -library: - -.. code:: - - [flake8] - exclude = venv, __init__.py, doc/_build - select = W191, W291, W293, W391, E115, E117, E122, E124, E125, E225, E231, E301, E303, E501, F401, F403 - count = True - max-complexity = 10 - max-line-length = 100 - statistics = True - -Flake8 has many options that can be set within the configuration file. -For a list and descriptions, see this `Flake8 documentation topic -`__. - -The example configuration defines the following options: - -- ``exclude`` - Denotes subdirectories and ``doc/_build``, along with all - ``__init__.py`` files to be excluded from the check. - -- ``select`` - Sequence of error codes that Flake8 will report errors - for. The set in the above configuration is a basic set of errors to - check for and is not an exhaustive list. - - For a full list of error codes and their descriptions, see this `Flake8 - documentation topic `__. - -- ``count`` - Total number of errors to print at the end of the check. - -- ``max-complexity`` - Sets the maximum allowed McCabe complexity value for a block of code. - The value of 10 was chosen because it is a common default. - -- ``max-line-length`` - Denotes the maximum line length for any one line of code. - The `PEP8`_ standard advises a maximum line length of 79. Because - this is a bit limiting in some cases, the maximum line length - recommended for a PyAnsys library is 100. - -- ``statistics`` - Number of occurrences of each error or warning code - to be printed as a report at the end of the check. - - -Running Flake8 --------------- -First, to install Flake8, run: - -.. code:: - - python -m pip install flake8 - -Then, you can run Flake8 from inside your project directory by executing: - -.. code:: - - flake8 . - -This uses the configuration defined in the ``.flake8`` file to -run the style checks on the appropriate files within the project and -report any errors. - -In PyAnsys libraries, Flake8 is run as part of the CI/CD for code style. -This action is run as a required check on pull requests, preventing -code in violation of style rules from being merged into the code -base. - - -Utilizing Black -~~~~~~~~~~~~~~~ -Manually checking for code styling can be a tedious task. Luckily, -several Python tools for auto-formatting code to meet PEP8 standards -are available to help with this. The PyAnsys project suggests the use of the -the formatting tool `black`_. - -On completing a code change, and before committing, `black`_ can be -run to reformat the code, following the PEP8 guidelines enforced through -Flake8. This will limit any manual code changes needed to address style -rules. - -.. _black: https://black.readthedocs.io/en/stable/ - -Optionally, it is possible to automate the use of `black`_. This can be -done with the tool `pre-commit`_. Setting up a `pre-commit hook -to run black `_ -will automatically format the code before committing. This simple way of -incorporating code style checks into the development workflow to maintain -PEP8 guidelines requires minimal manual effort. - -.. _pre-commit: https://pre-commit.com/ - - -Minimum Standards -~~~~~~~~~~~~~~~~~ -The following section describes the minimum set of code style standards -expected in a PyAnsys library. - -* `W191`_ - **Indentation contains tabs.** - - Indentations should be composed of four spaces, not tabs. - -* `W291`_ - **Trailing whitespace.** - - There should be no trailing whitespace after the final character - on a line. - -* `W293`_ - **Blank line contains whitespace.** - - Blank lines should not have any tabs or spaces. - -* `W391`_ - **Blank line at the end of every file.** - - There should be only one blank line at the end of each file. This - warning will occur when there are zero, two, or more than two blank - lines. - -* `E115`_ - **Comment block expected an indent.** - - An indented block comment was expected but a non-indented block - comment was found instead. - -* `E117`_ - **Line over-indented.** - - Lines should be consistently indented in increments of two or four. - -* `E122`_ - **Continuation line missing indentation or outdented.** - - Continuation line is not indented as far as it should be or is - indented too far. - -* `E124`_ - **Closing bracket does not match indentation.** - - Closing bracket does not match the indentation of the opening bracket. - -* `E125`_ - **Continuation line with same indent as next logical line.** - - Continuation line is indented at the same level as the next logical - line. It should be indented to one more level to distinguish it from - the next line. - -* `E225`_ - **Missing whitespace around operator.** - - There should be one space before and after all operators. - -* `E231`_ - **Missing whitespace after certain special characters.** - - There should be one space after the characters ``,``, ``;``, and ``:``. - -* `E301`_ - **Expected a blank line, found none.** - - All methods of a class should have a single line between them. - -* `E303`_ - **Too many blank lines.** - - There should be one line between methods and two lines between - methods and classes. - -* `E501`_ - **Line too long.** - - All code lines should not exceed 100 characters. The - `PEP8 line length guideline `_ - suggests a maximum line length of 79. Following this limit - is not as necessary today due to modern screen sizes. The suggested maximum - length of 100 can be easier to accommodate and can still support - viewing files side by side in code editors. - -* `F401`_ - **Module imported but unused.** - - Modules should only be imported if they are actually used. - -* `F403`_ - **'from module import *' used.** - - Importing using wildcards (``*``) should never be done. Importing - modules this way leads to uncertainty and pollutes the code. You - cannot know exactly what is being imported and name clashes are common. - Import only the modules to be used. - -* **Limit complexity of code to 10.** - - This is enforced by the ``max-complexity`` option described in - :ref:`configuring-flake8`. Limiting code complexity leads to code that - is easier to understand and less risky to modify. Write low- - complexity code when possible. - - -Your ``.flake8`` file should be: - -.. code:: - - [flake8] - exclude = venv, __init__.py, doc/_build - select = W191, W291, W293, W391, E115, E117, E122, E124, E125, E225, E231, E301, E303, E501, F401, F403 - count = True - max-complexity = 10 - max-line-length = 100 - statistics = True - - -.. _W191: https://www.flake8rules.com/rules/W191.html -.. _W291: https://www.flake8rules.com/rules/W291.html -.. _W293: https://www.flake8rules.com/rules/W293.html -.. _W391: https://www.flake8rules.com/rules/W391.html -.. _E115: https://www.flake8rules.com/rules/E115.html -.. _E117: https://www.flake8rules.com/rules/E117.html -.. _E122: https://www.flake8rules.com/rules/E122.html -.. _E124: https://www.flake8rules.com/rules/E124.html -.. _E125: https://www.flake8rules.com/rules/E125.html -.. _E225: https://www.flake8rules.com/rules/E225.html -.. _E231: https://www.flake8rules.com/rules/E231.html -.. _E301: https://www.flake8rules.com/rules/E301.html -.. _E303: https://www.flake8rules.com/rules/E303.html -.. _E501: https://www.flake8rules.com/rules/E501.html -.. _F401: https://www.flake8rules.com/rules/F401.html -.. _F403: https://www.flake8rules.com/rules/F403.html - From 07e2491ee8bec21ffb97084e0d81019a03c82f58 Mon Sep 17 00:00:00 2001 From: Jorge Martinez Date: Wed, 18 May 2022 10:59:36 +0200 Subject: [PATCH 03/18] Rename pep8_best_practices.rst -> pep8.rst --- .../{pep8_best_practices.rst => pep8.rst} | 624 ++++++++++-------- 1 file changed, 346 insertions(+), 278 deletions(-) rename doc/source/coding-style/{pep8_best_practices.rst => pep8.rst} (61%) diff --git a/doc/source/coding-style/pep8_best_practices.rst b/doc/source/coding-style/pep8.rst similarity index 61% rename from doc/source/coding-style/pep8_best_practices.rst rename to doc/source/coding-style/pep8.rst index 2d8b2524..40cd129c 100644 --- a/doc/source/coding-style/pep8_best_practices.rst +++ b/doc/source/coding-style/pep8.rst @@ -1,20 +1,25 @@ -.. _best_practices: +PEP 8 +===== -PEP 8 Best Practices -==================== -This topic summarizes key points from `PEP8`_ and how -they apply to PyAnsys libraries. The goal is for PyAnsys libraries to -be consistent in style and formatting with the `big three` -data science libraries: `NumPy`_, `SciPy`_, and `pandas`_. +This topic summarizes the key points from `PEP 8`_ and how they apply to PyAnsys +libraries. `PEP 8`_ style guideline was devised by the Python community in order +to increase the readability of Python code. `PEP 8`_ has been adopted by some of +the most popular libraries within the Python ecosystem such us: `NumPy`_, +`SciPy`_, and `pandas`_. +.. _PEP 8: https://www.python.org/dev/peps/pep-0008/ .. _NumPy: https://numpy.org/ .. _SciPy: https://www.scipy.org/ .. _pandas: https://pandas.pydata.org/ -.. _PEP8: https://www.python.org/dev/peps/pep-0008/ Imports -~~~~~~~ +------- +The following lines describe the code style guidelines that apply for the +``import`` statement. + +Imports Location +~~~~~~~~~~~~~~~~ Imports should always be placed at the top of the file, just after any module comments and docstrings and before module globals and constants. This reduces the likelihood of an `ImportError`_ that @@ -22,208 +27,122 @@ might only be discovered during runtime. .. _ImportError: https://docs.python.org/3/library/exceptions.html#ImportError -Instead of: +.. tabs:: -.. code:: python + .. tab:: Avoid - def compute_logbase8(x): - import math - return math.log(8, x) + .. code-block:: python -Use: + def compute_logbase8(x): + import math + return math.log(8, x) -.. code:: python + .. tab:: Use + + .. code-block:: python - import math + import math - def compute_logbase8(x): - return math.log(8, x) + def compute_logbase8(x): + return math.log(8, x) + +Imports Order +~~~~~~~~~~~~~ For better readability, group imports in this order: #. Standard library imports #. Related third-party imports #. Local application- or library-specific imports -Instead of: - -.. code:: python - - import sys - import subprocess - from mypackage import mymodule - import math +All imports should be performed in alphabetically order. - def compute_logbase8(x): - return math.log(8, x) +.. tabs:: + .. tab:: Avoid -Use: + .. code-block:: python -.. code:: python + import sys + import subprocess + from mypackage import mymodule + import math - import sys - import subprocess - import math - from mypackage import mymodule - def compute_logbase8(x): - return math.log(8, x) + def compute_logbase8(x): + return math.log(8, x) -You should place imports in separate lines unless they are -modules from the same package. + .. tab:: Use -Instead of: + .. code-block:: python -.. code:: python + import math + import subprocess + import sys - import sys, math - from my_package import my_module - from my_package import my_other_module + from mypackage import mymodule + - def compute_logbase8(x): - return math.log(8, x) + def compute_logbase8(x): + return math.log(8, x) -Use: -.. code:: python +Multiple Imports +~~~~~~~~~~~~~~~~ +You should place imports in separate lines unless they are modules from the same +package. - import sys - import math - from my_package import my_module, my_other_module +.. tabs:: - def compute_logbase8(x): - return math.log(8, x) + .. tab:: Avoid + .. code-block:: python + + import math, sys -You should avoid using wild cards in imports because doing so -can make it difficult to detect undefined names. For more information, -see `Python Anti-Patterns: using wildcard imports <(https://docs.quantifiedcode.com/python-anti-patterns/maintainability/from_module_import_all_used.html>`_. + from my_package import my_module + from my_package import my_other_module + -Instead of: + def compute_logbase8(x): + return math.log(8, x) + + .. tab:: Use + + .. code-block:: python + + import math + import sys -.. code:: python + from my_package import my_module, my_other_module + - from my_package.mymodule import * + def compute_logbase8(x): + return math.log(8, x) -Use: -.. code:: python +Imports Namespace +~~~~~~~~~~~~~~~~~ +You should avoid using wild cards in imports because doing so can make it +difficult to detect undefined names. For more information, see `Python +Anti-Patterns: using wildcard imports +<(https://docs.quantifiedcode.com/python-anti-patterns/maintainability/from_module_import_all_used.html>`_. - from my_package.my_module import myclass +.. tabs:: - -Indentation and Line Breaks ---------------------------- -Proper and consistent indentation is important to producing -easy-to-read and maintainable code. In Python, use four spaces per -indentation level and avoid tabs. - -Indentation should be used to emphasize: - - - Body of a control statement, such as a loop or a select statement - - Body of a conditional statement - - New scope block - -.. code:: python - - class MyFirstClass: - """MyFirstClass docstring""" - - class MySecondClass: - """MySecondClass docstring""" - - def top_level_function(): - """Top level function docstring""" - return - -For improved readability, add blank lines or wrapping lines. Two -blank lines should be added before and after all function and class -definitions. - -Inside a class, use a single line before any method definition. - -.. code:: python - - class MyClass: - """MyClass docstring""" - - def first_method(self): - """First method docstring""" - return - - def second_method(self): - """Second method docstring""" - return - -To make it clear when a 'paragraph' of code is complete and a new section -is starting, use a blank line to separate logical sections. - -Instead of: - -.. code:: - - if x < y: - - STATEMENTS_A - - else: - - if x > y: - - STATEMENTS_B - - else: - - STATEMENTS_C - - if x > 0 and x < 10: - - print("x is a positive single digit.") - -Use: - -.. code:: - - if x < y: - STATEMENTS_A - else: - if x > y: - STATEMENTS_B - else: - STATEMENTS_C - - if x > 0 and x < 10: - print("x is a positive single digit.") - elif x < 0: - print("x is less than zero.") - - -Maximum Line Length -------------------- -For source code lines, best practice is to keep the length at or below -100 characters. For docstrings and comments, best practice is to keep -the length at or below 72 characters. - -Lines longer than these recommended limits might not display properly -on some terminals and tools or might be difficult to follow. For example, -this line is difficult to follow: - -.. code:: python - - employee_hours = [schedule.earliest_hour for employee in self.public_employees for schedule in employee.schedules] - -The line can be rewritten as: - -.. code:: python - - employee_hours = [schedule.earliest_hour for employee in - self.public_employees for schedule in employee.schedules] - -Alternatively, instead of writing a list comprehension, you can use a -classic loop. + .. tab:: Avoid + + .. code-block:: python + + from my_package.my_module import * + + .. tab:: Use + + .. code-block:: python + + from my_package.my_module import myclass Naming Conventions @@ -240,15 +159,16 @@ global rules to determine the correct names: #. Avoid encodings. Do not append prefixes or type information. -Names to Avoid -~~~~~~~~~~~~~~ -Do not use the characters ``'l'``, ``'O'`` , or ``'I'`` as -single-character variable names. In some fonts, these characters are -indistinguishable from the numerals one and zero. +Variables +~~~~~~~~~ + +Do not use the characters ``'l'``, ``'O'`` , or ``'I'`` as single-character +variable names. In some fonts, these characters are indistinguishable from the +numerals one and zero. -Package and Module Naming Conventions -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Packages and Modules +~~~~~~~~~~~~~~~~~~~~ Use a short, lowercase word or words for module names. Separate words with underscores to improve readability. For example, use ``module.py`` or ``my_module.py``. @@ -259,25 +179,30 @@ from PyPi. .. code:: - pip install package + python -m pip install package -Class Naming Conventions -~~~~~~~~~~~~~~~~~~~~~~~~ -Use `camel case `_ when naming classes. Do not separate words -with underscores. +Classes +~~~~~~~ +Use `camel case `_ when naming +classes. Do not separate words with underscores. .. code:: python class MyClass(): """Docstring for MyClass""" - pass + ... + + +Use a lowercase word or words for Python functions or methods. Separate words +with underscores to improve readability. When naming class methods, the +following conventions apply: +- Only `dunder methods`_ must be enclosed by double underscores. +- Methods starting with double underscores are considered to be private methods. +- Methods starting with a single underscore are considered to be protected methods. -Function and Method Naming Conventions -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Use a lowercase word or words for Python functions or methods. Separate -words with underscores to improve readability. +.. _dunder methods: https://docs.python.org/3/reference/datamodel.html#special-method-names .. code:: python @@ -313,20 +238,25 @@ words with underscores to improve readability. self._value += 2 -Variable Naming Conventions -~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Use a lowercase single letter, word, or words when naming -variables. Separate words with underscores to improve readability. +.. note:: + + Remember that functions and methods naming is just a convention. In Python + there are not private members, meaning that you can always access these even + if they start with underscores. + + +Variables +~~~~~~~~~ +Use a lowercase single letter, word, or words when naming variables. Separate +words with underscores to improve readability. .. code:: python my_variable = 5 - -Constants are variables that are set at the module level and are used -by one or more methods within that module. Use an uppercase word or -words for constants. Separate words with underscores to improve -readability. +Constants are variables that are set at the module level and are used by one or +more methods within that module. Use an uppercase word or words for constants. +Separate words with underscores to improve readability. .. code:: python @@ -335,9 +265,128 @@ readability. MY_CONSTANT = 8 MY_OTHER_CONSTANT = 1000 +Indentation and Line Breaks +--------------------------- +Proper and consistent indentation is important to producing +easy-to-read and maintainable code. In Python, use four spaces per +indentation level and avoid tabs. + +Indentation should be used to emphasize: + + - Body of a control statement, such as a loop or a select statement + - Body of a conditional statement + - New scope block + +.. code:: python + + class MyFirstClass: + """MyFirstClass docstring""" + + class MySecondClass: + """MySecondClass docstring""" + + def top_level_function(): + """Top level function docstring""" + return + +For improved readability, add blank lines or wrapping lines. Two +blank lines should be added before and after all function and class +definitions. + +Inside a class, use a single line before any method definition. + +.. code-block:: python + + class MyClass: + """MyClass docstring""" + + def first_method(self): + """First method docstring""" + return + + def second_method(self): + """Second method docstring""" + return + +To make it clear when a 'paragraph' of code is complete and a new section +is starting, use a blank line to separate logical sections. + +Instead of: + +.. tabs:: + + .. tab:: Avoid + + .. code-block:: + + if x < y: + + STATEMENTS_A + + else: + + if x > y: + + STATEMENTS_B + + else: + + STATEMENTS_C + + if x > 0 and x < 10: + + print("x is a positive single digit.") + + .. tab:: Use + + .. code:: + + if x < y: + STATEMENTS_A + else: + if x > y: + STATEMENTS_B + else: + STATEMENTS_C + + if x > 0 and x < 10: + print("x is a positive single digit.") + elif x < 0: + print("x is less than zero.") + + +Maximum Line Length +------------------- +For source code lines, best practice is to keep the length at or below +100 characters. For docstrings and comments, best practice is to keep +the length at or below 72 characters. + +Lines longer than these recommended limits might not display properly +on some terminals and tools or might be difficult to follow. For example, +this line is difficult to follow: + +.. code:: python + + employee_hours = [schedule.earliest_hour for employee in self.public_employees for schedule in employee.schedules] + +The line can be rewritten as: -Comments -~~~~~~~~ +.. code:: python + + employee_hours = [ + schedule.earliest_hour + for employee in self.public_employees + for schedule in employee.schedules + ] + +Alternatively, instead of writing a list comprehension, you can use a +classic loop. + +Notice that sometimes it will not be possible to keep the line length below the +desired value without breaking the syntax rules. + +Comments Conventions +-------------------- Because a PyAnsys library generally involves multiple physics domains, users reading its source code do not have the same background as the developers who wrote it. This is why it is important for a library @@ -434,21 +483,16 @@ same line: .. code:: python - """This is a docstring.""". + """This is a docstring.""" For a multi-line docstring, put the ending ``"""`` on a line by itself. -PyAEDT follows the `numpydoc -`_ -docstring style, which is used by `numpy `_, -`scipy `_, `pandas -`_, and a variety of other Python open -source projects. For more information on docstrings for PyAnsys -libraries, see :ref:`Documentation Style`. +For more information on docstrings for PyAnsys libraries, see +:ref:`Documentation Style`. Programming Recommendations -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +--------------------------- The following sections provide some `PEP8 `_ suggestions for removing ambiguity and preserving consistency. They address some common pitfalls @@ -456,7 +500,7 @@ when writing Python code. Booleans and Comparisons ------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~ Don't compare Boolean values to ``True`` or ``False`` using the equivalence operator. @@ -515,7 +559,7 @@ especially important when parsing arguments. Handling Strings ----------------- +~~~~~~~~~~~~~~~~ Use ``.startswith()`` and ``.endswith()`` instead of slicing. Instead of: @@ -535,12 +579,12 @@ Use: if word.startswith('cat'): print('The word starts with "cat"') - if file_name.endswith('jpg'): + if file_name.endswith('.jpg'): print('The file is a JPEG') Reading the Windows Registry ----------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Never read the Windows registry or write to it because this is dangerous and makes it difficult to deploy libraries on different environments or operating systems. @@ -559,7 +603,7 @@ Bad practice - Example 2 Duplicated Code ---------------- +~~~~~~~~~~~~~~~ Follow the DRY principle, which states that "Every piece of knowledge must have a single, unambiguous, authoritative representation within a system." Attempt to follow this principle unless it overly complicates @@ -567,39 +611,43 @@ the code. For instance, the following example converts Fahrenheit to kelvin twice, which now requires the developer to maintain two separate lines that do the same thing. -.. code:: python - temp = 55 - new_temp = ((temp - 32) * (5 / 9)) + 273.15 +.. tabs:: - temp2 = 46 - new_temp_k = ((temp2 - 32) * (5 / 9)) + 273.15 + .. tab:: Avoid + + .. code-block:: python + + temp = 55 + new_temp = ((temp - 32) * (5 / 9)) + 273.15 -Instead, write a simple method that converts Fahrenheit to kelvin: + temp2 = 46 + new_temp_k = ((temp2 - 32) * (5 / 9)) + 273.15 -.. code:: python + + .. tab:: Use + + .. code-block:: python + + def fahr_to_kelvin(fahr) + """Convert temperature in Fahrenheit to Kelvin. - def fahr_to_kelvin(fahr) - """Convert temperature in Fahrenheit to kelvin. + Parameters + ---------- + fahr : int or float + Temperature in Fahrenheit. - Parameters: - ----------- - fahr: int or float - Temperature in Fahrenheit. + Returns + ------- + kelvin : float + Temperature in Kelvin. - Returns: - ----------- - kelvin : float - Temperature in kelvin. - """ - return ((fahr - 32) * (5 / 9)) + 273.15 + """ + return ((fahr - 32) * (5 / 9)) + 273.15 -Now, you can execute and get the same output with: + new_temp = fahr_to_kelvin(55) + new_temp_k = fahr_to_kelvin(46) -.. code:: python - - new_temp = fahr_to_kelvin(55) - new_temp_k = fahr_to_kelvin(46) This is a trivial example, but the approach can be applied for a variety of both simple and complex algorithms and workflows. Another @@ -610,8 +658,9 @@ for this method. import numpy as np + def test_fahr_to_kelvin(): - assert np.isclose(12.7778, fahr_to_kelvin(55)) + np.testing.assert_allclose(12.7778, fahr_to_kelvin(55)) Now, not only do you have one line of code to verify, but you can also use a testing framework such as ``pytest`` to test that the method is @@ -619,7 +668,7 @@ correct. Nested Blocks -------------- +~~~~~~~~~~~~~ Avoid deeply nested block structures (such as conditional blocks and loops) within one single code block. @@ -652,67 +701,86 @@ reusable and unit-testable. Loops ------ +~~~~~ While there is nothing inherently wrong with nested loops, to avoid certain pitfalls, steer clear of having loops with more than two levels. In some cases, you can rely on coding mechanisms like list comprehensions to circumvent nested loops. -Instead of: +.. tabs:: -.. code:: + .. tab:: Avoid - >>> squares = [] - >>> for i in range(10): - ... squares.append(i * i) - >>> squares - [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] + .. code-block:: python + + squares = [] + for i in range(10): + squares.append(i * i) + .. code-block:: pycon -Implement a list comprehension with: + >>> print(f"{squares = }") + squares = [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] -.. code:: - >>> squares = [i*i for i in range(10)] - >>> squares - [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] + .. tab:: Use + + .. code-block:: python + + squares = [i*i for i in range(10)] + + + .. code-block:: pycon + + >>> print(f"{squares = }") + squares = [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] If the loop is too complicated for creating a list comprehension, consider creating small functions and calling these instead. For example, extract all consonants in a sentence: -.. code:: python - - >>> sentence = 'This is a sample sentence.' - >>> vowels = 'aeiou' - >>> consonants = [] - >>> for letter in sentence: - ... if letter.isalpha() and letter.lower() not in vowels: - ... consonants.append(letter) - >>> consonants - ['T', 'h', 's', 's', 's', 'm', 'p', 'l', 's', 'n', 't', 'n', 'c'] - - -This is better implemented by creating a simple method to return if a -letter is a consonant: - - >>> def is_consonant(letter): - ... """Return ``True`` when a letter is a consonant.""" - ... vowels = 'aeiou' - ... return letter.isalpha() and letter.lower() not in vowels - ... - >>> sentence = 'This is a sample sentence.' - >>> consonants = [letter for letter in sentence if is_consonant(letter)] - >>> consonants - ['T', 'h', 's', 's', 's', 'm', 'p', 'l', 's', 'n', 't', 'n', 'c'] +.. tabs:: + + .. tab:: Avoid + + .. code-block:: python + + sentence = 'This is a sample sentence.' + vowels = 'aeiou' + consonants = [] + for letter in sentence: + if letter.isalpha() and letter.lower() not in vowels: + consonants.append(letter) + + .. code-block:: pycon + + >>> print(f"{consonants = }") + consonants = ['T', 'h', 's', 's', 's', 'm', 'p', 'l', 's', 'n', 't', 'n', 'c'] + + + .. tab:: Use + + .. code-block:: python + + def is_consonant(letter): + """Return ``True`` when a letter is a consonant.""" + vowels = 'aeiou' + return letter.isalpha() and letter.lower() not in vowels + + .. code-block:: pycon + + >>> sentence = 'This is a sample sentence.' + >>> consonants = [letter for letter in sentence if is_consonant(letter)] + >>> print(f"{consonants = }") + consonants = ['T', 'h', 's', 's', 's', 'm', 'p', 'l', 's', 'n', 't', 'n', 'c'] The second approach is more readable and better documented. Additionally, you could implement a unit test for ``is_consonant``. Security Considerations -~~~~~~~~~~~~~~~~~~~~~~~ +----------------------- Security, an ongoing process involving people and practices, ensures application confidentiality, integrity, and availability [#]_. Any library should be secure and implement good practices that avoid or mitigate possible security risks. From 87f75da51663f26a39920d22c8a8eb66bb627a5e Mon Sep 17 00:00:00 2001 From: Jorge Martinez Date: Wed, 18 May 2022 11:00:55 +0200 Subject: [PATCH 04/18] New formatting-tools.rst section --- doc/source/coding-style/formatting-tools.rst | 241 +++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 doc/source/coding-style/formatting-tools.rst diff --git a/doc/source/coding-style/formatting-tools.rst b/doc/source/coding-style/formatting-tools.rst new file mode 100644 index 00000000..28ee28cb --- /dev/null +++ b/doc/source/coding-style/formatting-tools.rst @@ -0,0 +1,241 @@ +Code Style Tools +================ + +There are plenty of tools for checking code style. This section presents some of +the most popular ones in the Python ecosystem. A minimum configuration is +provided for each one so you can easily include them in your PyAnsys project. + +Most of the tools presented can be configured using :ref:`the +\`\`pyproject.toml\`\` file`, avoiding dotfiles and thus leading to a much +cleaner root project directory. + + +Black +----- +`Black`_ is the most popular code formatter in the Python community, as it is +being maintained by the Python Software Foundation. It allows for a minimum +configuration to ensure that Python code format looks almost the same across +projects. + +Unlike `PEP 8`_, the default line length imposed by `black`_ is 88 and not 79 +characters. + +The minimum black configuration for a PyAnsys project should look like: + +.. code-block:: toml + + [tool.black] + line-length: "" + + +Isort +----- +The goal of `isort`_ is to properly format ``import`` statements by making sure +they follow the standard library, third party libraries and custom library +order. + +When using `isort`_ with `black`_, it is important to properly configure both +tools so no conflicts appear. To do so, make sure you take advantage of the +``--porfile black`` flag in `isort`_. + +.. code-block:: toml + + [tool.isort] + profile = "black" + force_sort_within_sections = true + line_length = "" + default_section = "THIRDPARTY" + src_paths = ["doc", "src", "tests"] + + +Flake8 +------ +The goal of `flake8` is to act as a `PEP 8`_ compliance checker. Again, it is +important to make sure that if this tool is being used with `black`_, no +conflicts arise. + +The following configuration is the minimum one to setup `flake8`_ together with +`black`_ one. + +The configuration for `flake8`_ must be specified in a ``.flake8`` file. + +.. code-block:: toml + + [flake8] + max-line-length = 88 + extend-ignore = E203 + + +Pre-commit +---------- +To make sure that every commit you made is compliant with the code style +guidelines of PyAnsys, you can take advantage of `pre-commit`_ in your project. +Every time you stage some changes and once you commit those, `pre-commit`_ will +only allow you to do so if all the defined hooks succeedd. + +The configuration for `pre-commit`_ must be defined in a +`.pre-commit-config.yaml` file. The following lines present a minimum +`pre-commit`_ configuration which includes both code and documentation +formatting tools. + + +.. code-block:: yaml + + repos: + + - repo: https://github.com/psf/black + rev: X.Y.Z + hooks: + - id: black + + - repo: https://github.com/pycqa/isort + rev: X.Y.Z + hooks: + - id: isort + + - repo: https://github.com/PyCQA/flake8 + rev: X.Y.Z + hooks: + - id: flake8 + + - repo: https://github.com/codespell-project/codespell + rev: vX.Y.Z + hooks: + - id: codespell + + - repo: https://github.com/pycqa/pydocstyle + rev: X.Y.Z + hooks: + - id: pydocstyle + additional_dependencies: [toml] + exclude: "tests/" + +Installing ``pre-commit`` +~~~~~~~~~~~~~~~~~~~~~~~~~ +You can install ``pre-commit`` by running: + +.. code-block:: bash + + python -m pip install pre-commit + +Then, make sure you install it as a ``Git hook`` by running: + +.. code-block:: bash + + pre-commit install + +Using ``pre-commit`` +~~~~~~~~~~~~~~~~~~~~ +From then on, pre-commit will automatically trigger every time you try to commit +a change. If any of the hooks defined in `.pre-commit-config.yaml` fails, you +will need to fix the failing files, stage the new changes and try to commit +those again. + +If you want to manually run ``pre-commit``, you can execute: + +.. code-block:: bash + + pre-commit run --all-files --show-diff-on-failure + +Previous command will show the current and expected style of the code if any of +the hooks fail. + + +Using ``pre-commit`` +~~~~~~~~~~~~~~~~~~~~ + +Tox +--- +A tool you may consider to use in your project is `tox`_. This tool is an +automation tool similar to `Make`_ but with the advantage of allowing to test +your package in a temporary virtual environment. This guarantees reproducible +builds, as your package is no longer tested in "local" mode but in isolated +form. + +Configuration for `tox`_ is stored in a ``tox.ini`` file. The minimum +configuration for a PyAnsys ``py-`` project should be: + +.. code-block:: ini + + [tox] + description = Default tox environments list + envlist = + style,{py37,py38,py39,py310}{,-coverage},doc + skip_missing_interpreters = true + isolated_build = true + isolated_build_env = build + + [testenv] + description = Checks for project unit tests and coverage (if desired) + basepython = + py37: python3.7 + py38: python3.8 + py39: python3.9 + py310: python3.10 + py: python3 + {style,reformat,doc,build}: python3 + setenv = + PYTHONUNBUFFERED = yes + coverage: PYTEST_EXTRA_ARGS = --cov=ansys.product --cov-report=term --cov-report=xml --cov-report=html + deps = + -r{toxinidir}/requirements/requirements_tests.txt + commands = + pytest {env:PYTEST_MARKERS:} {env:PYTEST_EXTRA_ARGS:} {posargs:-vv} + + [testenv:style] + description = Checks project code style + skip_install = true + deps = + pre-commit + commands = + pre-commit install + pre-commit run --all-files --show-diff-on-failure + + [testenv:doc] + description = Check if documentation generates properly + deps = + -r{toxinidir}/requirements/requirements_doc.txt + commands = + sphinx-build -d "{toxworkdir}/doc_doctree" doc/source "{toxworkdir}/doc_out" --color -vW -bhtml + + +Previous configuration assumes that you have a ``requirements/`` directory that +contains a ``requirements_tests.txt`` and a ``requirements_doc.txt``. In +addition, the ``style`` environment will execute pre-commit, which guarantees +the usage of this tool in your project. + +Installing ``tox`` +~~~~~~~~~~~~~~~~~~ +You can install this tool as any other Python one by running: + +.. code-block:: bash + + python -m pip install tox + + +Using ``tox`` +~~~~~~~~~~~~~ + +The core concept behind `tox`_ are ``environments``. These are similar to +``Makefile`` rules and highly customizable. Previous configuration ships with +different environments among which you can find: + +- ``style``: for checking the code style of your project. +- ``py``: which will run your test suite. +- ``doc``: for building the documentation of your project. + +Execute any of the previous environments by running ``tox -e ``. You +can run multiple environments by specifying those with commas ``tox -e +,,...```. To run all available environments, simply +execute ``tox``. + + +.. LINKS AND REFERENCES + +.. _black: https://black.readthedocs.io/en/latest/ +.. _isort: https://pycqa.github.io/isort/ +.. _flake8: https://flake8.pycqa.org/en/latest/ +.. _pre-commit: https://pre-commit.com/ +.. _tox: https://tox.wiki/en/latest/ +.. _PEP 8: https://www.python.org/dev/peps/pep-0008/ +.. _make: https://www.gnu.org/software/make/ From cf6481ba45d3089e4d2ced517b48b58752937138 Mon Sep 17 00:00:00 2001 From: Jorge Martinez Date: Wed, 18 May 2022 11:01:07 +0200 Subject: [PATCH 05/18] Fix links and references --- doc/source/coding-style/index.rst | 40 ++++++++++++------------- doc/source/guidelines/dev_practices.rst | 2 +- doc/source/index.rst | 2 +- doc/source/overview/administration.rst | 2 +- doc/source/overview/contributing.rst | 2 +- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/doc/source/coding-style/index.rst b/doc/source/coding-style/index.rst index 5a59528f..90691ddd 100644 --- a/doc/source/coding-style/index.rst +++ b/doc/source/coding-style/index.rst @@ -1,29 +1,29 @@ -.. _coding_style: - Coding Style -************ - -PyAnsys libraries are expected to follow `PEP8`_ and -be consistent in style and formatting with the 'big three' -data science libraries: `NumPy`_, `SciPy`_, and `pandas`_. - -.. _NumPy: https://numpy.org/ -.. _SciPy: https://www.scipy.org/ -.. _pandas: https://pandas.pydata.org/ -.. _PEP8: https://www.python.org/dev/peps/pep-0008/ +############ +Coding Style refers to the different rules defined in a software project which +need to be followed when writing source code. These guidelines ensure that all +the source code is going to look the same across the different files of the +project. -.. todo:: +The PyAnsys ecosystem is composed by multiple projects. To unify the coding +style among all projects, this coding style guideline was devised. - * Describe flake8 standards (in subpage), include example ``.flake8`` - with minimum standards. - * Include anything we've written from other documentation either in - this page or other pages. +PyAnsys libraries are expected to follow `PEP 8`_ and be consistent in style and +formatting with the 'big three' data science libraries: `NumPy`_, `SciPy`_, and +`pandas`_. .. toctree:: :hidden: :maxdepth: 3 - pep8_best_practices - beyond_pep8 - flake8 + pep8 + formatting-tools + + +.. LINKS AND REFERENCES + +.. _NumPy: https://numpy.org/ +.. _SciPy: https://www.scipy.org/ +.. _pandas: https://pandas.pydata.org/ +.. _PEP 8: https://www.python.org/dev/peps/pep-0008/ diff --git a/doc/source/guidelines/dev_practices.rst b/doc/source/guidelines/dev_practices.rst index b39d22ac..77d74e79 100644 --- a/doc/source/guidelines/dev_practices.rst +++ b/doc/source/guidelines/dev_practices.rst @@ -11,7 +11,7 @@ coding paradigms: gained by following the basic guidelines listed in PEP 20. As suggested in these guidelines, focus on making your additions intuitive, novel, and helpful for PyAnsys users. When in doubt, use ``import this``. - For Ansys code quality standards, see :ref:`coding_style`. + For Ansys code quality standards, see :ref:`Coding Style`. #. Document your contributions. Include a docstring for any added function, method, or class, following `numpydocs docstring `_ diff --git a/doc/source/index.rst b/doc/source/index.rst index ab347b9f..6fb50cdc 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -10,6 +10,6 @@ overview/index guidelines/index packaging/index - coding_style/index + coding-style/index doc-style/index abstractions/index diff --git a/doc/source/overview/administration.rst b/doc/source/overview/administration.rst index feb7fae8..f1a7b110 100644 --- a/doc/source/overview/administration.rst +++ b/doc/source/overview/administration.rst @@ -43,7 +43,7 @@ description, or branch protection management. Each repository is expected to follow this minimum set of standards: -- PEP8 code standards. See :ref:`best_practices`. +- PEP8 code standards. See :ref:`PEP 8`. - CI/CD using GitHub actions or Azure DevOps to enforce coding standards. - Publicly hosted documentation describing the API and providing examples. See :ref:`Documentation Style`. diff --git a/doc/source/overview/contributing.rst b/doc/source/overview/contributing.rst index fa630f21..e1c5093a 100644 --- a/doc/source/overview/contributing.rst +++ b/doc/source/overview/contributing.rst @@ -82,7 +82,7 @@ When you are ready to start contributing code, see: - :ref:`development_practices` for information on how PyAnsys development is conducted -- :ref:`best_practices` for information on how to style and format your +- :ref:`PEP 8` for information on how to style and format your code to adhere to PyAnsys standards From 76e8ab4e393748fbc56a60879739b4fd4fa86497 Mon Sep 17 00:00:00 2001 From: Jorge Martinez Date: Wed, 18 May 2022 11:13:24 +0200 Subject: [PATCH 06/18] Apply code suggestions --- doc/source/coding-style/pep8.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/doc/source/coding-style/pep8.rst b/doc/source/coding-style/pep8.rst index 40cd129c..70f7c92f 100644 --- a/doc/source/coding-style/pep8.rst +++ b/doc/source/coding-style/pep8.rst @@ -207,7 +207,7 @@ following conventions apply: .. code:: python class MyClass(): - """Docstring for MyClass""" + """Docstring for MyClass.""" def __init__(self, value): """Constructor. @@ -280,13 +280,13 @@ Indentation should be used to emphasize: .. code:: python class MyFirstClass: - """MyFirstClass docstring""" + """MyFirstClass docstring.""" class MySecondClass: - """MySecondClass docstring""" + """MySecondClass docstring.""" def top_level_function(): - """Top level function docstring""" + """Top level function docstring.""" return For improved readability, add blank lines or wrapping lines. Two @@ -298,14 +298,14 @@ Inside a class, use a single line before any method definition. .. code-block:: python class MyClass: - """MyClass docstring""" + """MyClass docstring.""" def first_method(self): - """First method docstring""" + """First method docstring.""" return def second_method(self): - """Second method docstring""" + """Second method docstring.""" return To make it clear when a 'paragraph' of code is complete and a new section @@ -317,7 +317,7 @@ Instead of: .. tab:: Avoid - .. code-block:: + .. code-block:: python if x < y: @@ -339,7 +339,7 @@ Instead of: .. tab:: Use - .. code:: + .. code-block:: python if x < y: STATEMENTS_A @@ -607,7 +607,7 @@ Duplicated Code Follow the DRY principle, which states that "Every piece of knowledge must have a single, unambiguous, authoritative representation within a system." Attempt to follow this principle unless it overly complicates -the code. For instance, the following example converts Fahrenheit to kelvin +the code. For instance, the following example converts Fahrenheit to Kelvin twice, which now requires the developer to maintain two separate lines that do the same thing. From ea24d24fe0ba9500661316ca1bf94ebb74debc00 Mon Sep 17 00:00:00 2001 From: Jorge Martinez Date: Wed, 18 May 2022 12:06:15 +0200 Subject: [PATCH 07/18] Improve pep8.rst tabs --- doc/source/coding-style/pep8.rst | 37 ++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/doc/source/coding-style/pep8.rst b/doc/source/coding-style/pep8.rst index 70f7c92f..eea6f72d 100644 --- a/doc/source/coding-style/pep8.rst +++ b/doc/source/coding-style/pep8.rst @@ -321,18 +321,18 @@ Instead of: if x < y: - STATEMENTS_A + ... else: if x > y: - STATEMENTS_B + ... else: - STATEMENTS_C - + ... + if x > 0 and x < 10: print("x is a positive single digit.") @@ -342,12 +342,12 @@ Instead of: .. code-block:: python if x < y: - STATEMENTS_A + ... else: if x > y: - STATEMENTS_B + ... else: - STATEMENTS_C + ... if x > 0 and x < 10: print("x is a positive single digit.") @@ -365,19 +365,24 @@ Lines longer than these recommended limits might not display properly on some terminals and tools or might be difficult to follow. For example, this line is difficult to follow: -.. code:: python - employee_hours = [schedule.earliest_hour for employee in self.public_employees for schedule in employee.schedules] +.. tabs:: -The line can be rewritten as: + .. tab:: Avoid -.. code:: python + .. code:: python - employee_hours = [ - schedule.earliest_hour - for employee in self.public_employees - for schedule in employee.schedules - ] + employee_hours = [schedule.earliest_hour for employee in self.public_employees for schedule in employee.schedules] + + .. tab:: Use + + .. code-block:: python + + employee_hours = [ + schedule.earliest_hour + for employee in self.public_employees + for schedule in employee.schedules + ] Alternatively, instead of writing a list comprehension, you can use a classic loop. From c7b267c209f7cb17e34f9300af27e57badcf202d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Mart=C3=ADnez?= <28702884+jorgepiloto@users.noreply.github.com> Date: Mon, 23 May 2022 09:38:56 +0200 Subject: [PATCH 08/18] Apply suggestions from code review Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> --- doc/source/coding-style/formatting-tools.rst | 82 ++++++++++---------- doc/source/coding-style/index.rst | 11 +-- 2 files changed, 46 insertions(+), 47 deletions(-) diff --git a/doc/source/coding-style/formatting-tools.rst b/doc/source/coding-style/formatting-tools.rst index 28ee28cb..760952ec 100644 --- a/doc/source/coding-style/formatting-tools.rst +++ b/doc/source/coding-style/formatting-tools.rst @@ -1,26 +1,26 @@ Code Style Tools ================ -There are plenty of tools for checking code style. This section presents some of +There are many tools for checking code style. This section presents some of the most popular ones in the Python ecosystem. A minimum configuration is -provided for each one so you can easily include them in your PyAnsys project. +provided for each one so that you can easily include them in your PyAnsys project. Most of the tools presented can be configured using :ref:`the -\`\`pyproject.toml\`\` file`, avoiding dotfiles and thus leading to a much +\`\`pyproject.toml\`\` file`. Avoiding dotfiles leads to a much cleaner root project directory. Black ----- -`Black`_ is the most popular code formatter in the Python community, as it is -being maintained by the Python Software Foundation. It allows for a minimum -configuration to ensure that Python code format looks almost the same across +`Black`_ is the most popular code formatter in the Python community because it is +maintained by the Python Software Foundation. It allows for a minimum +configuration to ensure that the Python code format looks almost the same across projects. -Unlike `PEP 8`_, the default line length imposed by `black`_ is 88 and not 79 -characters. +While `PEP 8`_ imposes a default line length of 79 characters, `black`_ has +a default line length of 88 characters. -The minimum black configuration for a PyAnsys project should look like: +The minimum `black`_ configuration for a PyAnsys project should look like this: .. code-block:: toml @@ -31,11 +31,10 @@ The minimum black configuration for a PyAnsys project should look like: Isort ----- The goal of `isort`_ is to properly format ``import`` statements by making sure -they follow the standard library, third party libraries and custom library -order. +that they follow the standard order: library, third-party libraries, and custom library. When using `isort`_ with `black`_, it is important to properly configure both -tools so no conflicts appear. To do so, make sure you take advantage of the +tools so that no conflicts appear. To do so, make sure you take advantage of the ``--porfile black`` flag in `isort`_. .. code-block:: toml @@ -50,12 +49,12 @@ tools so no conflicts appear. To do so, make sure you take advantage of the Flake8 ------ -The goal of `flake8` is to act as a `PEP 8`_ compliance checker. Again, it is -important to make sure that if this tool is being used with `black`_, no +The goal of `flake8` is to act as a `PEP 8`_ compliance checker. Again, if +this tool is being used with `black`_, it is important to make sure that no conflicts arise. -The following configuration is the minimum one to setup `flake8`_ together with -`black`_ one. +The following configuration is the minimum one to set up `flake8`_ together with +`black`_. The configuration for `flake8`_ must be specified in a ``.flake8`` file. @@ -68,14 +67,14 @@ The configuration for `flake8`_ must be specified in a ``.flake8`` file. Pre-commit ---------- -To make sure that every commit you made is compliant with the code style -guidelines of PyAnsys, you can take advantage of `pre-commit`_ in your project. -Every time you stage some changes and once you commit those, `pre-commit`_ will -only allow you to do so if all the defined hooks succeedd. +To ensure that every commit you make is compliant with the code style +guidelines for PyAnsys, you can take advantage of `pre-commit`_ in your project. +Every time you stage some changes and try to commit them, `pre-commit`_ will +only allow you to do this only if all defined hooks succeed. The configuration for `pre-commit`_ must be defined in a `.pre-commit-config.yaml` file. The following lines present a minimum -`pre-commit`_ configuration which includes both code and documentation +`pre-commit`_ configuration that includes both code and documentation formatting tools. @@ -126,18 +125,18 @@ Then, make sure you install it as a ``Git hook`` by running: Using ``pre-commit`` ~~~~~~~~~~~~~~~~~~~~ -From then on, pre-commit will automatically trigger every time you try to commit -a change. If any of the hooks defined in `.pre-commit-config.yaml` fails, you -will need to fix the failing files, stage the new changes and try to commit -those again. +One installed as described, ``pre-commit`` will automatically trigger every time +that you try to commit a change. If any of the hooks defined in `.pre-commit-config.yaml` +fails, you must fix the failing files, stage the new changes, and try to commit +them again. -If you want to manually run ``pre-commit``, you can execute: +If you want to manually run ``pre-commit``, you can run: .. code-block:: bash pre-commit run --all-files --show-diff-on-failure -Previous command will show the current and expected style of the code if any of +This command will show the current and expected style of the code if any of the hooks fail. @@ -146,11 +145,10 @@ Using ``pre-commit`` Tox --- -A tool you may consider to use in your project is `tox`_. This tool is an -automation tool similar to `Make`_ but with the advantage of allowing to test -your package in a temporary virtual environment. This guarantees reproducible -builds, as your package is no longer tested in "local" mode but in isolated -form. +A tool you might consider using in your project is `tox`_. While this automation +tool is similar to `Make`_, it supports testing of your package in a temporary +virtual environment. Being able to test your package in isolation rather than in +"local" mode guarantees reproducible builds. Configuration for `tox`_ is stored in a ``tox.ini`` file. The minimum configuration for a PyAnsys ``py-`` project should be: @@ -199,14 +197,14 @@ configuration for a PyAnsys ``py-`` project should be: sphinx-build -d "{toxworkdir}/doc_doctree" doc/source "{toxworkdir}/doc_out" --color -vW -bhtml -Previous configuration assumes that you have a ``requirements/`` directory that -contains a ``requirements_tests.txt`` and a ``requirements_doc.txt``. In -addition, the ``style`` environment will execute pre-commit, which guarantees +This minimum configuration assumes that you have a ``requirements/`` directory that +contains ``requirements_tests.txt`` and ``requirements_doc.txt``. In +addition, the ``style`` environment will execute ``pre-commit``, which guarantees the usage of this tool in your project. Installing ``tox`` ~~~~~~~~~~~~~~~~~~ -You can install this tool as any other Python one by running: +You can install ``tox`` like any other Python package: .. code-block:: bash @@ -216,18 +214,18 @@ You can install this tool as any other Python one by running: Using ``tox`` ~~~~~~~~~~~~~ -The core concept behind `tox`_ are ``environments``. These are similar to -``Makefile`` rules and highly customizable. Previous configuration ships with -different environments among which you can find: +`tox`_ uses ``environments``, which are similar to ``Makefile`` rules, +to make it highly customizable. Descriptions follow of some of the most +widely used environments: - ``style``: for checking the code style of your project. -- ``py``: which will run your test suite. +- ``py``: for running your test suite. - ``doc``: for building the documentation of your project. Execute any of the previous environments by running ``tox -e ``. You -can run multiple environments by specifying those with commas ``tox -e +can run multiple environments by separating them with commas ``tox -e ,,...```. To run all available environments, simply -execute ``tox``. +run ``tox``. .. LINKS AND REFERENCES diff --git a/doc/source/coding-style/index.rst b/doc/source/coding-style/index.rst index 90691ddd..3597a177 100644 --- a/doc/source/coding-style/index.rst +++ b/doc/source/coding-style/index.rst @@ -1,13 +1,14 @@ Coding Style ############ -Coding Style refers to the different rules defined in a software project which -need to be followed when writing source code. These guidelines ensure that all -the source code is going to look the same across the different files of the +Coding style refers to the different rules defined in a software project that +must be followed when writing source code. These rules ensure that all +the source code will look the same across the different files of the project. -The PyAnsys ecosystem is composed by multiple projects. To unify the coding -style among all projects, this coding style guideline was devised. +Because the PyAnsys ecosystem consists of many projects, coding style rules +are critical to ensuring that the source code will look the same across different +projects. PyAnsys libraries are expected to follow `PEP 8`_ and be consistent in style and formatting with the 'big three' data science libraries: `NumPy`_, `SciPy`_, and From b24f20ff1e23a475766dadf57c5a2d134694eb90 Mon Sep 17 00:00:00 2001 From: Jorge Martinez Date: Mon, 23 May 2022 10:49:38 +0200 Subject: [PATCH 09/18] Add more tabs --- doc/source/coding-style/pep8.rst | 155 ++++++++++++++++++------------- 1 file changed, 88 insertions(+), 67 deletions(-) diff --git a/doc/source/coding-style/pep8.rst b/doc/source/coding-style/pep8.rst index eea6f72d..91677df3 100644 --- a/doc/source/coding-style/pep8.rst +++ b/doc/source/coding-style/pep8.rst @@ -35,6 +35,7 @@ might only be discovered during runtime. def compute_logbase8(x): import math + return math.log(8, x) .. tab:: Use @@ -71,7 +72,7 @@ All imports should be performed in alphabetically order. def compute_logbase8(x): - return math.log(8, x) + return math.log(8, x) .. tab:: Use @@ -83,7 +84,7 @@ All imports should be performed in alphabetically order. import sys from mypackage import mymodule - + def compute_logbase8(x): return math.log(8, x) @@ -189,8 +190,9 @@ classes. Do not separate words with underscores. .. code:: python - class MyClass(): + class MyClass: """Docstring for MyClass""" + ... @@ -206,7 +208,7 @@ following conventions apply: .. code:: python - class MyClass(): + class MyClass: """Docstring for MyClass.""" def __init__(self, value): @@ -282,9 +284,11 @@ Indentation should be used to emphasize: class MyFirstClass: """MyFirstClass docstring.""" + class MySecondClass: """MySecondClass docstring.""" + def top_level_function(): """Top level function docstring.""" return @@ -372,7 +376,11 @@ this line is difficult to follow: .. code:: python - employee_hours = [schedule.earliest_hour for employee in self.public_employees for schedule in employee.schedules] + employee_hours = [ + schedule.earliest_hour + for employee in self.public_employees + for schedule in employee.schedules + ] .. tab:: Use @@ -461,13 +469,13 @@ Instead of: .. code:: python - x = 'John Smith' # Student Name + x = "John Smith" # Student Name Use: .. code:: python - user_name = 'John Smith' + user_name = "John Smith" Docstring Conventions @@ -509,55 +517,63 @@ Booleans and Comparisons Don't compare Boolean values to ``True`` or ``False`` using the equivalence operator. -Instead of: - -.. code:: python +.. tabs:: - if my_bool == True: - return result + .. tab:: Avoid -Use: + .. code-block:: python + + if my_bool == True: + return result -.. code:: python + .. tab:: Use - if my_bool: - return result + .. code-block:: python + + if my_bool: + return result Knowing that empty sequences are evaluated to ``False``, don't compare the length of these objects but rather consider how they would evaluate by using ``bool()``. -Instead of: - -.. code:: python - - my_list = [] - if not len(my_list): - raise ValueError('List is empty') +.. tabs:: -Use: + .. tab:: Avoid + + .. code-block:: python + + my_list = [] + if not len(my_list): + raise ValueError('List is empty') -.. code:: python + .. tab:: Use + + .. code-block:: python + + my_list = [] + if not my_list: + raise ValueError('List is empty') - my_list = [] - if not my_list: - raise ValueError('List is empty') In ``if`` statements, use ``is not`` rather than ``not ...``. -Instead of: - -.. code:: python +.. tabs:: - if not x is None: - return x + .. tab:: Avoid -Use: + .. code-block:: python + + if not x is None: + return x -.. code:: python + .. tab:: Use + + .. code-block:: python + + if x is not None: + return 'x exists!' - if x is not None: - return 'x exists!' Also, avoid ``if x:`` when you mean ``if x is not None:``. This is especially important when parsing arguments. @@ -567,25 +583,28 @@ Handling Strings ~~~~~~~~~~~~~~~~ Use ``.startswith()`` and ``.endswith()`` instead of slicing. -Instead of: - -.. code:: python - - if word[:3] == 'cat': - print('The word starts with "cat"') - if file_name[-3:] == 'jpg': - print('The file is a JPEG') - -Use: +.. tabs:: -.. code:: python + .. tab:: Avoid - if word.startswith('cat'): - print('The word starts with "cat"') + .. code-block:: python + + if word[:3] == 'cat': + print('The word starts with "cat"') + + if file_name[-3:] == 'jpg': + print('The file is a JPEG') - if file_name.endswith('.jpg'): - print('The file is a JPEG') + .. tab:: Use + + .. code-block:: python + + if word.startswith('cat'): + print('The word starts with "cat"') + + if file_name.endswith('.jpg'): + print('The file is a JPEG') Reading the Windows Registry @@ -594,17 +613,19 @@ Never read the Windows registry or write to it because this is dangerous and makes it difficult to deploy libraries on different environments or operating systems. -Bad practice - Example 1 - -.. code:: python - - self.sDesktopinstallDirectory = Registry.GetValue("HKEY_LOCAL_MACHINE\Software\Ansoft\ElectronicsDesktop\{}\Desktop".format(self.sDesktopVersion), "InstallationDirectory", '') +.. tabs:: -Bad practice - Example 2 + .. tab:: Avoid -.. code:: python + .. code-block:: python - EMInstall = (string)Registry.GetValue(string.Format(@"HKEY_LOCAL_MACHINE\SOFTWARE\Ansoft\ElectronicsDesktop{0}\Desktop", AnsysEmInstall.DesktopVersion), "InstallationDirectory", null); + self.sDesktopinstallDirectory = Registry.GetValue( + "HKEY_LOCAL_MACHINE\Software\Ansoft\ElectronicsDesktop\{}\Desktop".format( + self.sDesktopVersion + ), + "InstallationDirectory", + "", + ) Duplicated Code @@ -681,8 +702,8 @@ within one single code block. def validate_something(self, a, b, c): if a > b: - if a*2 > b: - if a*3 < b: + if a * 2 > b: + if a * 3 < b: raise ValueError else: for i in range(10): @@ -732,7 +753,7 @@ to circumvent nested loops. .. code-block:: python - squares = [i*i for i in range(10)] + squares = [i * i for i in range(10)] .. code-block:: pycon @@ -775,10 +796,10 @@ example, extract all consonants in a sentence: .. code-block:: pycon - >>> sentence = 'This is a sample sentence.' - >>> consonants = [letter for letter in sentence if is_consonant(letter)] - >>> print(f"{consonants = }") - consonants = ['T', 'h', 's', 's', 's', 'm', 'p', 'l', 's', 'n', 't', 'n', 'c'] + >>> sentence = "This is a sample sentence." + >>> consonants = [letter for letter in sentence if is_consonant(letter)] + >>> print(f"{consonants = }") + consonants = ['T', 'h', 's', 's', 's', 'm', 'p', 'l', 's', 'n', 't', 'n', 'c'] The second approach is more readable and better documented. Additionally, you could implement a unit test for ``is_consonant``. From e32bfbd4c2b9ff2deb9a2bb606b2b491ac2bc9e2 Mon Sep 17 00:00:00 2001 From: Jorge Martinez Date: Mon, 23 May 2022 11:08:02 +0200 Subject: [PATCH 10/18] Add additional options to flake8 --- doc/source/coding-style/formatting-tools.rst | 28 ++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/doc/source/coding-style/formatting-tools.rst b/doc/source/coding-style/formatting-tools.rst index 760952ec..fba09330 100644 --- a/doc/source/coding-style/formatting-tools.rst +++ b/doc/source/coding-style/formatting-tools.rst @@ -64,6 +64,34 @@ The configuration for `flake8`_ must be specified in a ``.flake8`` file. max-line-length = 88 extend-ignore = E203 +Flake8 has many options that can be set within the configuration file. +For a list and descriptions, see this `Flake8 documentation topic +`__. + +The example configuration defines the following options: + +- ``exclude`` + Denotes subdirectories and files to be excluded from the check. + +- ``select`` + Sequence of error codes that Flake8 will report errors + for. The set in the above configuration is a basic set of errors to + check for and is not an exhaustive list. + + For a full list of error codes and their descriptions, see this `Flake8 + documentation topic `__. + +- ``count`` + Total number of errors to print at the end of the check. + +- ``max-complexity`` + Sets the maximum allowed McCabe complexity value for a block of code. + The value of 10 was chosen because it is a common default. + +- ``statistics`` + Number of occurrences of each error or warning code + to be printed as a report at the end of the check. + Pre-commit ---------- From 194e674a3d6a8b519d31e6564aa181dc97acca7f Mon Sep 17 00:00:00 2001 From: Jorge Martinez Date: Mon, 23 May 2022 11:51:30 +0200 Subject: [PATCH 11/18] Improve formatting tools --- doc/source/coding-style/code/tox-flit.rst | 43 +++++++++ doc/source/coding-style/code/tox-poetry.rst | 46 ++++++++++ doc/source/coding-style/formatting-tools.rst | 94 +++++++++----------- 3 files changed, 129 insertions(+), 54 deletions(-) create mode 100644 doc/source/coding-style/code/tox-flit.rst create mode 100644 doc/source/coding-style/code/tox-poetry.rst diff --git a/doc/source/coding-style/code/tox-flit.rst b/doc/source/coding-style/code/tox-flit.rst new file mode 100644 index 00000000..ef8bf454 --- /dev/null +++ b/doc/source/coding-style/code/tox-flit.rst @@ -0,0 +1,43 @@ +.. code-block:: ini + + [tox] + description = Default tox environments list + envlist = + style,{py37,py38,py39,py310}{,-coverage},doc + skip_missing_interpreters = true + isolated_build = true + isolated_build_env = build + + [testenv] + description = Checks for project unit tests and coverage (if desired) + basepython = + py37: python3.7 + py38: python3.8 + py39: python3.9 + py310: python3.10 + py: python3 + {style,reformat,doc,build}: python3 + setenv = + PYTHONUNBUFFERED = yes + coverage: PYTEST_EXTRA_ARGS = --cov=ansys.product --cov-report=term --cov-report=xml --cov-report=html + deps = + -r{toxinidir}/requirements/requirements_tests.txt + commands = + pytest {env:PYTEST_MARKERS:} {env:PYTEST_EXTRA_ARGS:} {posargs:-vv} + + [testenv:style] + description = Checks project code style + skip_install = true + deps = + pre-commit + commands = + pre-commit install + pre-commit run --all-files --show-diff-on-failure + + [testenv:doc] + description = Check if documentation generates properly + deps = + -r{toxinidir}/requirements/requirements_doc.txt + commands = + sphinx-build -d "{toxworkdir}/doc_doctree" doc/source "{toxworkdir}/doc_out" --color -vW -bhtml + diff --git a/doc/source/coding-style/code/tox-poetry.rst b/doc/source/coding-style/code/tox-poetry.rst new file mode 100644 index 00000000..c44d4e65 --- /dev/null +++ b/doc/source/coding-style/code/tox-poetry.rst @@ -0,0 +1,46 @@ +.. code-block:: ini + + [tox] + description = Default tox environments list + envlist = + style,{py37,py38,py39,py310}{,-coverage},doc + skip_missing_interpreters = true + isolated_build = true + + [testenv] + description = Checks for project unit tests and coverage (if desired) + basepython = + py37: python3.7 + py38: python3.8 + py39: python3.9 + py310: python3.10 + py: python3 + {style,reformat,doc,build}: python3 + skip_install = true + whitelist_externals = + poetry + setenv = + PYTHONUNBUFFERED = yes + coverage: PYTEST_EXTRA_ARGS = --cov=ansys.product --cov-report=term --cov-report=xml --cov-report=html + deps = + -r{toxinidir}/requirements/requirements_tests.txt + commands = + poetry install + poetry run pytest {env:PYTEST_MARKERS:} {env:PYTEST_EXTRA_ARGS:} {posargs:-vv} + + [testenv:style] + description = Checks project code style + skip_install = true + deps = + pre-commit + commands = + pre-commit install + pre-commit run --all-files --show-diff-on-failure + + [testenv:doc] + description = Check if documentation generates properly + deps = + -r{toxinidir}/requirements/requirements_doc.txt + commands = + poetry run sphinx-build -d "{toxworkdir}/doc_doctree" doc/source "{toxworkdir}/doc_out" --color -vW -bhtml + diff --git a/doc/source/coding-style/formatting-tools.rst b/doc/source/coding-style/formatting-tools.rst index fba09330..c8169aca 100644 --- a/doc/source/coding-style/formatting-tools.rst +++ b/doc/source/coding-style/formatting-tools.rst @@ -25,7 +25,7 @@ The minimum `black`_ configuration for a PyAnsys project should look like this: .. code-block:: toml [tool.black] - line-length: "" + line-length: Isort @@ -42,7 +42,7 @@ tools so that no conflicts appear. To do so, make sure you take advantage of the [tool.isort] profile = "black" force_sort_within_sections = true - line_length = "" + line_length = default_section = "THIRDPARTY" src_paths = ["doc", "src", "tests"] @@ -93,6 +93,27 @@ The example configuration defines the following options: to be printed as a report at the end of the check. +Code Coverage +------------- +Code coverage allows to check the percetange of codebase tested by the test +suite. Code coverage should be as high as possible to guarantee that every piece +of code has been tested. + +For ``PyAnsys``, code coverage is done using `pytest-cov`_, a `pytest`_ plugin +which will trigger the code coverage analysis once your test suite has executed. + +Considering the layout presented in :ref:`Required Files`, the following +configuration for code coverage is the minimum one required for a ``PyAnsys`` +project: + +.. code-block:: toml + + [tool.coverage.run] + source = ["ansys."] + + [tool.coverage.report] + show_missing = true + Pre-commit ---------- To ensure that every commit you make is compliant with the code style @@ -101,7 +122,7 @@ Every time you stage some changes and try to commit them, `pre-commit`_ will only allow you to do this only if all defined hooks succeed. The configuration for `pre-commit`_ must be defined in a -`.pre-commit-config.yaml` file. The following lines present a minimum +``.pre-commit-config.yaml`` file. The following lines present a minimum `pre-commit`_ configuration that includes both code and documentation formatting tools. @@ -167,10 +188,6 @@ If you want to manually run ``pre-commit``, you can run: This command will show the current and expected style of the code if any of the hooks fail. - -Using ``pre-commit`` -~~~~~~~~~~~~~~~~~~~~ - Tox --- A tool you might consider using in your project is `tox`_. While this automation @@ -181,48 +198,16 @@ virtual environment. Being able to test your package in isolation rather than in Configuration for `tox`_ is stored in a ``tox.ini`` file. The minimum configuration for a PyAnsys ``py-`` project should be: -.. code-block:: ini - [tox] - description = Default tox environments list - envlist = - style,{py37,py38,py39,py310}{,-coverage},doc - skip_missing_interpreters = true - isolated_build = true - isolated_build_env = build - - [testenv] - description = Checks for project unit tests and coverage (if desired) - basepython = - py37: python3.7 - py38: python3.8 - py39: python3.9 - py310: python3.10 - py: python3 - {style,reformat,doc,build}: python3 - setenv = - PYTHONUNBUFFERED = yes - coverage: PYTEST_EXTRA_ARGS = --cov=ansys.product --cov-report=term --cov-report=xml --cov-report=html - deps = - -r{toxinidir}/requirements/requirements_tests.txt - commands = - pytest {env:PYTEST_MARKERS:} {env:PYTEST_EXTRA_ARGS:} {posargs:-vv} - - [testenv:style] - description = Checks project code style - skip_install = true - deps = - pre-commit - commands = - pre-commit install - pre-commit run --all-files --show-diff-on-failure - - [testenv:doc] - description = Check if documentation generates properly - deps = - -r{toxinidir}/requirements/requirements_doc.txt - commands = - sphinx-build -d "{toxworkdir}/doc_doctree" doc/source "{toxworkdir}/doc_out" --color -vW -bhtml +.. tabs:: + + .. tab:: Tox with Flit + + .. include:: code/tox-flit.rst + + .. tab:: Tox with Poetry + + .. include:: code/tox-poetry.rst This minimum configuration assumes that you have a ``requirements/`` directory that @@ -246,13 +231,12 @@ Using ``tox`` to make it highly customizable. Descriptions follow of some of the most widely used environments: -- ``style``: for checking the code style of your project. -- ``py``: for running your test suite. -- ``doc``: for building the documentation of your project. +- ``tox -e style`` checks the code style of your project. +- ``tox -e py`` runs your test suite. +- ``tox -e doc`` builds the documentation of your project. -Execute any of the previous environments by running ``tox -e ``. You -can run multiple environments by separating them with commas ``tox -e -,,...```. To run all available environments, simply +It is possible to run multiple environments by separating them with commas ``tox +-e ,,...```. To run all available environments, simply run ``tox``. @@ -262,6 +246,8 @@ run ``tox``. .. _isort: https://pycqa.github.io/isort/ .. _flake8: https://flake8.pycqa.org/en/latest/ .. _pre-commit: https://pre-commit.com/ +.. _pytest: https://docs.pytest.org/en/latest/ +.. _pytest-cov: https://pytest-cov.readthedocs.io/en/latest/ .. _tox: https://tox.wiki/en/latest/ .. _PEP 8: https://www.python.org/dev/peps/pep-0008/ .. _make: https://www.gnu.org/software/make/ From 1c890507a6106c1a98839580f2dcb743edd1d604 Mon Sep 17 00:00:00 2001 From: Jorge Martinez Date: Mon, 23 May 2022 12:16:55 +0200 Subject: [PATCH 12/18] Add required standard section --- doc/source/coding-style/index.rst | 1 + doc/source/coding-style/required-standard.rst | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 doc/source/coding-style/required-standard.rst diff --git a/doc/source/coding-style/index.rst b/doc/source/coding-style/index.rst index 3597a177..3a9e71ce 100644 --- a/doc/source/coding-style/index.rst +++ b/doc/source/coding-style/index.rst @@ -20,6 +20,7 @@ formatting with the 'big three' data science libraries: `NumPy`_, `SciPy`_, and pep8 formatting-tools + required-standard .. LINKS AND REFERENCES diff --git a/doc/source/coding-style/required-standard.rst b/doc/source/coding-style/required-standard.rst new file mode 100644 index 00000000..92be7f98 --- /dev/null +++ b/doc/source/coding-style/required-standard.rst @@ -0,0 +1,6 @@ +Required Standard +================= + +This section collects the minimum required standard for any ``PyAnsys`` project. +The individual configurations for the tools presented in :ref:`Code Formatting +Tools` and :ref:`Doc Formatting Tools` are combined together. From 47f222bc851ba850cfc772086786c23528d59c24 Mon Sep 17 00:00:00 2001 From: Jorge Martinez Date: Mon, 23 May 2022 16:39:42 +0200 Subject: [PATCH 13/18] Add required standard --- doc/source/coding-style/formatting-tools.rst | 4 +- doc/source/coding-style/required-standard.rst | 123 +++++++++++++++++- 2 files changed, 122 insertions(+), 5 deletions(-) diff --git a/doc/source/coding-style/formatting-tools.rst b/doc/source/coding-style/formatting-tools.rst index c8169aca..25adf3e9 100644 --- a/doc/source/coding-style/formatting-tools.rst +++ b/doc/source/coding-style/formatting-tools.rst @@ -25,7 +25,7 @@ The minimum `black`_ configuration for a PyAnsys project should look like this: .. code-block:: toml [tool.black] - line-length: + line-length: "" Isort @@ -42,7 +42,7 @@ tools so that no conflicts appear. To do so, make sure you take advantage of the [tool.isort] profile = "black" force_sort_within_sections = true - line_length = + line_length = "" default_section = "THIRDPARTY" src_paths = ["doc", "src", "tests"] diff --git a/doc/source/coding-style/required-standard.rst b/doc/source/coding-style/required-standard.rst index 92be7f98..006496c5 100644 --- a/doc/source/coding-style/required-standard.rst +++ b/doc/source/coding-style/required-standard.rst @@ -1,6 +1,123 @@ Required Standard ================= -This section collects the minimum required standard for any ``PyAnsys`` project. -The individual configurations for the tools presented in :ref:`Code Formatting -Tools` and :ref:`Doc Formatting Tools` are combined together. +This section collects the required standard for any ``PyAnsys`` project. The +individual configurations for the tools presented in :ref:`Code Style Tools` and +:ref:`Doc Style Tools` are combined together. + +The following lines should be included in :ref:`The \`\`pyproject.toml\`\` File` +to indicate the configuration of the different code and documentation style tools. + + +Required ``pyproject.toml`` Config +---------------------------------- + +.. code-block:: toml + + [tool.black] + line-length: "" + + [tool.isort] + profile = "black" + force_sort_within_sections = true + line_length = "" + default_section = "THIRDPARTY" + src_paths = ["doc", "src", "tests"] + + [tool.coverage.run] + source = ["ansys."] + + [tool.coverage.report] + show_missing = true + + [tool.pytest.ini_options] + addopts = "--doctest-modules" + + [tool.pydocstyle] + convention = "numpy" + + +Required ``.flake8`` Config +--------------------------- +Also, the following ``.flake8`` file is required: + +.. code-block:: toml + + [flake8] + max-line-length = 88 + extend-ignore = E203 + + +Required ``pre-commit`` Config +------------------------------ +You can take advantage of :ref:`Pre-Commit`, and include a +``.pre-commit-config.yaml`` file like the following one in your project: + + +.. code-block:: yaml + + repos: + + - repo: https://github.com/psf/black + rev: X.Y.Z + hooks: + - id: black + + - repo: https://github.com/pycqa/isort + rev: X.Y.Z + hooks: + - id: isort + + - repo: https://github.com/PyCQA/flake8 + rev: X.Y.Z + hooks: + - id: flake8 + + - repo: https://github.com/codespell-project/codespell + rev: vX.Y.Z + hooks: + - id: codespell + + - repo: https://github.com/pycqa/pydocstyle + rev: X.Y.Z + hooks: + - id: pydocstyle + additional_dependencies: [toml] + exclude: "tests/" + + +GitHub CI/CD integration +------------------------ +Finally, you can take advantage of :ref:`Unit Testing on GitHub via CI/CD` and +add create a ``style.yml`` workflow file in ``.github/workflows/``: + +.. code-block:: yaml + + name: Style + + on: + pull_request: + push: + tags: + - "*" + branches: + - main + + jobs: + style: + name: Code & Doc + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: '3.10' + - name: Install requirements + run: | + python -m pip install -U pip pre-commit + + - name: Run pre-commit + run: | + pre-commit run --all-files --show-diff-on-failure From 977a5e01b7f4546cd6e3a8624b272c7c8c478062 Mon Sep 17 00:00:00 2001 From: Jorge Martinez Date: Mon, 23 May 2022 16:42:13 +0200 Subject: [PATCH 14/18] Improve pep8.rst --- doc/source/coding-style/pep8.rst | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/doc/source/coding-style/pep8.rst b/doc/source/coding-style/pep8.rst index 91677df3..6df93c3a 100644 --- a/doc/source/coding-style/pep8.rst +++ b/doc/source/coding-style/pep8.rst @@ -465,17 +465,19 @@ avoided: Focus on writing self-documenting code and using short but descriptive variable names. -Instead of: - -.. code:: python - - x = "John Smith" # Student Name +.. tabs:: -Use: + .. tab:: Avoid -.. code:: python + .. code:: python + + x = "John Smith" # Student Name - user_name = "John Smith" + .. tab:: Use + + .. code:: python + + user_name = "John Smith" Docstring Conventions From 38389d70a4fa045657feb8ed5a26422098ad4744 Mon Sep 17 00:00:00 2001 From: Jorge Martinez Date: Mon, 23 May 2022 17:28:38 +0200 Subject: [PATCH 15/18] Add code suggestions --- doc/source/coding-style/pep8.rst | 67 +++++++++++++++----------------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/doc/source/coding-style/pep8.rst b/doc/source/coding-style/pep8.rst index 6df93c3a..1293abcd 100644 --- a/doc/source/coding-style/pep8.rst +++ b/doc/source/coding-style/pep8.rst @@ -1,10 +1,10 @@ PEP 8 ===== -This topic summarizes the key points from `PEP 8`_ and how they apply to PyAnsys -libraries. `PEP 8`_ style guideline was devised by the Python community in order +This section summarizes the key points from `PEP 8`_ and how they apply to PyAnsys +libraries. `PEP 8`_ style guideline were devised by the Python community to increase the readability of Python code. `PEP 8`_ has been adopted by some of -the most popular libraries within the Python ecosystem such us: `NumPy`_, +the most popular libraries within the Python ecosystem, including: `NumPy`_, `SciPy`_, and `pandas`_. .. _PEP 8: https://www.python.org/dev/peps/pep-0008/ @@ -15,11 +15,10 @@ the most popular libraries within the Python ecosystem such us: `NumPy`_, Imports ------- -The following lines describe the code style guidelines that apply for the -``import`` statement. +Code style guidelines follow for ``import`` statements. -Imports Location -~~~~~~~~~~~~~~~~ +Import Location +~~~~~~~~~~~~~~~ Imports should always be placed at the top of the file, just after any module comments and docstrings and before module globals and constants. This reduces the likelihood of an `ImportError`_ that @@ -55,9 +54,9 @@ For better readability, group imports in this order: #. Standard library imports #. Related third-party imports -#. Local application- or library-specific imports +#. Local application-specific or library-specific imports -All imports should be performed in alphabetically order. +All imports within each import grouping should be performed in alphabetical order. .. tabs:: @@ -124,9 +123,9 @@ package. return math.log(8, x) -Imports Namespace +Import Namespaces ~~~~~~~~~~~~~~~~~ -You should avoid using wild cards in imports because doing so can make it +You should avoid using wildcards in imports because doing so can make it difficult to detect undefined names. For more information, see `Python Anti-Patterns: using wildcard imports <(https://docs.quantifiedcode.com/python-anti-patterns/maintainability/from_module_import_all_used.html>`_. @@ -162,7 +161,6 @@ global rules to determine the correct names: Variables ~~~~~~~~~ - Do not use the characters ``'l'``, ``'O'`` , or ``'I'`` as single-character variable names. In some fonts, these characters are indistinguishable from the numerals one and zero. @@ -200,9 +198,9 @@ Use a lowercase word or words for Python functions or methods. Separate words with underscores to improve readability. When naming class methods, the following conventions apply: -- Only `dunder methods`_ must be enclosed by double underscores. -- Methods starting with double underscores are considered to be private methods. -- Methods starting with a single underscore are considered to be protected methods. +- Enclose only `dunder methods`_ with double underscores. +- Start a method that is to be considered private with double underscores. +- Start a method that is to be considered protected with a single underscore. .. _dunder methods: https://docs.python.org/3/reference/datamodel.html#special-method-names @@ -242,10 +240,9 @@ following conventions apply: .. note:: - Remember that functions and methods naming is just a convention. In Python - there are not private members, meaning that you can always access these even - if they start with underscores. - + Remember that these are only conventions for naming functions and methods. In Python + there are no private or protected members, meaning that you can always access even + those members that start with underscores. Variables ~~~~~~~~~ @@ -294,7 +291,7 @@ Indentation should be used to emphasize: return For improved readability, add blank lines or wrapping lines. Two -blank lines should be added before and after all function and class +blank lines should be added before and after all class and function definitions. Inside a class, use a single line before any method definition. @@ -398,8 +395,8 @@ classic loop. Notice that sometimes it will not be possible to keep the line length below the desired value without breaking the syntax rules. -Comments Conventions --------------------- +Comments +-------- Because a PyAnsys library generally involves multiple physics domains, users reading its source code do not have the same background as the developers who wrote it. This is why it is important for a library @@ -510,7 +507,7 @@ Programming Recommendations --------------------------- The following sections provide some `PEP8 `_ suggestions for removing -ambiguity and preserving consistency. They address some common pitfalls +ambiguity and preserving consistency. They also address some common pitfalls when writing Python code. @@ -592,21 +589,21 @@ Use ``.startswith()`` and ``.endswith()`` instead of slicing. .. code-block:: python - if word[:3] == 'cat': - print('The word starts with "cat"') + if word[:3] == "cat": + print("The word starts with 'cat'.") - if file_name[-3:] == 'jpg': - print('The file is a JPEG') + if file_name[-4:] == ".jpg": + print("The file is a JPEG.") .. tab:: Use .. code-block:: python - if word.startswith('cat'): - print('The word starts with "cat"') + if word.startswith("cat"): + print("The word starts with 'cat'.") - if file_name.endswith('.jpg'): - print('The file is a JPEG') + if file_name.endswith(".jpg"): + print("The file is a JPEG.") Reading the Windows Registry @@ -634,7 +631,7 @@ Duplicated Code ~~~~~~~~~~~~~~~ Follow the DRY principle, which states that "Every piece of knowledge must have a single, unambiguous, authoritative representation within a -system." Attempt to follow this principle unless it overly complicates +system." Follow this principle unless it overly complicates the code. For instance, the following example converts Fahrenheit to Kelvin twice, which now requires the developer to maintain two separate lines that do the same thing. @@ -690,8 +687,8 @@ for this method. def test_fahr_to_kelvin(): np.testing.assert_allclose(12.7778, fahr_to_kelvin(55)) -Now, not only do you have one line of code to verify, but you can also -use a testing framework such as ``pytest`` to test that the method is +Now, you have only one line of code to verify and can also use +a testing framework such as ``pytest`` to test that the method is correct. @@ -766,7 +763,7 @@ to circumvent nested loops. If the loop is too complicated for creating a list comprehension, consider creating small functions and calling these instead. For -example, extract all consonants in a sentence: +example to extract all consonants in a sentence: .. tabs:: From 0f23cadb4581df12058ac5cbd6c316ee1081fcc6 Mon Sep 17 00:00:00 2001 From: Jorge Martinez Date: Mon, 23 May 2022 17:32:31 +0200 Subject: [PATCH 16/18] Apply blacken-docs --- doc/source/abstractions/app-interface.rst | 82 ++++++++++--------- doc/source/coding-style/pep8.rst | 6 +- doc/source/doc-style/formatting-tools.rst | 5 +- doc/source/guidelines/version_support.rst | 5 +- doc/source/packaging/code/setup_file_code.rst | 4 +- 5 files changed, 48 insertions(+), 54 deletions(-) diff --git a/doc/source/abstractions/app-interface.rst b/doc/source/abstractions/app-interface.rst index d5a71874..25d795e6 100644 --- a/doc/source/abstractions/app-interface.rst +++ b/doc/source/abstractions/app-interface.rst @@ -61,45 +61,49 @@ within this method. .. code:: python - def create_open_region(self, frequency="1GHz", boundary="Radiation", - apply_infinite_gp=False, gp_axis="-z"): - """Create an open region on the active editor. - - Parameters - ---------- - frequency : str, optional - Frequency with units. The default is ``"1GHz"``. - boundary : str, optional - Type of the boundary. The default is ``"Radiation"``. - apply_infinite_gp : bool, optional - Whether to apply an infinite ground plane. The default is ``False``. - gp_axis : str, optional - The default is ``"-z"``. - - Returns - ------- - bool - ``True`` when successful, ``False`` when failed. - - Examples - -------- - Create an open region in the active editor at 1 GHz. - - >>> hfss.create_open_region(frequency="1GHz") - - """ - vars = [ - "NAME:Settings", - "OpFreq:=", frequency, - "Boundary:=", boundary, - "ApplyInfiniteGP:=", apply_infinite_gp - ] - if apply_infinite_gp: - vars.append("Direction:=") - vars.append(gp_axis) - - self._omodelsetup.CreateOpenRegion(vars) - return True + def create_open_region( + self, frequency="1GHz", boundary="Radiation", apply_infinite_gp=False, gp_axis="-z" + ): + """Create an open region on the active editor. + + Parameters + ---------- + frequency : str, optional + Frequency with units. The default is ``"1GHz"``. + boundary : str, optional + Type of the boundary. The default is ``"Radiation"``. + apply_infinite_gp : bool, optional + Whether to apply an infinite ground plane. The default is ``False``. + gp_axis : str, optional + The default is ``"-z"``. + + Returns + ------- + bool + ``True`` when successful, ``False`` when failed. + + Examples + -------- + Create an open region in the active editor at 1 GHz. + + >>> hfss.create_open_region(frequency="1GHz") + + """ + vars = [ + "NAME:Settings", + "OpFreq:=", + frequency, + "Boundary:=", + boundary, + "ApplyInfiniteGP:=", + apply_infinite_gp, + ] + if apply_infinite_gp: + vars.append("Direction:=") + vars.append(gp_axis) + + self._omodelsetup.CreateOpenRegion(vars) + return True Here, the COM ``CreateOpenRegion`` method is abstracted, encapsulating the model setup object. There's no reason why a user needs direct diff --git a/doc/source/coding-style/pep8.rst b/doc/source/coding-style/pep8.rst index 1293abcd..3faccbed 100644 --- a/doc/source/coding-style/pep8.rst +++ b/doc/source/coding-style/pep8.rst @@ -373,11 +373,7 @@ this line is difficult to follow: .. code:: python - employee_hours = [ - schedule.earliest_hour - for employee in self.public_employees - for schedule in employee.schedules - ] + employee_hours = [schedule.earliest_hour for employee in self.public_employees for schedule in employee.schedules] .. tab:: Use diff --git a/doc/source/doc-style/formatting-tools.rst b/doc/source/doc-style/formatting-tools.rst index 87f29edb..626ecb6b 100644 --- a/doc/source/doc-style/formatting-tools.rst +++ b/doc/source/doc-style/formatting-tools.rst @@ -97,10 +97,7 @@ list of extensions: .. code-block:: python - extensions = [ - 'numpydoc', - ... - ] + extensions = ["numpydoc", ...] Once the `numpydoc`_ extension is added, you can select which `validation checks `_ diff --git a/doc/source/guidelines/version_support.rst b/doc/source/guidelines/version_support.rst index b9a990f2..bf7c9195 100644 --- a/doc/source/guidelines/version_support.rst +++ b/doc/source/guidelines/version_support.rst @@ -34,10 +34,7 @@ required Python version within ``setup.py`` with: [...] - setup(name="my_package_name", - python_requires='>3.6', - [...] - ) + setup(name="my_package_name", python_requires=">3.6", [...]) This helps ``pip`` to know which versions of your library support which versions of Python. You can also impose an upper limit if you're diff --git a/doc/source/packaging/code/setup_file_code.rst b/doc/source/packaging/code/setup_file_code.rst index 3fce14eb..39759c80 100644 --- a/doc/source/packaging/code/setup_file_code.rst +++ b/doc/source/packaging/code/setup_file_code.rst @@ -1,9 +1,9 @@ .. code:: python """Installation file for ansys-mapdl-core.""" - + from setuptools import find_namespace_packages, setup - + setup( name="ansys--", packages=find_namespace_packages(where="src", include="ansys*"), From 15acec5f956e888b13156a0c30d590d2325eec16 Mon Sep 17 00:00:00 2001 From: Jorge Martinez Date: Mon, 23 May 2022 17:50:25 +0200 Subject: [PATCH 17/18] Fix code snippets --- doc/source/coding-style/pep8.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/source/coding-style/pep8.rst b/doc/source/coding-style/pep8.rst index 3faccbed..f2a2ca44 100644 --- a/doc/source/coding-style/pep8.rst +++ b/doc/source/coding-style/pep8.rst @@ -734,9 +734,9 @@ to circumvent nested loops. .. code-block:: python - squares = [] - for i in range(10): - squares.append(i * i) + squares = [] + for i in range(10): + squares.append(i * i) .. code-block:: pycon @@ -791,10 +791,10 @@ example to extract all consonants in a sentence: .. code-block:: pycon - >>> sentence = "This is a sample sentence." - >>> consonants = [letter for letter in sentence if is_consonant(letter)] - >>> print(f"{consonants = }") - consonants = ['T', 'h', 's', 's', 's', 'm', 'p', 'l', 's', 'n', 't', 'n', 'c'] + >>> sentence = "This is a sample sentence." + >>> consonants = [letter for letter in sentence if is_consonant(letter)] + >>> print(f"{consonants = }") + consonants = ['T', 'h', 's', 's', 's', 'm', 'p', 'l', 's', 'n', 't', 'n', 'c'] The second approach is more readable and better documented. Additionally, you could implement a unit test for ``is_consonant``. From 28bf52f0e4d324b07980589bdc37370f94fce8f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Mart=C3=ADnez?= <28702884+jorgepiloto@users.noreply.github.com> Date: Tue, 24 May 2022 09:52:34 +0200 Subject: [PATCH 18/18] Apply suggestions from code review Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> --- doc/source/abstractions/app-interface.rst | 2 +- doc/source/coding-style/formatting-tools.rst | 38 +++++++++---------- doc/source/coding-style/required-standard.rst | 12 +++--- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/doc/source/abstractions/app-interface.rst b/doc/source/abstractions/app-interface.rst index 25d795e6..84bc5f4c 100644 --- a/doc/source/abstractions/app-interface.rst +++ b/doc/source/abstractions/app-interface.rst @@ -64,7 +64,7 @@ within this method. def create_open_region( self, frequency="1GHz", boundary="Radiation", apply_infinite_gp=False, gp_axis="-z" ): - """Create an open region on the active editor. + """Create an open region in the active editor. Parameters ---------- diff --git a/doc/source/coding-style/formatting-tools.rst b/doc/source/coding-style/formatting-tools.rst index 25adf3e9..2227226e 100644 --- a/doc/source/coding-style/formatting-tools.rst +++ b/doc/source/coding-style/formatting-tools.rst @@ -18,7 +18,7 @@ configuration to ensure that the Python code format looks almost the same across projects. While `PEP 8`_ imposes a default line length of 79 characters, `black`_ has -a default line length of 88 characters. +a default line length of 88 characters. The minimum `black`_ configuration for a PyAnsys project should look like this: @@ -31,10 +31,10 @@ The minimum `black`_ configuration for a PyAnsys project should look like this: Isort ----- The goal of `isort`_ is to properly format ``import`` statements by making sure -that they follow the standard order: library, third-party libraries, and custom library. +that they follow the standard order: library, third-party libraries, and custom libraries. When using `isort`_ with `black`_, it is important to properly configure both -tools so that no conflicts appear. To do so, make sure you take advantage of the +tools so that no conflicts arise. To accomplish this, use the ``--porfile black`` flag in `isort`_. .. code-block:: toml @@ -65,16 +65,16 @@ The configuration for `flake8`_ must be specified in a ``.flake8`` file. extend-ignore = E203 Flake8 has many options that can be set within the configuration file. -For a list and descriptions, see this `Flake8 documentation topic +For more information, see this `Flake8 documentation topic `__. -The example configuration defines the following options: +The example configuration defines these options: - ``exclude`` - Denotes subdirectories and files to be excluded from the check. + Subdirectories and files to exclude from the check. - ``select`` - Sequence of error codes that Flake8 will report errors + Sequence of error codes that Flake8 is to report errors for. The set in the above configuration is a basic set of errors to check for and is not an exhaustive list. @@ -85,22 +85,22 @@ The example configuration defines the following options: Total number of errors to print at the end of the check. - ``max-complexity`` - Sets the maximum allowed McCabe complexity value for a block of code. + Maximum allowed McCabe complexity value for a block of code. The value of 10 was chosen because it is a common default. - ``statistics`` Number of occurrences of each error or warning code - to be printed as a report at the end of the check. + to print as a report at the end of the check. Code Coverage ------------- -Code coverage allows to check the percetange of codebase tested by the test +Code coverage indicates the percentage of the codebase tested by the test suite. Code coverage should be as high as possible to guarantee that every piece of code has been tested. For ``PyAnsys``, code coverage is done using `pytest-cov`_, a `pytest`_ plugin -which will trigger the code coverage analysis once your test suite has executed. +that triggers the code coverage analysis once your test suite has executed. Considering the layout presented in :ref:`Required Files`, the following configuration for code coverage is the minimum one required for a ``PyAnsys`` @@ -118,8 +118,8 @@ Pre-commit ---------- To ensure that every commit you make is compliant with the code style guidelines for PyAnsys, you can take advantage of `pre-commit`_ in your project. -Every time you stage some changes and try to commit them, `pre-commit`_ will -only allow you to do this only if all defined hooks succeed. +Every time you stage some changes and try to commit them, `pre-commit`_ only +allows them to be committed if all defined hooks succeed. The configuration for `pre-commit`_ must be defined in a ``.pre-commit-config.yaml`` file. The following lines present a minimum @@ -166,7 +166,7 @@ You can install ``pre-commit`` by running: python -m pip install pre-commit -Then, make sure you install it as a ``Git hook`` by running: +Then, ensure that you install it as a ``Git hook`` by running: .. code-block:: bash @@ -174,8 +174,8 @@ Then, make sure you install it as a ``Git hook`` by running: Using ``pre-commit`` ~~~~~~~~~~~~~~~~~~~~ -One installed as described, ``pre-commit`` will automatically trigger every time -that you try to commit a change. If any of the hooks defined in `.pre-commit-config.yaml` +One installed as described, ``pre-commit`` automatically triggers every time +that you try to commit a change. If any hook defined in `.pre-commit-config.yaml` fails, you must fix the failing files, stage the new changes, and try to commit them again. @@ -190,10 +190,10 @@ the hooks fail. Tox --- -A tool you might consider using in your project is `tox`_. While this automation +You might consider using `tox`_ in your project. While this automation tool is similar to `Make`_, it supports testing of your package in a temporary virtual environment. Being able to test your package in isolation rather than in -"local" mode guarantees reproducible builds. +"local" mode guarantees reproducible builds. Configuration for `tox`_ is stored in a ``tox.ini`` file. The minimum configuration for a PyAnsys ``py-`` project should be: @@ -212,7 +212,7 @@ configuration for a PyAnsys ``py-`` project should be: This minimum configuration assumes that you have a ``requirements/`` directory that contains ``requirements_tests.txt`` and ``requirements_doc.txt``. In -addition, the ``style`` environment will execute ``pre-commit``, which guarantees +addition, the ``style`` environment must execute ``pre-commit``, which guarantees the usage of this tool in your project. Installing ``tox`` diff --git a/doc/source/coding-style/required-standard.rst b/doc/source/coding-style/required-standard.rst index 006496c5..97f35a80 100644 --- a/doc/source/coding-style/required-standard.rst +++ b/doc/source/coding-style/required-standard.rst @@ -1,7 +1,7 @@ -Required Standard -================= +Required Standards +================== -This section collects the required standard for any ``PyAnsys`` project. The +This section collects the required standards for any ``PyAnsys`` project. The individual configurations for the tools presented in :ref:`Code Style Tools` and :ref:`Doc Style Tools` are combined together. @@ -39,7 +39,7 @@ Required ``pyproject.toml`` Config Required ``.flake8`` Config --------------------------- -Also, the following ``.flake8`` file is required: +The following ``.flake8`` file is also required: .. code-block:: toml @@ -50,7 +50,7 @@ Also, the following ``.flake8`` file is required: Required ``pre-commit`` Config ------------------------------ -You can take advantage of :ref:`Pre-Commit`, and include a +You can take advantage of :ref:`Pre-Commit` by including a ``.pre-commit-config.yaml`` file like the following one in your project: @@ -89,7 +89,7 @@ You can take advantage of :ref:`Pre-Commit`, and include a GitHub CI/CD integration ------------------------ Finally, you can take advantage of :ref:`Unit Testing on GitHub via CI/CD` and -add create a ``style.yml`` workflow file in ``.github/workflows/``: +create a ``style.yml`` workflow file in ``.github/workflows/``: .. code-block:: yaml