cbpr-validate 1.0.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 (72) hide show
  1. cbpr_validate-1.0.0/.claude/settings.local.json +17 -0
  2. cbpr_validate-1.0.0/.claude/settings.local.json.tmp.31316.7bec411697e7 +18 -0
  3. cbpr_validate-1.0.0/.github/workflows/ci.yml +22 -0
  4. cbpr_validate-1.0.0/.github/workflows/release.yml +123 -0
  5. cbpr_validate-1.0.0/.gitignore +17 -0
  6. cbpr_validate-1.0.0/BUILD_PLAN.md +480 -0
  7. cbpr_validate-1.0.0/CLAUDE.md +107 -0
  8. cbpr_validate-1.0.0/PKG-INFO +209 -0
  9. cbpr_validate-1.0.0/README.md +190 -0
  10. cbpr_validate-1.0.0/pyproject.toml +61 -0
  11. cbpr_validate-1.0.0/src/cbpr_validate/__init__.py +18 -0
  12. cbpr_validate-1.0.0/src/cbpr_validate/api/__init__.py +0 -0
  13. cbpr_validate-1.0.0/src/cbpr_validate/api/main.py +120 -0
  14. cbpr_validate-1.0.0/src/cbpr_validate/cli.py +247 -0
  15. cbpr_validate-1.0.0/src/cbpr_validate/codesets/__init__.py +0 -0
  16. cbpr_validate-1.0.0/src/cbpr_validate/codesets/data/iso20022_codesets.json +276 -0
  17. cbpr_validate-1.0.0/src/cbpr_validate/codesets/loader.py +35 -0
  18. cbpr_validate-1.0.0/src/cbpr_validate/config.py +37 -0
  19. cbpr_validate-1.0.0/src/cbpr_validate/core.py +132 -0
  20. cbpr_validate-1.0.0/src/cbpr_validate/match/__init__.py +20 -0
  21. cbpr_validate-1.0.0/src/cbpr_validate/match/matcher.py +449 -0
  22. cbpr_validate-1.0.0/src/cbpr_validate/match/result.py +98 -0
  23. cbpr_validate-1.0.0/src/cbpr_validate/model/__init__.py +15 -0
  24. cbpr_validate-1.0.0/src/cbpr_validate/model/finding.py +21 -0
  25. cbpr_validate-1.0.0/src/cbpr_validate/model/payment.py +89 -0
  26. cbpr_validate-1.0.0/src/cbpr_validate/model/validation_result.py +21 -0
  27. cbpr_validate-1.0.0/src/cbpr_validate/parsers/__init__.py +0 -0
  28. cbpr_validate-1.0.0/src/cbpr_validate/parsers/_common.py +97 -0
  29. cbpr_validate-1.0.0/src/cbpr_validate/parsers/detect.py +35 -0
  30. cbpr_validate-1.0.0/src/cbpr_validate/parsers/pacs002.py +39 -0
  31. cbpr_validate-1.0.0/src/cbpr_validate/parsers/pacs004.py +52 -0
  32. cbpr_validate-1.0.0/src/cbpr_validate/parsers/pacs008.py +108 -0
  33. cbpr_validate-1.0.0/src/cbpr_validate/parsers/pacs009.py +82 -0
  34. cbpr_validate-1.0.0/src/cbpr_validate/parsers/parse.py +50 -0
  35. cbpr_validate-1.0.0/src/cbpr_validate/report/__init__.py +0 -0
  36. cbpr_validate-1.0.0/src/cbpr_validate/report/json_report.py +57 -0
  37. cbpr_validate-1.0.0/src/cbpr_validate/report/junit_report.py +89 -0
  38. cbpr_validate-1.0.0/src/cbpr_validate/report/text_report.py +103 -0
  39. cbpr_validate-1.0.0/src/cbpr_validate/rules/__init__.py +0 -0
  40. cbpr_validate-1.0.0/src/cbpr_validate/rules/address.py +99 -0
  41. cbpr_validate-1.0.0/src/cbpr_validate/rules/agents.py +142 -0
  42. cbpr_validate-1.0.0/src/cbpr_validate/rules/amounts.py +87 -0
  43. cbpr_validate-1.0.0/src/cbpr_validate/rules/codes.py +77 -0
  44. cbpr_validate-1.0.0/src/cbpr_validate/rules/registry.py +58 -0
  45. cbpr_validate-1.0.0/src/cbpr_validate/rules/returns.py +222 -0
  46. cbpr_validate-1.0.0/src/cbpr_validate/rules/structural.py +123 -0
  47. cbpr_validate-1.0.0/src/cbpr_validate/schema/__init__.py +0 -0
  48. cbpr_validate-1.0.0/src/cbpr_validate/schema/xsd.py +104 -0
  49. cbpr_validate-1.0.0/tests/__init__.py +6 -0
  50. cbpr_validate-1.0.0/tests/conftest.py +157 -0
  51. cbpr_validate-1.0.0/tests/fixtures/pacs008_valid_hybrid_ro.xml +99 -0
  52. cbpr_validate-1.0.0/tests/test_addr004_country_codes.py +95 -0
  53. cbpr_validate-1.0.0/tests/test_api.py +165 -0
  54. cbpr_validate-1.0.0/tests/test_bicfi_agents.py +107 -0
  55. cbpr_validate-1.0.0/tests/test_cli.py +294 -0
  56. cbpr_validate-1.0.0/tests/test_cod004_pacs002.py +36 -0
  57. cbpr_validate-1.0.0/tests/test_core.py +161 -0
  58. cbpr_validate-1.0.0/tests/test_golden_valid.py +78 -0
  59. cbpr_validate-1.0.0/tests/test_interface_parity.py +133 -0
  60. cbpr_validate-1.0.0/tests/test_match_correlation.py +442 -0
  61. cbpr_validate-1.0.0/tests/test_misc_coverage.py +40 -0
  62. cbpr_validate-1.0.0/tests/test_parsers.py +124 -0
  63. cbpr_validate-1.0.0/tests/test_parsers_edgecases.py +57 -0
  64. cbpr_validate-1.0.0/tests/test_parsers_phase4.py +145 -0
  65. cbpr_validate-1.0.0/tests/test_phase3_rules.py +111 -0
  66. cbpr_validate-1.0.0/tests/test_report.py +226 -0
  67. cbpr_validate-1.0.0/tests/test_rules_address.py +157 -0
  68. cbpr_validate-1.0.0/tests/test_rules_agents.py +116 -0
  69. cbpr_validate-1.0.0/tests/test_rules_returns.py +111 -0
  70. cbpr_validate-1.0.0/tests/test_schema_xsd.py +149 -0
  71. cbpr_validate-1.0.0/tests/test_smoke.py +18 -0
  72. cbpr_validate-1.0.0/tests/test_str003_mandatory_amount.py +123 -0
