Contributing to PySTRA#

PySTRA implements traditional structural reliability methods and practical tools for code calibration and structural assessment. Contributions should make those methods easier to understand, verify, and use. General UQ features need a specific structural reliability use case to fit the project.

This guide establishes the conventions for v2 onward. During the migration, target v2.0 for breaking changes and follow the migration plan. Existing code still contains legacy APIs: their presence is not a style precedent. Implement the agreed stage without introducing a second competing API. Changes intended for the stable line retain its compatibility requirements.

Start with the user and the numerical method#

For a new method or substantial API change, include a short usage example, the problem it solves, its assumptions, and a reference case. Put the proposed contract in the PR before expanding the implementation. Routine fixes can proceed directly with focused evidence; a separate design document is not required for every change.

Keep numerical changes, mechanical renaming, formatting, and file moves in separate commits wherever practical. Update the migration manifest/guide when an import, parameter, result schema, default, or supported extension hook changes. After 2.0, public API changes follow the documented deprecation and release policy.

Naming and public interfaces#

  • Use snake_case for functions, methods, parameters, attributes, and compound module names; CapWords for classes; UPPER_SNAKE_CASE for constants.

  • Capitalize every letter of an acronym inside a CapWords class name. PEP 8 (Descriptive: Naming Styles) states: “When using acronyms in CapWords, capitalize all the letters of the acronym. Thus HTTPServerError is better than HttpServerError.” This is a single rule applied uniformly, not a list of blessed exceptions: FORM, SORM, SystemFORM, FBCProcess, DDO, DDOCriterion, LQI, SWTP, PCESurrogate, PCKrigingSurrogate, FBRLearning.

  • Name extreme-value distributions by family, not by type numeral: Gumbel, GumbelMin, Frechet, Weibull, GEV, GEVMin. The bare family name is the conventional flavour (maxima for Gumbel and Fréchet, minima for Weibull) and the opposite flavour takes a Min or Max suffix. Use ASCII in identifiers (Frechet) and give the Type I/II/III names in docstrings so users can find them.

  • ScipyDist keeps its existing name and is not to be “corrected”. GEVmax is kept as a permanent alias for GEV — the one deliberate alias in the 2.0 API.

  • Functions, methods, variables, and modules stay lowercase/snake_case, including their acronyms — PEP 8’s rule governs CapWords only, so run_form and pc_kriging.py are correct as they stand.

  • Prefer std, start_point, limit_state, model, options, n_samples, max_iterations, failure_probability, and reference_period. Use analyze in Python identifiers. Keep established pdf, cdf, ppf, beta, and alpha.

  • Name quantities by meaning. Do not use pseudo-Hungarian container/type prefixes such as dict_, list_, or arr_, or compressed forms such as dfXstarcal. This applies to parameters, attributes, private helpers, and local variables throughout the codebase, not only public APIs. Use nominal_values, design_points, or reliability_results rather than dict_nom, dfXstar, or list_form_obj. Replace cryptic abbreviations with meaningful names; deleting the prefix alone is not sufficient. Express container types through type annotations. Conventional df or a readable name such as factors_df is acceptable for a local DataFrame in a short pandas operation when it aids clarity. Prefer semantic names for parameters, persistent attributes, and returned results. Judge meaning rather than banning words: list_cases() describes an operation, and cut_sets describes a reliability concept. These are different from naming a variable list_cases merely because its container happens to be a Python list.

  • Mathematical local names such as x, u, and rho are appropriate near an equation. Preserve user-provided variable names and external API spellings; a limit-state argument R can remain R when it names the model variable.

  • Use properties for cheap data access and verbs for operations. Prefer explicit coordinates to boolean switches such as getDesignPoint(False).

  • Make configuration keyword-only, validate it, and reject unknown settings. Avoid booleans or numeric flags that silently change a parameter’s meaning.

  • Use explicit imports and deliberate __all__ exports. Public signatures have type hints and NumPy-style docstrings covering shapes, units, defaults, assumptions, returns, and failure behavior. Mark internal helpers with _.

House style#

