perfattr 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. perfattr-0.1.0/.gitignore +64 -0
  2. perfattr-0.1.0/LICENSE +21 -0
  3. perfattr-0.1.0/PKG-INFO +89 -0
  4. perfattr-0.1.0/README.md +61 -0
  5. perfattr-0.1.0/docs/performance.md +60 -0
  6. perfattr-0.1.0/docs/specification.md +561 -0
  7. perfattr-0.1.0/pyproject.toml +87 -0
  8. perfattr-0.1.0/scripts/benchmark_core.py +245 -0
  9. perfattr-0.1.0/src/perfattr/__init__.py +16 -0
  10. perfattr-0.1.0/src/perfattr/_linking.py +37 -0
  11. perfattr-0.1.0/src/perfattr/_schemas.py +104 -0
  12. perfattr-0.1.0/src/perfattr/attribution.py +945 -0
  13. perfattr-0.1.0/src/perfattr/py.typed +1 -0
  14. perfattr-0.1.0/tests/fixtures/README.md +29 -0
  15. perfattr-0.1.0/tests/fixtures/linking_boundaries/benchmark.csv +5 -0
  16. perfattr-0.1.0/tests/fixtures/linking_boundaries/expected_horizon.csv +3 -0
  17. perfattr-0.1.0/tests/fixtures/linking_boundaries/expected_period_detail.csv +5 -0
  18. perfattr-0.1.0/tests/fixtures/linking_boundaries/portfolio.csv +5 -0
  19. perfattr-0.1.0/tests/fixtures/multi_period_linking/benchmark.csv +5 -0
  20. perfattr-0.1.0/tests/fixtures/multi_period_linking/expected_horizon.csv +3 -0
  21. perfattr-0.1.0/tests/fixtures/multi_period_linking/expected_period_detail.csv +5 -0
  22. perfattr-0.1.0/tests/fixtures/multi_period_linking/portfolio.csv +5 -0
  23. perfattr-0.1.0/tests/fixtures/single_period_authoritative/benchmark.csv +2 -0
  24. perfattr-0.1.0/tests/fixtures/single_period_authoritative/expected_period_detail.csv +3 -0
  25. perfattr-0.1.0/tests/fixtures/single_period_authoritative/portfolio.csv +3 -0
  26. perfattr-0.1.0/tests/fixtures/single_period_derived/benchmark.csv +4 -0
  27. perfattr-0.1.0/tests/fixtures/single_period_derived/expected_period_detail.csv +6 -0
  28. perfattr-0.1.0/tests/fixtures/single_period_derived/portfolio.csv +5 -0
  29. perfattr-0.1.0/tests/test_attribution.py +418 -0
  30. perfattr-0.1.0/tests/test_fixtures.py +290 -0
  31. perfattr-0.1.0/tests/test_package.py +8 -0