@@ -0,0 +1,17 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(.venv/Scripts/python.exe *)",
5
+ "Bash(python -c \"import json; d=json.load\\(open\\('src/cbpr_validate/codesets/data/iso20022_codesets.json'\\)\\); print\\('RETURN', sorted\\(d['ExternalReturnReason1Code']\\)\\); print\\('STATUS', sorted\\(d['ExternalStatusReason1Code']\\)\\); print\\('ISO3166', sorted\\(d['ISO3166-1-alpha-2']\\)\\)\")",
6
+ "Bash(python -m pytest -q)",
7
+ "Bash(python -m pip install -q pytest pytest-cov ruff mypy)",
8
+ "Bash(./.venv/Scripts/python.exe -m mypy src tests)",
9
+ "Bash(./.venv/Scripts/python.exe -m pytest -q)",
10
+ "Bash(./.venv/Scripts/python.exe -m ruff check src tests)",
11
+ "Bash(./.venv/Scripts/python.exe -)",
12
+ "Bash(./.venv/Scripts/cbpr-validate.exe check *)",
13
+ "Bash(echo \"exit=$?\")",
14
+ "Bash(./.venv/Scripts/cbpr-validate.exe match *)"
15
+ ]
16
+ }
17
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(.venv/Scripts/python.exe *)",
5
+ "Bash(python -c \"import json; d=json.load\\(open\\('src/cbpr_validate/codesets/data/iso20022_codesets.json'\\)\\); print\\('RETURN', sorted\\(d['ExternalReturnReason1Code']\\)\\); print\\('STATUS', sorted\\(d['ExternalStatusReason1Code']\\)\\); print\\('ISO3166', sorted\\(d['ISO3166-1-alpha-2']\\)\\)\")",
6
+ "Bash(python -m pytest -q)",
7
+ "Bash(python -m pip install -q pytest pytest-cov ruff mypy)",
8
+ "Bash(./.venv/Scripts/python.exe -m mypy src tests)",
9
+ "Bash(./.venv/Scripts/python.exe -m pytest -q)",
10
+ "Bash(./.venv/Scripts/python.exe -m ruff check src tests)",
11
+ "Bash(./.venv/Scripts/python.exe -)",
12
+ "Bash(./.venv/Scripts/cbpr-validate.exe check *)",
13
+ "Bash(echo \"exit=$?\")",
14
+ "Bash(./.venv/Scripts/cbpr-validate.exe match *)",
15
+ "Bash(./.venv/Scripts/python.exe -c ' *)"
16
+ ]
17
+ }
18
+ }
@@ -0,0 +1,22 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ matrix:
13
+ python-version: ["3.11", "3.12", "3.13"]
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: actions/setup-python@v5
17
+ with:
18
+ python-version: ${{ matrix.python-version }}
19
+ - run: pip install -e ".[dev]"
20
+ - run: ruff check .
21
+ - run: mypy src
22
+ - run: pytest
@@ -0,0 +1,123 @@
1
+ name: Release
2
+
3
+ # Publishes to PyPI via Trusted Publishing (OIDC) - no API token is stored in
4
+ # the repo or on anyone's laptop. PyPI verifies the workflow identity instead.
5
+ #
6
+ # push a v* tag -> publish to PyPI
7
+ # run manually -> publish to TestPyPI (or PyPI, if you pick it)
8
+ #
9
+ # A PyPI release is permanent: a version number can never be reused, even after
10
+ # deletion. So everything that can be checked is checked before the upload -
11
+ # the full test matrix, the tag/version agreement, and an install of the actual
12
+ # built wheel.
13
+
14
+ on:
15
+ push:
16
+ tags: ["v*"]
17
+ workflow_dispatch:
18
+ inputs:
19
+ target:
20
+ description: "Where to publish"
21
+ type: choice
22
+ options: [testpypi, pypi]
23
+ default: testpypi
24
+
25
+ permissions:
26
+ contents: read
27
+
28
+ jobs:
29
+ # Never publish a red build. Same matrix as CI, because "it passed on main"
30
+ # is not the same claim as "this tag passes".
31
+ test:
32
+ runs-on: ubuntu-latest
33
+ strategy:
34
+ matrix:
35
+ python-version: ["3.11", "3.12", "3.13"]
36
+ steps:
37
+ - uses: actions/checkout@v4
38
+ - uses: actions/setup-python@v5
39
+ with:
40
+ python-version: ${{ matrix.python-version }}
41
+ - run: pip install -e ".[dev]"
42
+ - run: ruff check .
43
+ - run: mypy src
44
+ - run: pytest
45
+
46
+ build:
47
+ needs: test
48
+ runs-on: ubuntu-latest
49
+ steps:
50
+ - uses: actions/checkout@v4
51
+ - uses: actions/setup-python@v5
52
+ with:
53
+ python-version: "3.11"
54
+
55
+ - name: Build sdist and wheel
56
+ run: |
57
+ pip install build twine
58
+ python -m build
59
+ twine check dist/*
60
+
61
+ # The version lives in the package and the tag is written by hand, so
62
+ # they can disagree. Catching that here costs seconds; catching it after
63
+ # an upload costs the version number.
64
+ - name: Tag must match the package version
65
+ if: startsWith(github.ref, 'refs/tags/v')
66
+ run: |
67
+ TAG="${GITHUB_REF_NAME#v}"
68
+ PKG=$(python -c "import re,pathlib; \
69
+ print(re.search(r'__version__ = \"([^\"]+)\"', \
70
+ pathlib.Path('src/cbpr_validate/__init__.py').read_text()).group(1))")
71
+ echo "tag=$TAG package=$PKG"
72
+ test "$TAG" = "$PKG" || { echo "::error::tag v$TAG != package $PKG"; exit 1; }
73
+
74
+ # A wheel can pass every test and still be broken on install - most often
75
+ # because a package-data file (here the ISO 20022 code-set snapshot) was
76
+ # left out of it. So exercise the artifact itself, not the source tree.
77
+ - name: Smoke-test the built wheel
78
+ run: |
79
+ python -m venv /tmp/smoke
80
+ /tmp/smoke/bin/pip install --quiet dist/*.whl
81
+ /tmp/smoke/bin/python -c "import cbpr_validate; print(cbpr_validate.__version__)"
82
+ /tmp/smoke/bin/python -c "from cbpr_validate.codesets.loader import get_codes; \
83
+ n=len(get_codes('ISO3166-1-alpha-2')); print('country codes:', n); assert n > 200"
84
+ /tmp/smoke/bin/cbpr-validate validate tests/fixtures/pacs008_valid_hybrid_ro.xml
85
+
86
+ - uses: actions/upload-artifact@v4
87
+ with:
88
+ name: dist
89
+ path: dist/
90
+
91
+ publish-testpypi:
92
+ needs: build
93
+ if: github.event_name == 'workflow_dispatch' && inputs.target == 'testpypi'
94
+ runs-on: ubuntu-latest
95
+ environment:
96
+ name: testpypi
97
+ url: https://test.pypi.org/p/cbpr-validate
98
+ permissions:
99
+ id-token: write # the OIDC token Trusted Publishing exchanges for an upload
100
+ steps:
101
+ - uses: actions/download-artifact@v4
102
+ with:
103
+ name: dist
104
+ path: dist/
105
+ - uses: pypa/gh-action-pypi-publish@release/v1
106
+ with:
107
+ repository-url: https://test.pypi.org/legacy/
108
+
109
+ publish-pypi:
110
+ needs: build
111
+ if: startsWith(github.ref, 'refs/tags/v') || (github.event_name == 'workflow_dispatch' && inputs.target == 'pypi')
112
+ runs-on: ubuntu-latest
113
+ environment:
114
+ name: pypi
115
+ url: https://pypi.org/p/cbpr-validate
116
+ permissions:
117
+ id-token: write
118
+ steps:
119
+ - uses: actions/download-artifact@v4
120
+ with:
121
+ name: dist
122
+ path: dist/
123
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,17 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .eggs/
5
+ build/
6
+ dist/
7
+ .venv/
8
+ venv/
9
+ .pytest_cache/
10
+ .mypy_cache/
11
+ .ruff_cache/
12
+ .coverage
13
+ htmlcov/
14
+ .env
15
+
16
+ # Local learning notes
17
+ learning_guide/