Use these conventions for documentation, docstrings, comments and examples:

  • Write PySTRA in prose and pystra in imports, paths and package commands. Preserve literal identifiers, distribution metadata, quotations and legal attribution, including the public exception name PystraError.

  • Use US English, including optimization, normalized, behavior and modeling. External names and API spellings remain unchanged.

  • Use sentence-case titles and headings, retaining proper names and acronyms. In authored RST, use = for the page title, - for sections, then ~ and ^ for deeper levels. Preserve heading depth and link destinations.

  • Lead task instructions with verbs and describe current behavior in the present tense. Prefer short explanatory paragraphs and plain language. Support accuracy and performance claims with evidence and limitations.

  • Use limit state and design point as nouns, and limit-state function and design-point search as modifiers. Prefer failure probability; probability of failure is also valid when it reads naturally.

  • Use standard normal space and independent standard normal coordinates. Define local u, x, and any correlated-normal z notation explicitly; preserve and explain the notation of reproduced sources.

  • In new equations, use \mathbf{x} and \mathbf{u} for Latin vectors, \boldsymbol{\alpha} for Greek vectors, p_f for failure probability and \beta for the normal-equivalent reliability index. Typography changes must preserve mathematical meaning, equation labels and source conventions.

  • State actual array shapes and define dimension names. Public points have shape (n_variables,); public sample batches have shape (n_samples, n_variables). Explicitly document private column kernels. State units and reference periods, retaining the source benchmark’s units. Put a space between a number and its engineering unit or percent symbol. Distinguish a random variable’s CoV from an estimator’s uncertainty.

  • Use NumPy docstring sections for substantive Parameters, Returns and Raises contracts. Put constructor arguments on the class and method-specific contracts on methods; concise summaries suffice for obvious properties and private helpers. A summary sentence is followed by a blank line before elaboration. Use raw strings for LaTeX and real source lines for lists.

  • Format identifiers as inline literals and use Sphinx roles for useful API links, :doc: for pages, :ref: for named sections and :eq: for equations. Use descriptive link labels, RST list-tables for comparisons, * for RST bullets and - for Markdown bullets. Number lists only for ordered actions.

  • End task pages and notebooks with **Continue:** and relevant links separated by ·. Keep the purposeful **Use this method:** theory and **Use it:** API labels. Notebooks also retain purpose, prerequisites, assumptions, interpreted results, captions and meaningful figure alternatives.

  • Begin library modules with a useful docstring, then standard-library, third-party and local imports in separate groups. Omit interpreter/encoding headers from library modules. Preserve optional imports and deliberate public re-exports; keep explicit __all__ and the aliases np and ra.

  • Public signatures have useful type annotations. Use modern built-in containers and unions, such as list[float] and Result | None. Keep annotation coverage and syntax conversion in dedicated commits, and check runtime resolution, forward references and generated documentation.

  • Use f-strings for interpolated messages. Validation messages identify the input and constraint, normally without terminal punctuation. Preserve exception classes, statuses, causes and existing message contracts.

  • Comments explain mathematics, invariants, provenance or non-obvious choices. Remove verified obsolete commented-out code. Preserve NumPy ownership, shape, allocation and evaluation-order semantics; style work is not a numerical refactor. Black remains the Python formatter.

  • Prefer behavior-named pytest functions, parametrization for shared invariants and precise expected exception types. Keep useful test classes, numerical reference values, seeds and tolerances.

Use RST for authored source pages; Markdown remains appropriate for notebooks and repository documents. docs/source/install.md is intentionally parsed as RST: do not rename or convert it as a style change. Preserve quoted reference titles, source-specific engineering notation and historical migration records.

Keep computation and state understandable#

Models describe a problem; algorithms execute; results record what happened; reporting presents those results. Constructors must not start an analysis. Use explicit inputs and returned results rather than a sequence of methods that populate attributes needed by later methods. Snapshot results so a later run cannot change an earlier result.

Prefer small functions for numerical operations and small data objects for specifications/results. Add a class when it owns a coherent responsibility. Use composition and narrow interfaces where substitution is actually needed; avoid deep inheritance trees, general registries, and speculative abstractions.

Keep arrays and explicit variable/case metadata in numerical kernels. DataFrame conversion and plotting belong at the boundary. Do not use mutable tables as hidden communication between solver stages. Return figures/axes without implicitly displaying them, and return summaries rather than printing during computation. Diagnostics can use logging or an explicit progress callback.

Do not mutate caller-owned models, mappings, arrays, or distributions while iterating candidate designs. Keep caches, evaluation counts, and random state local to the run, with documented invalidation and RNG ownership.

For code calibration, prioritize the normalized workflow: candidate factors, code designs, reliability evaluation, and comparison against targets. Keep probability models separate from factor sets. The specialized inverse workflow uses the separate solve_designs, derive_factors, select_factors, design_with_factors and verify_designs operations documented in the migration guide; do not force all code studies through it. Preserve governing-case information and numerical diagnostics. A convenience runner composes operations; it does not duplicate them.

Numerical contracts and evidence#

Document coordinate systems, Jacobian direction, variable ordering, failure event convention, and reference-period assumptions. Use the agreed 2.0 point and batch shapes at public boundaries; adapt existing kernels explicitly during migration. Never infer array orientation from a square shape.