@@ -0,0 +1,64 @@
1
+ # Generated project outputs
2
+ /.cache/
3
+
4
+ # Python-generated files
5
+ __pycache__/
6
+ *.py[cod]
7
+ *$py.class
8
+ *.so
9
+
10
+ # Distribution / packaging
11
+ /build/
12
+ /dist/
13
+ *.egg-info/
14
+ .eggs/
15
+
16
+ # Installer remnants
17
+ pip-delete-this-directory.txt
18
+
19
+ # Tests, type checking, and profiling
20
+ /.pytest_cache/
21
+ /.mypy_cache/
22
+ .dmypy.json
23
+ dmypy.json
24
+ htmlcov/
25
+ .coverage
26
+ .coverage.*
27
+ *.cover
28
+ *.py,cover
29
+ coverage.xml
30
+ *.prof
31
+ .profraw
32
+
33
+ # pyenv
34
+ .python-version
35
+
36
+ # Local environment
37
+ .env
38
+ .env.*
39
+ !.env.example
40
+ /.venv/
41
+
42
+ # IDEs and text editors
43
+ .vscode/
44
+ .idea/
45
+ *.swp
46
+ *.swo
47
+ *.swn
48
+
49
+ # macOS
50
+ .DS_Store
51
+ .AppleDouble
52
+ .LSOverride
53
+
54
+ # Windows
55
+ Thumbs.db
56
+ ehthumbs.db
57
+ Desktop.ini
58
+ $RECYCLE.BIN/
59
+
60
+ # Linux
61
+ .Trash-*
62
+
63
+ # Temporary files
64
+ .~lock.*#
perfattr-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 John Reynolds
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,89 @@
1
+ Metadata-Version: 2.5
2
+ Name: perfattr
3
+ Version: 0.1.0
4
+ Summary: Auditable portfolio performance attribution using pandas and NumPy.
5
+ Project-URL: Repository, https://github.com/JohnDReynolds/perfattr
6
+ Author: John Reynolds
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Keywords: attribution,brinson,finance,performance,portfolio
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Financial and Insurance Industry
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Typing :: Typed
18
+ Requires-Python: >=3.11
19
+ Requires-Dist: numpy>=1.26
20
+ Requires-Dist: pandas>=2.2
21
+ Provides-Extra: dev
22
+ Requires-Dist: build>=1.2; extra == 'dev'
23
+ Requires-Dist: pylint>=4.0; extra == 'dev'
24
+ Requires-Dist: pyright>=1.1.409; extra == 'dev'
25
+ Requires-Dist: pytest>=8.0; extra == 'dev'
26
+ Requires-Dist: twine>=6.0; extra == 'dev'
27
+ Description-Content-Type: text/markdown
28
+
29
+ # perfattr
30
+
31
+ `perfattr` is a small, auditable portfolio performance-attribution calculation
32
+ library built with pandas and NumPy.
33
+
34
+ The 0.1.0 release provides a reusable Brinson-Fachler calculation core for
35
+ prepared reporting-period data. Source loading, portfolio accounting, vendor schemas,
36
+ calendar logic, and presentation are intentionally outside the package boundary.
37
+
38
+ The calculation core accepts one or more prepared reporting periods and provides
39
+ input validation, universe equalization, Brinson-Fachler allocation and selection,
40
+ logarithmic contribution linking, Carino active-effect linking, cumulative and
41
+ full-horizon results, and financial reconciliation. The governing roadmap is available
42
+ in [`_extras/perfattr_roadmap.md`](_extras/perfattr_roadmap.md), and the complete
43
+ portable calculation contract is defined in
44
+ [`docs/specification.md`](docs/specification.md).
45
+
46
+ ```python
47
+ from perfattr import calculate_attribution
48
+
49
+ result = calculate_attribution(portfolio, benchmark)
50
+ print(result.period_detail)
51
+ ```
52
+
53
+ ## Development
54
+
55
+ Create and activate a virtual environment:
56
+
57
+ ```bash
58
+ python3 -m venv .venv
59
+ source .venv/bin/activate
60
+ ```
61
+
62
+ Install the package and development dependencies:
63
+
64
+ ```bash
65
+ python -m pip install --editable ".[dev]"
66
+ ```
67
+
68
+ Run the initial checks:
69
+
70
+ ```bash
71
+ python -m pytest
72
+ python -m pylint src/perfattr tests scripts
73
+ python -m pyright
74
+ ```
75
+
76
+ Run the four roadmap performance workloads:
77
+
78
+ ```bash
79
+ python scripts/benchmark_core.py --samples 5
80
+ python scripts/benchmark_core.py --samples 5 --input-form authoritative
81
+ ```
82
+
83
+ Add `--workload monthly_121260 --profile` to inspect one workload's cumulative
84
+ call profile. The benchmark methodology and initial observations are recorded in
85
+ [`docs/performance.md`](docs/performance.md).
86
+
87
+ ## License
88
+
89
+ `perfattr` is distributed under the MIT License.
@@ -0,0 +1,61 @@
1
+ # perfattr
2
+
3
+ `perfattr` is a small, auditable portfolio performance-attribution calculation
4
+ library built with pandas and NumPy.
5
+
6
+ The 0.1.0 release provides a reusable Brinson-Fachler calculation core for
7
+ prepared reporting-period data. Source loading, portfolio accounting, vendor schemas,
8
+ calendar logic, and presentation are intentionally outside the package boundary.
9
+
10
+ The calculation core accepts one or more prepared reporting periods and provides
11
+ input validation, universe equalization, Brinson-Fachler allocation and selection,
12
+ logarithmic contribution linking, Carino active-effect linking, cumulative and
13
+ full-horizon results, and financial reconciliation. The governing roadmap is available
14
+ in [`_extras/perfattr_roadmap.md`](_extras/perfattr_roadmap.md), and the complete
15
+ portable calculation contract is defined in
16
+ [`docs/specification.md`](docs/specification.md).
17
+
18
+ ```python
19
+ from perfattr import calculate_attribution
20
+
21
+ result = calculate_attribution(portfolio, benchmark)
22
+ print(result.period_detail)
23
+ ```
24
+
25
+ ## Development
26
+
27
+ Create and activate a virtual environment:
28
+
29
+ ```bash
30
+ python3 -m venv .venv
31
+ source .venv/bin/activate
32
+ ```
33
+
34
+ Install the package and development dependencies:
35
+
36
+ ```bash
37
+ python -m pip install --editable ".[dev]"
38
+ ```
39
+
40
+ Run the initial checks:
41
+
42
+ ```bash
43
+ python -m pytest
44
+ python -m pylint src/perfattr tests scripts
45
+ python -m pyright
46
+ ```
47
+
48
+ Run the four roadmap performance workloads:
49
+
50
+ ```bash
51
+ python scripts/benchmark_core.py --samples 5
52
+ python scripts/benchmark_core.py --samples 5 --input-form authoritative
53
+ ```
54
+
55
+ Add `--workload monthly_121260 --profile` to inspect one workload's cumulative
56
+ call profile. The benchmark methodology and initial observations are recorded in
57
+ [`docs/performance.md`](docs/performance.md).
58
+
59
+ ## License
60
+
61
+ `perfattr` is distributed under the MIT License.
@@ -0,0 +1,60 @@
1
+ # Performance observations
2
+
3
+ This document records repeatable observations rather than release thresholds. Run the
4
+ benchmark again on the target environment before drawing conclusions from the absolute
5
+ times.
6
+
7
+ ## Method
8
+
9
+ [`scripts/benchmark_core.py`](../scripts/benchmark_core.py) builds deterministic,
10
+ prepared inputs before measurement, warms the public API once, and reports the median
11
+ of the requested elapsed-time samples. Peak memory is the incremental peak of
12
+ Python-tracked allocations while `calculate_attribution` runs; prepared input memory
13
+ is reported separately.
14
+
15
+ The four workloads correspond to the roadmap shapes:
16
+
17
+ - `normal`: 6,063 rows per side across 60 monthly periods;
18
+ - `selected_10x`: 60,630 rows per side across 60 monthly periods;
19
+ - `monthly_121260`: 121,260 rows per side across 120 monthly periods; and
20
+ - `history_25y`: 30,300 rows per side across 300 monthly periods.
21
+
22
+ The default `derived` form supplies weights and returns. The `authoritative` form also
23
+ supplies contribution, matching the accounting-integrated contract.
24
+
25
+ ## Initial standalone baseline
26
+
27
+ These observations were collected on September 3, 2026, on an Apple arm64 machine
28
+ using Python 3.11.9, pandas 3.0.5, and NumPy 2.4.6. Each elapsed result is the median of
29
+ five samples.
30
+
31
+ | Workload | Input form | Median elapsed | Prepared inputs | Peak traced allocation |
32
+ | --- | --- | ---: | ---: | ---: |
33
+ | `normal` | derived | 0.0270 s | 2.0 MiB | 4.6 MiB |
34
+ | `selected_10x` | derived | 0.0971 s | 20.4 MiB | 44.6 MiB |
35
+ | `monthly_121260` | derived | 0.1723 s | 40.7 MiB | 89.0 MiB |
36
+ | `history_25y` | derived | 0.0576 s | 10.2 MiB | 22.4 MiB |
37
+ | `normal` | authoritative | 0.0275 s | 2.1 MiB | 4.6 MiB |
38
+ | `selected_10x` | authoritative | 0.0969 s | 21.3 MiB | 44.6 MiB |
39
+ | `monthly_121260` | authoritative | 0.1718 s | 42.6 MiB | 89.1 MiB |
40
+ | `history_25y` | authoritative | 0.0575 s | 10.6 MiB | 22.4 MiB |
41
+
42
+ Profiling the largest workload placed most core time in required input validation and
43
+ normalization. The absolute time was already modest, so no core refactor or additional
44
+ dependency was justified.
45
+
46
+ ## `ppar` adapter observation
47
+
48
+ An isolated 121,260-row-per-side adapter profile used Python 3.12.1, pandas 3.0.0,
49
+ NumPy 2.4.2, and Polars 1.38.0. It identified per-value Python-list materialization at
50
+ the pandas/Polars boundary as the dominant non-core cost. Passing existing columnar
51
+ NumPy arrays in both directions reduced the median of five samples from approximately
52
+ 0.52 seconds to 0.23 seconds and reduced peak traced allocation from 142.9 MiB to
53
+ 113.1 MiB. The completed differential suite established migration parity; the
54
+ permanent 500x integration gate remains the authority for workflow performance.
55
+
56
+ After the change, the permanent `ppar` 500x integration command passed all scenarios.
57
+ The large-source workflow took 1.41 seconds at both 12,126 and 6,063,000 source rows;
58
+ the selected-input workflow grew from 0.23 to 0.47 seconds at 10x rows; and the
59
+ long-history workflow grew from 1.28 to 1.85 seconds at 5x history. These timings are
60
+ observations, not thresholds.