Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
No results found
Show changes
Commits on Source (4)
__pycache__
.ipynb_checkpoints
.coverage*
coverage.xml
*.pyc
*.vti
/build
......
......@@ -203,7 +203,6 @@ minimal-sympy-master:
script:
- python -m pip install --upgrade git+https://github.com/sympy/sympy.git
- python quicktest.py
allow_failure: true
tags:
- docker
- cuda
......@@ -255,30 +254,25 @@ pycodegen-integration:
# -------------------- Code Quality ---------------------------------------------------------------------
flake8-lint:
.qa-base:
stage: "Code Quality"
image: i10git.cs.fau.de:5005/pycodegen/pycodegen/nox:alpine
needs: []
except:
variables:
- $ENABLE_NIGHTLY_BUILDS
image: i10git.cs.fau.de:5005/pycodegen/pycodegen/full
script:
- flake8 src/pystencils
tags:
- docker
mypy-typecheck:
stage: "Code Quality"
except:
variables:
- $ENABLE_NIGHTLY_BUILDS
image: i10git.cs.fau.de:5005/pycodegen/pycodegen/full
before_script:
- pip install -e .[tests]
lint:
extends: .qa-base
script:
- mypy src/pystencils
tags:
- docker
- nox --session lint
typecheck:
extends: .qa-base
script:
- nox --session typecheck
# -------------------- Unit Tests ---------------------------------------------------------------------
......@@ -286,18 +280,12 @@ mypy-typecheck:
tests-and-coverage:
stage: "Unit Tests"
needs: []
image: i10git.cs.fau.de:5005/pycodegen/pycodegen/full:cupy12.3
before_script:
- pip install -e .[tests]
image: i10git.cs.fau.de:5005/pycodegen/pycodegen/nox:ubuntu24.04-cuda12.6
script:
- env
- pip list
- export NUM_CORES=$(nproc --all)
- mkdir -p ~/.config/matplotlib
- echo "backend:template" > ~/.config/matplotlib/matplotlibrc
- mkdir public
- pytest -v -n $NUM_CORES --cov-report html --cov-report xml --cov-report term --cov=. -m "not longrun" --html test-report/index.html --junitxml=report.xml
- python -m coverage xml
- nox --session "testsuite(cupy12)"
tags:
- docker
- cuda11
......@@ -318,14 +306,11 @@ tests-and-coverage:
build-documentation:
image: i10git.cs.fau.de:5005/pycodegen/pycodegen/full:cupy12.3
image: i10git.cs.fau.de:5005/pycodegen/pycodegen/nox:ubuntu24.04-cuda12.6
stage: docs
needs: []
before_script:
- pip install -e .[doc]
script:
- cd docs
- make html SPHINXOPTS="-W --keep-going"
- nox --session docs -- --fail-on-warnings
tags:
- docker
- cuda11
......@@ -335,7 +320,7 @@ build-documentation:
pages:
image: i10git.cs.fau.de:5005/pycodegen/pycodegen/full
image: alpine:latest
stage: deploy
needs: ["tests-and-coverage", "build-documentation"]
script:
......
# Development Workflow
This page contains instructions on how to get started with developing pystencils.
## Prepare the Git Repository
The pystencils Git repository is hosted at [i10git.cs.fau.de](https://i10git.cs.fau.de), the GitLab instance of the
[Chair for Systems Simulation](https://www.cs10.tf.fau.de/) at [FAU Erlangen-Nürnberg](https://fau.de).
In order to contribute code to pystencils, you will need to acquire an account there; to do so,
please follow the instructions on the GitLab landing page.
### Create a Fork
Only the core developers of pystencils have write-access to the primary repository.
To contribute, you will therefore have to create a fork of that repository
by navigating to the [repository page](https://i10git.cs.fau.de/pycodegen/pystencils)
and selecting *Fork* there.
In this fork, you may freely create branches and develop code, which may later be merged to a primary branch
via merge requests.
### Create a Local Clone
Once you have a fork of the repository, you can clone it to your local machine using the git command-line.
:::{note}
To clone via SSH, which is recommended, you will first have to [register an SSH key](https://docs.gitlab.com/ee/user/ssh.html).
:::
Open up a shell and navigate to a directory you want to work in.
Then, enter
```bash
git clone git@i10git.cs.fau.de:<your-username>/pystencils.git
```
to clone your fork of pystencils.
:::{note}
To keep up to date with the upstream repository, you can add it as a secondary remote to your clone:
```bash
git remote add upstream git@i10git.cs.fau.de:pycodegen/pystencils.git
```
You can point your clone's `master` branch at the upstream master like this:
```bash
git pull --set-upstream upstream master
```
:::
## Set Up the Python Environment
To develop pystencils, you will need at least the following software installed on your machine:
- Python 3.10 or later: Since pystencils minimal supported version is Python 3.10, we recommend that you work with Python 3.10 directly.
- An up-to-date C++ compiler, used by pystencils to JIT-compile generated code
- [Nox](https://nox.thea.codes/en/stable/), which we use for test automation.
Nox will be used extensively in the instructions on testing below.
- Optionally [CUDA](https://developer.nvidia.com/cuda-toolkit),
if you have an Nvidia or AMD GPU and plan to develop on pystencils' GPU capabilities
Once you have these, set up a [virtual environment](https://docs.python.org/3/library/venv.html) for development.
This ensures that your system's installation of Python is kept clean, and isolates your development environment
from outside influence.
Use the following commands to create a virtual environment at `.venv` and perform an editable install of pystencils into it:
```bash
python -m venv .venv
source .venv/bin/activate
export PIP_REQUIRE_VIRTUALENV=true
pip install -e .[dev]
```
:::{note}
Setting `PIP_REQUIRE_VIRTUALENV` ensures that pip refuses to install packages globally --
Consider setting this variable globally in your shell's configuration file.
:::
You are now ready to go! Create a new git branch to work on, open up an IDE, and start coding.
Make sure your IDE recognizes the virtual environment you created, though.
## Static Code Analysis
### PEP8 Code Style
We use [flake8](https://github.com/PyCQA/flake8/tree/main) to check our code for compliance with the
[PEP8](https://peps.python.org/pep-0008/) code style.
You can either run `flake8` directly, or through Nox, to analyze your code with respect to style errors:
::::{grid}
:::{grid-item}
```bash
nox -s lint
```
:::
:::{grid-item}
```bash
flake8 src/pystencils
```
:::
::::
### Static Type Checking
New code added to pystencils is required to carry type annotations,
and its types are checked using [mypy](https://mypy.readthedocs.io/en/stable/index.html#).
To discover type errors, run *mypy* either directly or via Nox:
::::{grid}
:::{grid-item}
```bash
nox -s typecheck
```
:::
:::{grid-item}
```bash
mypy src/pystencils
```
:::
::::
:::{note}
Type checking is currently restricted to the `codegen`, `jit`, `backend`, and `types` modules,
since most code in the remaining modules is significantly older and is not comprehensively
type-annotated. As more modules are updated with type annotations, this list will expand in the future.
If you think a new module is ready to be type-checked, add an exception clause for it in the `mypy.ini` file.
:::
## Running the Test Suite
Pystencils comes with an extensive and steadily growing suite of unit tests.
To run the testsuite, you may invoke a variant of the Nox `testsuite` session.
There are multiple different versions of the `testsuite` session, depending on whether you are testing with our
without CUDA, or which version of Python you wish to test with.
You can list the available sessions using `nox -l`.
Select one of the `testsuite` variants and run it via `nox -s "testsuite(<variant>)"`, e.g.
```
nox -s "testsuite(cpu)"
```
for the CPU-only suite.
During the testsuite run, coverage information is collected and displayed using [coverage.py](https://coverage.readthedocs.io/en/7.6.10/).
You can display a detailed overview of code coverage by opening the generated `htmlcov/index.html` page.
## Building the Documentation
The pystencils documentation pages are written in MyST Markdown and ReStructuredText,
located at the `docs` folder, and built using Sphinx.
To build the documentation pages of pystencils, simply run the `docs` Nox session:
```bash
nox -s docs
```
This will emit the generated HTML pages to `docs/build/html`.
The `docs` session permits two parameters to customize its execution:
- `--clean`: Clean the page generator's output before building
- `--fail-on-warnings`: Have the build fail (finish with a nonzero exit code) if Sphinx emits any warnings.
You must pass any of these to the session command *after a pair of dashes* (`--`); e.g.:
```bash
nox -s docs -- --clean
```
# Contributor Guide
Welcome to the Contributor's Guide to pystencils!
If you are interested in contributing to the development of pystencils, this is the place to start.
Pystencils is an open-source package licensed under the [AGPL v3](https://www.gnu.org/licenses/agpl-3.0.en.html).
As such, the act of contributing to pystencils by submitting a merge request is taken as agreement to the terms of the licence.
:::{toctree}
:maxdepth: 2
dev-workflow
:::
......@@ -95,8 +95,9 @@ Topics
.. toctree::
:maxdepth: 1
:caption: Advanced
:caption: Topics
contributing/index
migration
backend/index
......
......@@ -11,6 +11,12 @@ ignore_errors = False
[mypy-pystencils.types.*]
ignore_errors = False
[mypy-pystencils.codegen.*]
ignore_errors = False
[mypy-pystencils.jit.*]
ignore_errors = False
[mypy-setuptools.*]
ignore_missing_imports=true
......@@ -22,3 +28,6 @@ ignore_missing_imports=true
[mypy-cupy.*]
ignore_missing_imports=true
[mypy-cpuinfo.*]
ignore_missing_imports=true
from __future__ import annotations
from typing import Sequence
import os
import nox
import subprocess
import re
nox.options.sessions = ["lint", "typecheck", "testsuite"]
def get_cuda_version(session: nox.Session) -> None | tuple[int, ...]:
query_args = ["nvcc", "--version"]
try:
query_result = subprocess.run(query_args, capture_output=True)
except FileNotFoundError:
return None
matches = re.findall(r"release \d+\.\d+", str(query_result.stdout))
if matches:
match = matches[0]
version_string = match.split()[-1]
try:
return tuple(int(v) for v in version_string.split("."))
except ValueError:
pass
session.warn("nvcc was found, but I am unable to determine the CUDA version.")
return None
def install_cupy(
session: nox.Session, cupy_version: str, skip_if_no_cuda: bool = False
):
if cupy_version is not None:
cuda_version = get_cuda_version(session)
if cuda_version is None or cuda_version[0] not in (11, 12):
if skip_if_no_cuda:
session.skip(
"No compatible installation of CUDA found - Need either CUDA 11 or 12"
)
else:
session.warn(
"Running without cupy: no compatbile installation of CUDA found. Need either CUDA 11 or 12."
)
return
cuda_major = cuda_version[0]
cupy_package = f"cupy-cuda{cuda_major}x=={cupy_version}"
session.install(cupy_package)
def check_external_doc_dependencies(session: nox.Session):
dot_args = ["dot", "--version"]
try:
_ = subprocess.run(dot_args, capture_output=True)
except FileNotFoundError:
session.error(
"Unable to build documentation: "
"Command `dot` from the `graphviz` package (https://www.graphviz.org/) is not available"
)
def editable_install(session: nox.Session, opts: Sequence[str] = ()):
if opts:
opts_str = "[" + ",".join(opts) + "]"
else:
opts_str = ""
session.install("-e", f".{opts_str}")
@nox.session(python="3.10", tags=["qa", "code-quality"])
def lint(session: nox.Session):
"""Lint code using flake8"""
session.install("flake8")
session.run("flake8", "src/pystencils")
@nox.session(python="3.10", tags=["qa", "code-quality"])
def typecheck(session: nox.Session):
"""Run MyPy for static type checking"""
editable_install(session)
session.install("mypy")
session.run("mypy", "src/pystencils")
@nox.parametrize("cupy_version", [None, "12", "13"], ids=["cpu", "cupy12", "cupy13"])
@nox.session(python="3.10", tags=["test"])
def testsuite(session: nox.Session, cupy_version: str | None):
if cupy_version is not None:
install_cupy(session, cupy_version, skip_if_no_cuda=True)
editable_install(session, ["alltrafos", "use_cython", "interactive", "testsuite"])
num_cores = os.cpu_count()
session.run(
"pytest",
"-v",
"-n",
str(num_cores),
"--cov-report=term",
"--cov=.",
"-m",
"not longrun",
"--html",
"test-report/index.html",
"--junitxml=report.xml",
)
session.run("coverage", "html")
session.run("coverage", "xml")
@nox.session(python=["3.10"], tags=["docs"])
def docs(session: nox.Session):
"""Build the documentation pages"""
check_external_doc_dependencies(session)
install_cupy(session, "12.3")
editable_install(session, ["doc"])
env = {}
session_args = session.posargs
if "--fail-on-warnings" in session_args:
env["SPHINXOPTS"] = "-W --keep-going"
session.chdir("docs")
if "--clean" in session_args:
session.run("make", "clean", external=True)
session.run("make", "html", external=True, env=env)
......@@ -44,6 +44,11 @@ interactive = [
use_cython = [
'Cython'
]
dev = [
"flake8",
"mypy",
"black",
]
doc = [
'sphinx',
'pydata-sphinx-theme==0.15.4',
......@@ -52,9 +57,12 @@ doc = [
'sphinx_autodoc_typehints',
'pandoc',
'sphinx_design',
'myst-nb'
'myst-nb',
'matplotlib',
'ipywidgets',
'graphviz',
]
tests = [
testsuite = [
'pytest',
'pytest-cov',
'pytest-html',
......@@ -68,6 +76,7 @@ tests = [
'matplotlib',
'py-cpuinfo',
'randomgen>=1.18',
'scipy'
]
[build-system]
......
......@@ -23,6 +23,7 @@ filterwarnings =
ignore:Using or importing the ABCs from 'collections' instead of from 'collections.abc':DeprecationWarning
ignore:Animation was deleted without rendering anything:UserWarning
# Coverage Configuration
[run]
branch = True
source = src/pystencils
......@@ -31,6 +32,7 @@ source = src/pystencils
omit = doc/*
tests/*
setup.py
noxfile.py
quicktest.py
conftest.py
versioneer.py
......
......@@ -126,7 +126,7 @@ class KernelCreationContext:
symb.apply_dtype(dtype)
return symb
def get_new_symbol(self, name: str, dtype: PsType | None = None) -> PsSymbol:
"""Always create a new symbol, deduplicating its name if another symbol with the same name already exists."""
......@@ -173,15 +173,11 @@ class KernelCreationContext:
) -> PsSymbol:
"""Canonically duplicates the given symbol.
A new symbol with the new name ``symb.name + "__<counter>"`` and optionally a different data type
A new symbol with the new name ``symb.name + "__<counter>"`` and optionally a different data type
is created, added to the symbol table, and returned.
The ``counter`` reflects the number of previously created duplicates of this symbol.
"""
if (result := self._symbol_ctr_pattern.search(symb.name)) is not None:
span = result.span()
basename = symb.name[: span[0]]
else:
basename = symb.name
basename = self.basename(symb)
if new_dtype is None:
new_dtype = symb.dtype
......@@ -194,6 +190,14 @@ class KernelCreationContext:
return self.get_symbol(dup_name, new_dtype)
assert False, "unreachable code"
def basename(self, symb: PsSymbol) -> str:
"""Returns the original name a symbol had before duplication."""
if (result := self._symbol_ctr_pattern.search(symb.name)) is not None:
span = result.span()
return symb.name[: span[0]]
else:
return symb.name
@property
def symbols(self) -> Iterable[PsSymbol]:
"""Return an iterable of all symbols listed in the symbol table."""
......
......@@ -448,6 +448,7 @@ class CreateKernelConfig:
if cpu_openmp is not None:
_deprecated_option("cpu_openmp", "cpu_optim.openmp")
deprecated_omp: OpenMpConfig | bool
match cpu_openmp:
case True:
deprecated_omp = OpenMpConfig()
......
......@@ -116,6 +116,7 @@ class DefaultKernelCreationDriver:
self._target = self._cfg.get_target()
self._platform = self._get_platform()
self._intermediates: CodegenIntermediates | None
if retain_intermediates:
self._intermediates = CodegenIntermediates()
else:
......