Development Standards ===================== Contributing ------------ Here is a getting started guide to contributing. If you have any questions Micah and Travis are available to give input and answer your questions. Before contributing you should review the :ref:`scope` and design philosophy. .. _Versioning: Versioning ---------- Version information is stored in git tags, and retrieved using `setuptools scm `_. The version tag shall match the regular expression: ``v\d\.\d+\.\d+(a\d+|\.post\d+)?``. These tags will be applied by a maintainer during the release process, and cannot be applied by normal users. MontePy follows the `semantic versioning standard `_ and the `PyPA specification for version specifiers `_ to the best of our abilities. The version numbers can be read as ``..``. Here is a quick summary of release types used, that is not meant to be authoritative: * **Major release**: This is a release that break backwards compatibility. * **Minor release**: This is a release the adds a new feature. * **Patch release**: This is a bug-fix release only. * **Post release**: This is a release that doesn't change any code. This will add an extra ``\.post\d+`` to the end of the *previous* version. * **Alpha release**: This is a testing release. Generally this is preparing for a major release. Features are not locked at this point, and may change. This is signified by adding ``a\d+`` to the end of the *next* release. Design Philosophy ----------------- #. **Do Not Repeat Yourself (DRY)** #. If it's worth doing, it's worth doing well. #. Use abstraction and inheritance smartly. #. Use ``@property`` getters, and if needed setters. Setters must verify and clean user inputs. For the most part use :func:`~montepy.utilities.make_prop_val_node`, and :func:`~montepy.utilities.make_prop_pointer`. #. Fail early and politely. If there's something that might be bad: the user should get a helpful error as soon as the error is apparent. #. Test. test. test. The goal is to achieve 100% test coverage. Unit test first, then do integration testing. A new feature merge request will ideally have around a dozen new test cases. #. Do it right the first time. #. Document all functions. #. Expect everything to mutate at any time. #. Avoid relative imports when possible. Use top level ones instead: e.g., ``import montepy.cell.Cell``. #. Defer to vanilla python, and only use the standard library. Currently the only dependencies are `numpy `_ and `sly `_. There must be good justification for breaking from this convention and complicating things for the user. Style Guide ----------- #. Thou shall be `PEP 8 `_, and use `black `_. #. Spaces not tabs with 4 spaces for an indent. #. External imports before internal imports with a blank line in between. All imports are alphabetized. Naming Conventions ^^^^^^^^^^^^^^^^^^ #. Follow `PEP 8 naming conventions `_ e.g., #. ``lower_case_with_underscores`` for variables, methods, functions, and module names, etc. #. ``CapitalizedWords`` for class names * ``MCNP_ClassName`` is an exception. For all Other acronyms use: ``AcronymMoreWords``. Above all, prioritize legibility. #. ``UPER_CASE_WITH_UNDERSCORES`` for pseudo-constant variables #. ``_single_leading_underscore`` should be used for almost all internal attributes. #. ``__double_leading_underscore`` should be used for private internal attributes that should not be accessed by users or sub-classes. #. Variables should be nouns/noun-phrases #. Functions/methods should be verb/verb-phrases. #. Properties/attributes of classes should be nouns or ``is_adjective`` phrases. #. Collections should be a plural noun, and single instances should be singular. In loops there should be consistent names, e.g., ``for cell in cells:``. #. When appropriate names should mirror Python core libraries (e.g., :class:`~montepy.numbered_object_collection.NumberedObjectCollection` tries to mirror methods of ``dict``, ``list``, and ``set``). #. Within reason: avoid abbreviating words. Above all, prioritize legibility. #. For user facing functions and attributes, short names are best. (:func:`~montepy.surfaces.surface.Surface.surface_constants`, really should have been ``constants`` in hind-sight). Doc Strings ----------- All public (not ``_private``) classes and functions *must* have doc strings. Most ``_private`` classes and functions should still be documented for other developers. `NumPy's style guide is the standard `_ used for MontePy doc strings. Mandatory Elements ^^^^^^^^^^^^^^^^^^ #. One line descriptions. #. Type annotations in the function signature #. Description of all inputs. #. Description of return values (can be skipped for None). #. ``.. versionadded::``/ ``.. versionchanged::`` information for all new functions and classes. This information can be dropped with major releases. #. Example code for showing how to use objects that implement atypical ``__dunders__``, e.g., for ``__setitem__``, ``__iter__``, etc. #. `Type hints `_ on all new or modified functions. .. note:: Class ``__init__`` arguments are documented in the class docstrings and not in ``__init__``. .. note:: MontePy is in the process of migrating to type annotations, so not all functions will have them. Eventually MontePy may use a type enforcement engine that will use these hints. See :issue:`91` for more information. If you have issues with circular imports add the import: ``from __future__ import annotations``, this is from `PEP 563 `_. Highly Recommended. ^^^^^^^^^^^^^^^^^^^ #. A class level ``.. seealso:`` section referencing the user manuals. #. An examples code block. These should start with a section header: "Exampes". All code blocks should use `sphinx doctest `_. .. note:: MontePy docstrings features custom commands for linking to MCNP user manuals. These in general follow the ``:manual62:``, ``:manual63:``, ``:manual631:`` pattern. The MCNP 6.2.0 manual only supports linking to a specific page, and not a section, so the argument it takes is a page number: ``:manual62:`123```: becomes :manual62:`123`. The MCNP 6.3 manuals do support linking to section anchors. By default the command links to a ``\\subsubsection``, e.g., ``:manual63:`5.6.1``` becomes: :manual63:`5.6.1`. For other sections see: ``doc/source/conf.py``. Example ^^^^^^^ Here is the docstrings for :class:`~montepy.cell.Cell`. .. code-block:: python class Cell(Numbered_MCNP_Object): """Object to represent a single MCNP cell defined in CSG. Examples ^^^^^^^^ First the cell needs to be initialized. .. testcode:: python import montepy cell = montepy.Cell() Then a number can be set. By default the cell is voided: .. doctest:: python >>> cell.number = 5 >>> print(cell.material) None >>> mat = montepy.Material() >>> mat.number = 20 >>> mat.add_nuclide("1001.80c", 1.0) >>> cell.material = mat >>> # mass and atom density are different >>> cell.mass_density = 0.1 Cells can be inverted with ``~`` to make a geometry definition that is a compliment of that cell. .. testcode:: python complement = ~cell See Also -------- * :manual631sec:`5.2` * :manual63sec:`5.2` * :manual62:`55` .. versionchanged:: 1.0.0 Added number parameter Parameters ---------- input : Union[Input, str] The Input syntax object this will wrap and parse. number : int The number to set for this object. """ # snip def __init__( self, input: InitInput = None, number: int = None, ): Testing ------- Pytest is the official testing framework for MontePy. In the past it was unittest, and so the test suite is in a state of transition. Here are the principles for writing new tests: #. Do not write any new tests using ``unittest.TestCase``. #. Use ``assert`` and not ``self.assert...``, even if it's available. #. `parametrizing `_ is preferred over verbose tests. #. Use `fixtures `_. #. Use property based testing with `hypothesis `_, when it makes sense. This is generally for complicated functions that users use frequently, such as constructors. See this `tutorial for an introduction to property based testing `_. Test Organization ^^^^^^^^^^^^^^^^^ Tests are organized in the ``tests`` folder in the following way: #. Unit tests are in their own files for each class or a group of classes. #. Integration tests go in ``tests/test_*integration.py``. New integration files are welcome. #. Interface tests with other libraries, e.g., ``pickle`` go in ``tests/test_interface.py``. #. Test classes are preffered to organize tests by concepts. Each MontePy class should have its own test class. These should not subclass anything. Methods should accept ``_`` instead of ``self`` to note that class structure is purely organizational. Test Migration ^^^^^^^^^^^^^^ Currently the test suite does not conform to these standards fully. Help with making the migration to the new standards is appreciated. So don't think something is sacred about a test file that does not follow these conventions. Deprecation Guidelines ---------------------- Deprecation is an important part of the development life-cycle and a signal for users to help with migrations. Deprecations can occur either during a major release, or between major releases. The deprecation process is really part of a larger migration documentation process, and it provides a good last line of defense for users on how to migrate their code. .. note:: See :ref:`Versioning` section for more details on release types. Major Release Deprecations ^^^^^^^^^^^^^^^^^^^^^^^^^^ These are deprecations that occur during a major release. Generally these are deprecations necessary for the release to work, and must be at versions: ``Major.0.0``. For these deprecations the guidelines are: #. Try not to break too much. #. Warn with a ``DeprecationWarning`` if the deprecated function is still usable. Otherwise ``raise`` it as an ``Exception``. #. Add clear documentation on the fact it is deprecated and what the alternative is. #. Write a migration plan, preferably it should be part of the releases prior the major release. #. Only clear these ``DeprecationWarnings`` at the next major release. Mid-Major Release Deprecations ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ These are deprecations that are not during a major release. That is when the version matches: ``Major.Minor.0`` or ``Major.Minor.Patch``. The guidelines are: #. Do not break anything #. Warn with a ``DeprecationWarning`` (or ``PendingDeprecationWarning``, or ``FutureWarning`` as appropriate. `See the guide on warnings `_.) #. Add clear documentation on the fact it is deprecated and what the alternative is. #. Clear these warnings and documentation notations at the next major release.