Distinguish estimates, approximations, bounds, and diagnostics. State what event a bound applies to. Check the capabilities required by each algorithm; unsupported inputs or transformations must fail clearly. Nonconvergence, unattainable calibration targets, and sampling-budget termination must remain visible to callers. They must not become a zero failure probability or a previous run’s successful result.

Use local random generators and explicit seeds for reproducible examples. Specify the numerical environment and statistical tolerance when necessary. Prefer published or analytic reference cases and mathematical invariants over tests that merely repeat the implementation. For a bug, add a focused regression case; for a method, test its assumptions and meaningful failure modes as well as a successful example. Explain intentional changes to baseline values.

Preserve original references and attribution when extracting or reorganizing existing methods. Review code against the shared project conventions and numerical evidence, rather than a contributor’s personal style.

Local workflow and pull requests#

Create a feature branch from the current integration branch. Install in a virtual environment. Use Python 3.13 for the documentation/formatting tools; the runtime test matrix covers Python 3.12 and 3.13:

For a new conda environment, install Python and Pandoc first. Run the package commands from your checkout of v2.0 (or a feature branch based on it):

conda create -n pystra2.0 python=3.13 pandoc
conda activate pystra2.0
python -m pip install -e '.[test,docs,al]'
python -m pip install black==26.5.1
python -m pytest -q

Run Black on changed Python files and include formatting in the appropriate commit. Black remains the formatter during migration. Run python scripts/api_inventory.py --check-names --check-migration for naming, baseline API coverage, and current calibration signature checks. After changing the migration records or the top-level namespace, run python scripts/generate_signposts.py; the tests check that the signposts are current. Update the reviewed migration records alongside contract changes; historical naming maps are not the current calibration API. Remaining attribute/parameter cleanup and import enforcement remain later stages; existing legacy fields are not a precedent for new code. CI also executes every indexed tutorial using scripts/execute_notebooks.py.

From docs, run:

make html SPHINXOPTS="-W --keep-going"
python ../scripts/check_docs.py build/html
python -m sphinx -b doctest -W -D nbsphinx_execute=never source build/doctest

Sphinx executes new or edited notebooks and caches the rendered results. Changes to PySTRA source, notebook helper modules, the Python interpreter or installed dependency versions invalidate all notebook results. A first build therefore runs every tutorial. Use -E for an explicitly fresh build.

To render saved outputs after separately executing the tutorials, use make html SPHINXOPTS="-W --keep-going -D nbsphinx_execute=never". This explicit shortcut does not validate notebook execution.

When changing notebook code or APIs used by a notebook, execute the affected notebooks and inspect their outputs before building. From the repository root, for example:

python scripts/execute_notebooks.py ex_active_extensions --output-dir docs/source/notebooks

Omit the notebook name to execute all tutorials in the nested tutorial index, as CI does. Add each notebook to exactly one category page under docs/source/tutorials/; add ordinary links for other discovery routes. Provide pystra notebook metadata with dependencies (core or al) and support_files (helper filenames, or an empty list). Put related guide, API and theory links in the final Markdown cell. For each code cell producing figures, set metadata.pystra.figure_alts to a list of descriptive strings in image-output order. Add a visible Markdown caption after that cell so the explanation is also available when the notebook is opened in Jupyter. The local Sphinx extension uses those alternatives and creates runnable download bundles. New methods should include a short runnable example and theory/reference documentation. Keep optional external-solver or network-dependent examples identifiable with their required environment.

Tutorials use sentence-case titles, a short purpose and prerequisites, explicit problem assumptions, runnable code, and interpretation of the results. Use import pystra as ra, Black formatting, explicit seeds for stochastic examples and the shared plotting helpers for common reliability figures. Keep benchmark attribution and distinguish independent reference probabilities from method approximations. Install the project into the environment; do not add repository path-search boilerplate to notebooks.

PRs should state the concrete behavior change, API impact, numerical evidence, and relevant validation commands/results. Identify skipped checks and known limitations. Use the PR template as a review aid, applying only relevant items. Avoid unrelated formatting or dependency churn. Maintainers handle release version bumps; ordinary contributions should not bump the package version.

The migration plan defines the broader release matrix, benchmark comparisons, packaging checks, and documentation gates. Small documentation edits do not require rerunning the entire numerical suite.

License and method provenance#

PySTRA is GPL-3.0-or-later. Preserve copyright and licence notices when adapting code, and identify its source and changes. Cite the original papers and benchmark definitions; distinguish reproductions from variants and software comparisons. Do not imply endorsement by the cited authors or toolbox developers. Include independent reference calculations and explicit statistical tolerances for stochastic methods. Run optional active-learning checks with .[test,al].

Extension recipes#

The distribution recipe covers distribution construction and sensitivity hooks. The conventions above apply to all contributions.

The distribution-extension instructions are now collected in Adding a distribution.