Skip to content

Commit b3cd191

Browse files
lars-reimannhmgaudeckerMImmesberger
authored
Namespaces (#17)
Provide new high-level functions: - `concatenate_functions_tree` - `create_input_structure_tree` allowing for nested dicts as tree representations. The standard case is nested with `qualified_names`, which `"__".join()` the paths. Qualified names need to be used as function arguments in case a function from a different module is needed. --------- Co-authored-by: Hans-Martin von Gaudecker <[email protected]> Co-authored-by: Marvin Immesberger <[email protected]>
1 parent 86efbb7 commit b3cd191

18 files changed

+1321
-158
lines changed

.github/workflows/main.yml

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,53 @@
1+
---
12
name: main
23
on:
34
push:
4-
branches:
5-
- main
5+
branches: [main]
66
pull_request:
77
branches:
8-
- '*'
9-
8+
- '*'
109
# Automatically cancel a previous run.
1110
concurrency:
1211
group: ${{ github.head_ref || github.run_id }}
1312
cancel-in-progress: true
14-
1513
jobs:
16-
1714
run-tests:
18-
1915
name: Run tests for ${{ matrix.os }} on ${{ matrix.python-version }}
2016
runs-on: ${{ matrix.os }}
21-
2217
strategy:
2318
fail-fast: false
2419
matrix:
25-
os: ['ubuntu-latest', 'macos-latest', 'windows-latest']
20+
os: [ubuntu-latest, macos-latest, windows-latest]
2621
python-version: ['3.9', '3.10', '3.11']
27-
2822
steps:
2923
- uses: actions/checkout@v2
3024
- uses: conda-incubator/setup-miniconda@v2
3125
with:
3226
auto-update-conda: true
3327
python-version: ${{ matrix.python-version }}
34-
3528
- name: Install core dependencies.
3629
shell: bash -l {0}
3730
run: conda install -c conda-forge tox-conda
38-
3931
- name: Run pytest.
4032
shell: bash -l {0}
4133
run: tox -e pytest -- -m "not slow" --cov-report=xml --cov=./
42-
4334
- name: Upload coverage report.
4435
if: runner.os == 'Linux' && matrix.python-version == '3.9'
4536
uses: codecov/codecov-action@v1
4637
with:
4738
token: ${{ secrets.CODECOV_TOKEN }}
48-
4939
docs:
50-
5140
name: Run documentation.
5241
runs-on: ubuntu-latest
53-
5442
steps:
5543
- uses: actions/checkout@v2
5644
- uses: conda-incubator/setup-miniconda@v2
5745
with:
5846
auto-update-conda: true
5947
python-version: 3.9
60-
6148
- name: Install core dependencies.
6249
shell: bash -l {0}
6350
run: conda install -c conda-forge tox-conda
64-
6551
- name: Build docs
6652
shell: bash -l {0}
6753
run: tox -e sphinx

.github/workflows/publish-to-pypi.yml

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,31 @@
1+
---
12
name: PyPI
2-
33
on: push
4-
54
jobs:
65
build-n-publish:
76
name: Build and publish Python 🐍 distributions 📦 to PyPI
87
runs-on: ubuntu-latest
98
steps:
10-
- uses: actions/checkout@master
11-
12-
- name: Set up Python 3.8
13-
uses: actions/setup-python@v1
14-
with:
15-
python-version: 3.8
16-
17-
- name: Install pypa/build
18-
run: >-
19-
python -m
20-
pip install
21-
build
22-
--user
23-
- name: Build a binary wheel and a source tarball
24-
run: >-
25-
python -m
26-
build
27-
--sdist
28-
--wheel
29-
--outdir dist/
30-
- name: Publish distribution 📦 to PyPI
31-
if: startsWith(github.ref, 'refs/tags')
32-
uses: pypa/gh-action-pypi-publish@master
33-
with:
34-
password: ${{ secrets.PYPI_API_TOKEN }}
9+
- uses: actions/checkout@master
10+
- name: Set up Python 3.8
11+
uses: actions/setup-python@v1
12+
with:
13+
python-version: 3.8
14+
- name: Install pypa/build
15+
run: >-
16+
python -m
17+
pip install
18+
build
19+
--user
20+
- name: Build a binary wheel and a source tarball
21+
run: >-
22+
python -m
23+
build
24+
--sdist
25+
--wheel
26+
--outdir dist/
27+
- name: Publish distribution 📦 to PyPI
28+
if: startsWith(github.ref, 'refs/tags')
29+
uses: pypa/gh-action-pypi-publish@master
30+
with:
31+
password: ${{ secrets.PYPI_API_TOKEN }}

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ ipython_config.py
8484
# VS Code
8585
.vscode
8686

87+
# IntelliJ
88+
.idea/
89+
8790
# pyenv
8891
.python-version
8992

.pre-commit-config.yaml

Lines changed: 23 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,51 @@
1+
---
12
repos:
23
- repo: meta
34
hooks:
45
- id: check-hooks-apply
56
- id: check-useless-excludes
6-
# - id: identity # Prints all files passed to pre-commits. Debugging.
7+
# - id: identity # Prints all files passed to pre-commits. Debugging.
8+
- repo: https://github.com/lyz-code/yamlfix
9+
rev: 1.17.0
10+
hooks:
11+
- id: yamlfix
712
- repo: https://github.com/pre-commit/pre-commit-hooks
8-
rev: v4.4.0
13+
rev: v5.0.0
914
hooks:
1015
- id: check-added-large-files
11-
args:
12-
- --maxkb=1300
16+
args: [--maxkb=10000]
1317
- id: check-case-conflict
1418
- id: check-merge-conflict
1519
- id: check-vcs-permalinks
20+
- id: check-yaml
1621
- id: check-toml
1722
- id: debug-statements
1823
- id: end-of-file-fixer
1924
- id: fix-byte-order-marker
20-
types:
21-
- text
25+
types: [text]
2226
- id: forbid-submodules
2327
- id: mixed-line-ending
24-
args:
25-
- --fix=lf
28+
args: [--fix=lf]
2629
description: Forces to replace line ending by the UNIX 'lf' character.
27-
- id: name-tests-test
28-
args:
29-
- --pytest-test-first
3030
- id: no-commit-to-branch
31-
args:
32-
- --branch
33-
- main
31+
args: [--branch, main]
3432
- id: trailing-whitespace
3533
- id: check-ast
3634
- id: check-docstring-first
37-
- repo: https://github.com/psf/black
38-
rev: 23.3.0
39-
hooks:
40-
- id: black
41-
language_version: python3.10
42-
- repo: https://github.com/asottile/blacken-docs
43-
rev: 1.13.0
35+
- repo: https://github.com/adrienverge/yamllint.git
36+
rev: v1.35.1
4437
hooks:
45-
- id: blacken-docs
46-
- repo: https://github.com/PyCQA/docformatter
47-
rev: v1.5.1
48-
hooks:
49-
- id: docformatter
50-
args:
51-
- --in-place
52-
- --wrap-summaries
53-
- '88'
54-
- --wrap-descriptions
55-
- '88'
56-
- --blank
57-
- repo: https://github.com/charliermarsh/ruff-pre-commit
58-
rev: v0.0.261
38+
- id: yamllint
39+
- repo: https://github.com/astral-sh/ruff-pre-commit
40+
rev: v0.7.2
5941
hooks:
42+
# Run the linter.
6043
- id: ruff
61-
- repo: https://github.com/nbQA-dev/nbQA
62-
rev: 1.7.0
63-
hooks:
64-
- id: nbqa-black
65-
- id: nbqa-ruff
66-
- repo: https://github.com/asottile/setup-cfg-fmt
67-
rev: v2.2.0
68-
hooks:
69-
- id: setup-cfg-fmt
70-
- repo: https://github.com/mgedmin/check-manifest
71-
rev: '0.49'
72-
hooks:
73-
- id: check-manifest
44+
types_or: [python, jupyter]
7445
args:
75-
- --no-build-isolation
76-
additional_dependencies:
77-
- setuptools-scm
78-
- toml
46+
- --fix
47+
# Run the formatter.
48+
- id: ruff-format
49+
types_or: [python, jupyter]
7950
ci:
8051
autoupdate_schedule: monthly

.readthedocs.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1+
---
12
version: 2
2-
33
build:
44
image: latest
5-
65
python:
76
version: 3.8
8-
97
conda:
108
environment: docs/rtd_environment.yml

codecov.yml

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
1+
---
12
codecov:
23
notify:
3-
require_ci_to_pass: yes
4-
4+
require_ci_to_pass: true
55
coverage:
66
precision: 2
77
round: down
8-
range: "50...100"
8+
range: 50...100
99
status:
1010
patch:
1111
default:
1212
target: 80%
1313
project:
1414
default:
1515
target: 80%
16-
17-
ignore:
18-
- ".tox/**/*"
19-
- "setup.py"
16+
ignore: [.tox/**/*, setup.py]

docs/rtd_environment.yml

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
channels:
2-
- conda-forge
3-
- nodefaults
4-
1+
---
2+
channels: [conda-forge, nodefaults]
53
dependencies:
64
- python=3.9
75
- pip
@@ -17,6 +15,4 @@ dependencies:
1715
- sphinx-copybutton
1816
- sphinx-panels
1917
- pydata-sphinx-theme>=0.3.0
20-
21-
- pip:
22-
- ../
18+
- pip: [../]

docs/source/examples.rst

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,91 @@ outputs. And we would like to have them as a dictionary. We can do this as follo
8383
{"h": 0.6, "f": 5, "g": 3.0}
8484
8585
86+
Functions from different namespaces
87+
-----------------------------------
88+
89+
In large projects, function names can become lengthy when they share the same namespace.
90+
Using dags, we can concatenate functions from different namespaces.
91+
92+
Suppose we define the following function in the module `linear_functions.py`:
93+
94+
.. code-block:: python
95+
96+
def f(x):
97+
return 0.5 * x
98+
99+
In another module, called `parabolic_functions.py`, we define two more functions. Note,
100+
that there is a function `f` in this module as well.
101+
102+
.. code-block:: python
103+
104+
def f(x):
105+
return x**2
106+
107+
def h(f, linear_functions__f):
108+
return (f + linear_functions__f) ** 2
109+
110+
The function `h` takes two inputs:
111+
- `f` from `parabolic_functions.py`, referenced directly as f within the current
112+
namespace.
113+
- `f` from `linear_functions.py`, referenced using its namespace with a double
114+
underscore separator (`linear_functions__f`).
115+
116+
Using `concatenate_functions_tree`, we are able to combine the functions from both
117+
modules.
118+
119+
First, we need to define the functions tree, which maps functions to their namespace.
120+
The functions tree can be nested to an arbitrary depth.
121+
122+
.. code-block:: python
123+
from linear_functions import f as linear_functions__f
124+
from parabolic_functions import f as parabolic_functions__f
125+
from parabolic_functions import h as parabolic_functions__h
126+
127+
# Define functions tree
128+
functions = {
129+
"linear_functions": {"f": linear_functions__f},
130+
"parabolic_functions": {
131+
"f": parabolic_functions__f,
132+
"h": parabolic_functions__h
133+
},
134+
}
135+
136+
Next, we define the input structure, which maps the parameters of the functions to their
137+
namespace. The input structure can also be created via the
138+
`create_input_structure_tree` function.
139+
140+
.. code-block:: python
141+
# Define input structure
142+
input_structure = {
143+
"linear_functions": {"x": None},
144+
"parabolic_functions": {"x": None},
145+
}
146+
147+
148+
Finally, we combine the functions using `concatenate_functions_tree`.
149+
150+
.. code-block:: python
151+
# Get combined function
152+
combined = concatenate_functions_tree(
153+
functions,
154+
input_structure=input_structure,
155+
targets={"parabolic_functions": {"h": None}},
156+
)
157+
158+
# Call combined function
159+
combined(inputs={
160+
"linear_functions": {"x": 2},
161+
"parabolic_functions": {"x": 1},
162+
})
163+
164+
.. code-block:: python
165+
166+
{"h": 4.0}
167+
168+
Importantly, dags does not allow for branches with trailing underscores in the
169+
definition of the functions tree.
170+
86171
Renaming the output of a function
87172
---------------------------------
88173

0 commit comments

Comments
 (0)