finanzonline-uid 2.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 (135) hide show
  1. finanzonline_uid-2.0.0/.devcontainer/devcontainer.json +22 -0
  2. finanzonline_uid-2.0.0/.devcontainer/settings.json +6 -0
  3. finanzonline_uid-2.0.0/.env.example +131 -0
  4. finanzonline_uid-2.0.0/.github/dependabot.yml +22 -0
  5. finanzonline_uid-2.0.0/.github/workflows/ci.yml +205 -0
  6. finanzonline_uid-2.0.0/.github/workflows/codeql.yml +39 -0
  7. finanzonline_uid-2.0.0/.github/workflows/release.yml +50 -0
  8. finanzonline_uid-2.0.0/.gitignore +180 -0
  9. finanzonline_uid-2.0.0/.qlty/qlty.toml +2 -0
  10. finanzonline_uid-2.0.0/.snyk +5 -0
  11. finanzonline_uid-2.0.0/API_REFERENCE_de.md +428 -0
  12. finanzonline_uid-2.0.0/API_REFERENCE_en.md +428 -0
  13. finanzonline_uid-2.0.0/CHANGELOG.md +30 -0
  14. finanzonline_uid-2.0.0/CLAUDE.md +172 -0
  15. finanzonline_uid-2.0.0/CLI_REFERENCE_de.md +171 -0
  16. finanzonline_uid-2.0.0/CLI_REFERENCE_en.md +171 -0
  17. finanzonline_uid-2.0.0/CONFIGURATION_de.md +252 -0
  18. finanzonline_uid-2.0.0/CONFIGURATION_en.md +252 -0
  19. finanzonline_uid-2.0.0/CONTRIBUTING.md +48 -0
  20. finanzonline_uid-2.0.0/DEVELOPMENT.md +134 -0
  21. finanzonline_uid-2.0.0/INSTALL_de.md +266 -0
  22. finanzonline_uid-2.0.0/INSTALL_en.md +266 -0
  23. finanzonline_uid-2.0.0/LICENSE +22 -0
  24. finanzonline_uid-2.0.0/Makefile +68 -0
  25. finanzonline_uid-2.0.0/PKG-INFO +232 -0
  26. finanzonline_uid-2.0.0/README.md +187 -0
  27. finanzonline_uid-2.0.0/README_en.md +187 -0
  28. finanzonline_uid-2.0.0/RETURNCODES_de.md +91 -0
  29. finanzonline_uid-2.0.0/RETURNCODES_en.md +91 -0
  30. finanzonline_uid-2.0.0/babel.cfg +5 -0
  31. finanzonline_uid-2.0.0/codecov.yml +28 -0
  32. finanzonline_uid-2.0.0/docs/prd/BMF_DataBox_Download_Webservice_2.pdf +0 -0
  33. finanzonline_uid-2.0.0/docs/prd/BMF_DataBox_Download_Webservice_Dokumentenversion.pdf +0 -0
  34. finanzonline_uid-2.0.0/docs/prd/BMF_Session_Webservice_Englisch.pdf +0 -0
  35. finanzonline_uid-2.0.0/docs/prd/BMF_UID_Abfrage_Webservice_2.pdf +0 -0
  36. finanzonline_uid-2.0.0/docs/prd/databox.xsd +105 -0
  37. finanzonline_uid-2.0.0/docs/prd/databoxService.wsdl +55 -0
  38. finanzonline_uid-2.0.0/docs/prd/login.wdsl +55 -0
  39. finanzonline_uid-2.0.0/docs/prd/login.xsd +82 -0
  40. finanzonline_uid-2.0.0/docs/prd/prd.md +344 -0
  41. finanzonline_uid-2.0.0/docs/prd/uidAbfrageService.wsdl +36 -0
  42. finanzonline_uid-2.0.0/docs/systemdesign/module_reference.md +273 -0
  43. finanzonline_uid-2.0.0/notebooks/Quickstart.ipynb +165 -0
  44. finanzonline_uid-2.0.0/pyproject.toml +174 -0
  45. finanzonline_uid-2.0.0/reset_git_history.sh +54 -0
  46. finanzonline_uid-2.0.0/scripts/__init__.py +9 -0
  47. finanzonline_uid-2.0.0/scripts/__main__.py +9 -0
  48. finanzonline_uid-2.0.0/scripts/_utils.py +768 -0
  49. finanzonline_uid-2.0.0/scripts/build.py +53 -0
  50. finanzonline_uid-2.0.0/scripts/bump.py +33 -0
  51. finanzonline_uid-2.0.0/scripts/bump_major.py +21 -0
  52. finanzonline_uid-2.0.0/scripts/bump_minor.py +21 -0
  53. finanzonline_uid-2.0.0/scripts/bump_patch.py +21 -0
  54. finanzonline_uid-2.0.0/scripts/bump_version.py +122 -0
  55. finanzonline_uid-2.0.0/scripts/clean.py +75 -0
  56. finanzonline_uid-2.0.0/scripts/cli.py +229 -0
  57. finanzonline_uid-2.0.0/scripts/dependencies.py +590 -0
  58. finanzonline_uid-2.0.0/scripts/dev.py +20 -0
  59. finanzonline_uid-2.0.0/scripts/help.py +38 -0
  60. finanzonline_uid-2.0.0/scripts/install.py +20 -0
  61. finanzonline_uid-2.0.0/scripts/menu.py +640 -0
  62. finanzonline_uid-2.0.0/scripts/push.py +310 -0
  63. finanzonline_uid-2.0.0/scripts/release.py +95 -0
  64. finanzonline_uid-2.0.0/scripts/run_cli.py +147 -0
  65. finanzonline_uid-2.0.0/scripts/target_metadata.py +198 -0
  66. finanzonline_uid-2.0.0/scripts/test.py +1004 -0
  67. finanzonline_uid-2.0.0/scripts/toml_config.py +433 -0
  68. finanzonline_uid-2.0.0/scripts/version_current.py +21 -0
  69. finanzonline_uid-2.0.0/src/finanzonline_uid/__init__.py +29 -0
  70. finanzonline_uid-2.0.0/src/finanzonline_uid/__init__conf__.py +74 -0
  71. finanzonline_uid-2.0.0/src/finanzonline_uid/__main__.py +114 -0
  72. finanzonline_uid-2.0.0/src/finanzonline_uid/_datetime_utils.py +53 -0
  73. finanzonline_uid-2.0.0/src/finanzonline_uid/adapters/__init__.py +20 -0
  74. finanzonline_uid-2.0.0/src/finanzonline_uid/adapters/cache/__init__.py +14 -0
  75. finanzonline_uid-2.0.0/src/finanzonline_uid/adapters/cache/file_cache.py +285 -0
  76. finanzonline_uid-2.0.0/src/finanzonline_uid/adapters/finanzonline/__init__.py +26 -0
  77. finanzonline_uid-2.0.0/src/finanzonline_uid/adapters/finanzonline/session_client.py +268 -0
  78. finanzonline_uid-2.0.0/src/finanzonline_uid/adapters/finanzonline/uid_query_client.py +318 -0
  79. finanzonline_uid-2.0.0/src/finanzonline_uid/adapters/notification/__init__.py +23 -0
  80. finanzonline_uid-2.0.0/src/finanzonline_uid/adapters/notification/email_adapter.py +614 -0
  81. finanzonline_uid-2.0.0/src/finanzonline_uid/adapters/output/__init__.py +25 -0
  82. finanzonline_uid-2.0.0/src/finanzonline_uid/adapters/output/formatters.py +181 -0
  83. finanzonline_uid-2.0.0/src/finanzonline_uid/adapters/ratelimit/__init__.py +15 -0
  84. finanzonline_uid-2.0.0/src/finanzonline_uid/adapters/ratelimit/rate_limit_tracker.py +320 -0
  85. finanzonline_uid-2.0.0/src/finanzonline_uid/application/__init__.py +38 -0
  86. finanzonline_uid-2.0.0/src/finanzonline_uid/application/ports.py +138 -0
  87. finanzonline_uid-2.0.0/src/finanzonline_uid/application/use_cases.py +193 -0
  88. finanzonline_uid-2.0.0/src/finanzonline_uid/behaviors.py +133 -0
  89. finanzonline_uid-2.0.0/src/finanzonline_uid/cli.py +817 -0
  90. finanzonline_uid-2.0.0/src/finanzonline_uid/config.py +440 -0
  91. finanzonline_uid-2.0.0/src/finanzonline_uid/config_deploy.py +139 -0
  92. finanzonline_uid-2.0.0/src/finanzonline_uid/config_show.py +124 -0
  93. finanzonline_uid-2.0.0/src/finanzonline_uid/defaultconfig.d/20-email.toml +95 -0
  94. finanzonline_uid-2.0.0/src/finanzonline_uid/defaultconfig.d/30-logging.toml +420 -0
  95. finanzonline_uid-2.0.0/src/finanzonline_uid/defaultconfig.toml +192 -0
  96. finanzonline_uid-2.0.0/src/finanzonline_uid/domain/__init__.py +61 -0
  97. finanzonline_uid-2.0.0/src/finanzonline_uid/domain/errors.py +203 -0
  98. finanzonline_uid-2.0.0/src/finanzonline_uid/domain/models.py +370 -0
  99. finanzonline_uid-2.0.0/src/finanzonline_uid/domain/return_codes.py +249 -0
  100. finanzonline_uid-2.0.0/src/finanzonline_uid/enums.py +91 -0
  101. finanzonline_uid-2.0.0/src/finanzonline_uid/i18n.py +156 -0
  102. finanzonline_uid-2.0.0/src/finanzonline_uid/locales/de/LC_MESSAGES/messages.mo +0 -0
  103. finanzonline_uid-2.0.0/src/finanzonline_uid/locales/de/LC_MESSAGES/messages.po +339 -0
  104. finanzonline_uid-2.0.0/src/finanzonline_uid/locales/es/LC_MESSAGES/messages.mo +0 -0
  105. finanzonline_uid-2.0.0/src/finanzonline_uid/locales/es/LC_MESSAGES/messages.po +339 -0
  106. finanzonline_uid-2.0.0/src/finanzonline_uid/locales/fr/LC_MESSAGES/messages.mo +0 -0
  107. finanzonline_uid-2.0.0/src/finanzonline_uid/locales/fr/LC_MESSAGES/messages.po +339 -0
  108. finanzonline_uid-2.0.0/src/finanzonline_uid/locales/messages.pot +19 -0
  109. finanzonline_uid-2.0.0/src/finanzonline_uid/locales/ru/LC_MESSAGES/messages.mo +0 -0
  110. finanzonline_uid-2.0.0/src/finanzonline_uid/locales/ru/LC_MESSAGES/messages.po +339 -0
  111. finanzonline_uid-2.0.0/src/finanzonline_uid/logging_setup.py +107 -0
  112. finanzonline_uid-2.0.0/src/finanzonline_uid/mail.py +391 -0
  113. finanzonline_uid-2.0.0/src/finanzonline_uid/py.typed +0 -0
  114. finanzonline_uid-2.0.0/tests/adapters/__init__.py +1 -0
  115. finanzonline_uid-2.0.0/tests/adapters/test_email_adapter.py +586 -0
  116. finanzonline_uid-2.0.0/tests/adapters/test_file_cache.py +381 -0
  117. finanzonline_uid-2.0.0/tests/adapters/test_formatters.py +182 -0
  118. finanzonline_uid-2.0.0/tests/adapters/test_rate_limit_tracker.py +396 -0
  119. finanzonline_uid-2.0.0/tests/adapters/test_session_client.py +435 -0
  120. finanzonline_uid-2.0.0/tests/adapters/test_uid_query_client.py +391 -0
  121. finanzonline_uid-2.0.0/tests/application/__init__.py +1 -0
  122. finanzonline_uid-2.0.0/tests/application/test_use_cases.py +187 -0
  123. finanzonline_uid-2.0.0/tests/conftest.py +456 -0
  124. finanzonline_uid-2.0.0/tests/domain/__init__.py +1 -0
  125. finanzonline_uid-2.0.0/tests/domain/test_errors.py +139 -0
  126. finanzonline_uid-2.0.0/tests/domain/test_models.py +278 -0
  127. finanzonline_uid-2.0.0/tests/domain/test_return_codes.py +200 -0
  128. finanzonline_uid-2.0.0/tests/test_behaviors.py +67 -0
  129. finanzonline_uid-2.0.0/tests/test_cli.py +1223 -0
  130. finanzonline_uid-2.0.0/tests/test_config_finanzonline.py +474 -0
  131. finanzonline_uid-2.0.0/tests/test_i18n.py +202 -0
  132. finanzonline_uid-2.0.0/tests/test_mail.py +560 -0
  133. finanzonline_uid-2.0.0/tests/test_metadata.py +106 -0
  134. finanzonline_uid-2.0.0/tests/test_module_entry.py +161 -0
  135. finanzonline_uid-2.0.0/tests/test_scripts.py +270 -0
@@ -0,0 +1,22 @@
1
+ {
2
+ "image": "mcr.microsoft.com/devcontainers/python:3.13",
3
+
4
+ "postCreateCommand": "bash -lc '\nPY=/usr/local/bin/python;\n$PY -m pip install -U pip && \\\n$PY -m pip install ipykernel && \\\n$PY -m pip install -e . && \\\n# register kernel using this exact interpreter\n$PY -m ipykernel install --name=python3 --display-name=\"Python 3 (3.13)\" --user && \\\n# patch the notebook to point to the python3 kernelspec (VS Code will bind to /usr/local/bin/python)\n$PY - <<\"PY\"\nimport json, pathlib\np = pathlib.Path(\"notebooks/Quickstart.ipynb\")\nif p.exists():\n nb = json.loads(p.read_text(encoding=\"utf-8\"))\n md = nb.setdefault(\"metadata\", {})\n md[\"kernelspec\"] = {\n \"name\": \"python3\",\n \"display_name\": \"Python 3 (3.13)\",\n \"language\": \"python\"\n }\n md[\"language_info\"] = {\"name\": \"python\"}\n p.write_text(json.dumps(nb, ensure_ascii=False, indent=1), encoding=\"utf-8\")\n print(\"Pinned kernelspec to python3 in\", p)\nelse:\n print(\"Notebook not found:\", p)\nPY'\n",
5
+
6
+ "customizations": {
7
+ "vscode": {
8
+ "extensions": ["ms-toolsai.jupyter", "ms-python.python"],
9
+ "settings": {
10
+ "workbench.startupEditor": "none",
11
+ "jupyter.alwaysTrustNotebooks": true,
12
+ "jupyter.kernelPickerType": "OnlyRecommended",
13
+ "python.defaultInterpreterPath": "/usr/local/bin/python"
14
+ }
15
+ },
16
+ "codespaces": {
17
+ "openFiles": ["README.md"]
18
+ }
19
+ },
20
+
21
+ "postAttachCommand": "bash -lc 'if [ -f notebooks/Quickstart.ipynb ]; then code -r notebooks/Quickstart.ipynb; fi'"
22
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "python.defaultInterpreterPath": "/usr/local/bin/python3.13",
3
+ "jupyter.alwaysTrustNotebooks": true,
4
+ "jupyter.kernelPickerType": "OnlyRecommended",
5
+ "jupyter.askForKernelRestart": false
6
+ }
@@ -0,0 +1,131 @@
1
+ # Copy to .env and fill values as needed.
2
+ #
3
+ # .env file format (no prefix needed):
4
+ # SECTION__KEY=value
5
+ #
6
+ # Environment variable format (requires prefix):
7
+ # FINANZONLINE_UID___SECTION__KEY=value
8
+
9
+ # =============================================================================
10
+ # CI/CD Tokens
11
+ # =============================================================================
12
+
13
+ # Codecov upload token (required for private repos; optional for public repos)
14
+ CODECOV_TOKEN=
15
+
16
+ # PyPI API token for release workflow (.github/workflows/release.yml)
17
+ # Format: pypi-AgENdGVzdC5weXBpLm9yZwIk...
18
+ PYPI_API_TOKEN=
19
+
20
+ # Optional: GitHub token for API-limited tasks
21
+ GITHUB_TOKEN=
22
+
23
+ # =============================================================================
24
+ # Application Settings
25
+ # =============================================================================
26
+
27
+ # Language for user-facing messages and email notifications
28
+ # Supported: en (English), de (German), es (Spanish), fr (French), ru (Russian)
29
+ APP__LANGUAGE=en
30
+
31
+ # =============================================================================
32
+ # FinanzOnline Configuration (required for UID checks)
33
+ # =============================================================================
34
+ #
35
+ # IMPORTANT: The user (BENID) must have webservice permissions enabled!
36
+ # Check FinanzOnline user administration to ensure the user is configured
37
+ # as a webservice user, not just a regular FinanzOnline user.
38
+ #
39
+ # Return code -7 means "The user is not a web service user"
40
+ # Return code -4 means "The access codes are not valid"
41
+ #
42
+
43
+ # Participant ID (Teilnehmer-ID) - 8-12 alphanumeric characters
44
+ FINANZONLINE__TID=123456789
45
+
46
+ # User ID (Benutzer-ID) - 5-12 characters
47
+ # IMPORTANT: Must be a WEBSERVICE user created in FinanzOnline user admin!
48
+ FINANZONLINE__BENID=MYUSER
49
+
50
+ # Password/PIN - 5-128 characters
51
+ FINANZONLINE__PIN=secret
52
+
53
+ # Your Austrian UID (must start with ATU)
54
+ FINANZONLINE__UID_TN=ATU12345678
55
+
56
+ # Software Producer VAT-ID - 10-24 alphanumeric characters
57
+ # This is the VAT-ID of the company that produced the software - put Your own ATU Number there
58
+ FINANZONLINE__HERSTELLERID=ATU12345678
59
+
60
+ # Optional: Session and query timeouts
61
+ # FINANZONLINE__SESSION_TIMEOUT=60.0
62
+ # FINANZONLINE__QUERY_TIMEOUT=60.0
63
+
64
+ # Default email recipients for UID check results (JSON array format)
65
+ # Note: EMAIL__DEFAULT_RECIPIENTS is preferred as it works even when FO config fails
66
+ # FINANZONLINE__DEFAULT_RECIPIENTS=["admin@example.com"]
67
+
68
+ # Email format for notifications (default: both)
69
+ # Options: html, plain, both
70
+ # - html: Send HTML-only emails (rich formatting)
71
+ # - plain: Send plain text-only emails
72
+ # - both: Send multipart/alternative with both formats
73
+ FINANZONLINE__EMAIL_FORMAT=both
74
+
75
+ # Cache valid UID results for this many hours (0 = disabled, default: 48)
76
+ # Only valid results are cached. Email notifications include cache timestamp.
77
+ FINANZONLINE__CACHE_RESULTS_HOURS=48
78
+
79
+ # Path to cache file (default: platform-specific cache directory)
80
+ # Uses file locking for safe concurrent access on network drives
81
+ # FINANZONLINE__CACHE_FILE=/shared/network/uid_cache.json
82
+
83
+ # Rate limiting: Maximum API queries allowed within the time window (0 = disabled)
84
+ # When exceeded: logs warning, sends email, but query still proceeds (BMF handles actual limit)
85
+ # Note: Cache hits don't count toward rate limit - only actual API calls are tracked
86
+ FINANZONLINE__RATELIMIT_QUERIES=50
87
+
88
+ # Rate limiting: Sliding window duration in hours (default: 24)
89
+ FINANZONLINE__RATELIMIT_HOURS=24.0
90
+
91
+ # Path to rate limit tracking file (default: platform-specific cache directory)
92
+ # Uses file locking for safe concurrent access
93
+ # FINANZONLINE__RATELIMIT_FILE=/shared/network/rate_limits.json
94
+
95
+ # Default email recipients for ALL notifications (including config errors)
96
+ # This is the PRIMARY recipient setting - used even when FinanzOnline config fails
97
+ FINANZONLINE__DEFAULT_RECIPIENTS=["admin@example.com"]
98
+
99
+ # =============================================================================
100
+ # Email Configuration (for sending notifications)
101
+ # =============================================================================
102
+
103
+ # SMTP servers in JSON array format (tried in order)
104
+ EMAIL__SMTP_HOSTS=["smtp.example.com:587"]
105
+
106
+ # Default sender address
107
+ EMAIL__FROM_ADDRESS=alerts@example.com
108
+
109
+ # SMTP authentication (optional, both needed for auth)
110
+ # EMAIL__SMTP_USERNAME=your-email@example.com
111
+ # EMAIL__SMTP_PASSWORD=your-app-password
112
+
113
+ # SMTP connection settings
114
+ # EMAIL__USE_STARTTLS=true
115
+ # EMAIL__TIMEOUT=30.0
116
+
117
+
118
+ # =============================================================================
119
+ # Testing (for local development)
120
+ # =============================================================================
121
+
122
+ # Test SMTP server configuration
123
+ TEST_SMTP_SERVER=
124
+ TEST_EMAIL_ADDRESS=
125
+
126
+ # =============================================================================
127
+ # Logging Configuration
128
+ # =============================================================================
129
+ # Uses same SECTION__KEY format as other settings (via lib_layered_config)
130
+ # LIB_LOG_RICH__CONSOLE_LEVEL=DEBUG
131
+ # LIB_LOG_RICH__CONSOLE_FORMAT_PRESET=short
@@ -0,0 +1,22 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "pip"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ allow:
8
+ - dependency-type: "direct"
9
+ labels:
10
+ - "dependencies"
11
+ commit-message:
12
+ prefix: "deps"
13
+ include: "scope"
14
+ - package-ecosystem: "github-actions"
15
+ directory: "/"
16
+ schedule:
17
+ interval: "weekly"
18
+ labels:
19
+ - "dependencies"
20
+ commit-message:
21
+ prefix: "deps"
22
+ include: "scope"
@@ -0,0 +1,205 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ main, master ]
6
+ pull_request:
7
+ branches: [ main, master ]
8
+ schedule:
9
+ # Run daily at 3:17 AM UTC (off-peak hours, odd minute to avoid congestion)
10
+ - cron: '17 3 * * *'
11
+
12
+ jobs:
13
+ test:
14
+ name: Tests (Python ${{ matrix.python }}, ${{ matrix.os }})
15
+ runs-on: ${{ matrix.os }}
16
+ strategy:
17
+ fail-fast: false
18
+ matrix:
19
+ os: [ubuntu-latest, macos-latest, windows-latest]
20
+ # Test against Python 3.10, 3.11, 3.12, and 3.13
21
+ python: ["3.10", "3.11", "3.12", "3.13"]
22
+ env:
23
+ PYO3_USE_ABI3_FORWARD_COMPATIBILITY: "1"
24
+ PYTHONIOENCODING: "utf-8"
25
+ steps:
26
+ - uses: actions/checkout@v6
27
+ - uses: actions/setup-python@v6
28
+ with:
29
+ python-version: ${{ matrix.python }}
30
+ cache: 'pip'
31
+ cache-dependency-path: 'pyproject.toml'
32
+ - name: Install uv
33
+ uses: astral-sh/setup-uv@v7
34
+ with:
35
+ enable-cache: true
36
+ - name: Install rtoml for metadata extraction
37
+ shell: bash
38
+ run: python -m pip install rtoml
39
+ - name: Extract project metadata
40
+ shell: python
41
+ run: |
42
+ import os
43
+ import rtoml
44
+ from pathlib import Path
45
+
46
+ data = rtoml.loads(Path('pyproject.toml').read_text('utf-8'))
47
+ project = data['project']['name']
48
+ module = project.replace('-', '_')
49
+ dash = project.replace('_', '-')
50
+ scripts = list(data['project'].get('scripts', {}).keys())
51
+ cli_bin = scripts[0] if scripts else dash
52
+
53
+ with open(os.environ['GITHUB_ENV'], 'a', encoding='utf-8') as env:
54
+ env.write(f"PROJECT_NAME={project}\n")
55
+ env.write(f"PACKAGE_MODULE={module}\n")
56
+ env.write(f"CLI_BIN={cli_bin}\n")
57
+ - name: Install make on Windows
58
+ if: runner.os == 'Windows'
59
+ shell: pwsh
60
+ run: |
61
+ choco install -y make
62
+ echo "C:\\ProgramData\\chocolatey\\bin" >> $env:GITHUB_PATH
63
+ - name: Install journald prerequisites
64
+ if: runner.os == 'Linux'
65
+ shell: bash
66
+ run: |
67
+ sudo apt-get update
68
+ sudo apt-get install -y python3-systemd
69
+
70
+ - name: Upgrade pip
71
+ shell: bash
72
+ run: python -m pip install --upgrade pip
73
+
74
+ - name: Install dev deps
75
+ shell: bash
76
+ run: |
77
+ uv pip install -e .[dev] --system
78
+
79
+ - name: Install Windows Event Log prerequisites
80
+ if: runner.os == 'Windows'
81
+ shell: bash
82
+ run: |
83
+ uv pip install pywin32 --system
84
+ - name: Cache ruff
85
+ uses: actions/cache@v5
86
+ with:
87
+ path: .ruff_cache
88
+ key: ruff-${{ runner.os }}-${{ github.sha }}
89
+ restore-keys: |
90
+ ruff-${{ runner.os }}-
91
+ - name: Cache pyright
92
+ uses: actions/cache@v5
93
+ with:
94
+ path: .pyright
95
+ key: pyright-${{ runner.os }}-py${{ matrix.python }}-${{ github.sha }}
96
+ restore-keys: |
97
+ pyright-${{ runner.os }}-py${{ matrix.python }}-
98
+ pyright-${{ runner.os }}-
99
+ - name: Run full test suite (lint, types, tests, coverage, codecov)
100
+ shell: bash
101
+ env:
102
+ TEST_VERBOSE: "1"
103
+ run: make test
104
+ - name: Build wheel/sdist
105
+ shell: bash
106
+ run: python -m build
107
+ - name: Verify wheel install in clean env
108
+ shell: bash
109
+ run: |
110
+ python -m venv .venv_wheel
111
+ . .venv_wheel/bin/activate 2>/dev/null || . .venv_wheel/Scripts/activate 2>/dev/null
112
+ pip install dist/*.whl
113
+ "$CLI_BIN" --version 2>/dev/null || python -m "$PACKAGE_MODULE" --version
114
+
115
+ pipx-uv:
116
+ name: pipx/uv verification (ubuntu)
117
+ runs-on: ubuntu-latest
118
+ steps:
119
+ - uses: actions/checkout@v6
120
+ - uses: actions/setup-python@v6
121
+ with:
122
+ python-version: "3.13"
123
+ cache: 'pip'
124
+ cache-dependency-path: 'pyproject.toml'
125
+ - name: Install rtoml for metadata extraction
126
+ run: python -m pip install rtoml
127
+ - name: Extract project metadata
128
+ shell: python
129
+ run: |
130
+ import os
131
+ import rtoml
132
+ from pathlib import Path
133
+
134
+ data = rtoml.loads(Path('pyproject.toml').read_text('utf-8'))
135
+ project = data['project']['name']
136
+ module = project.replace('-', '_')
137
+ dash = project.replace('_', '-')
138
+ scripts = list(data['project'].get('scripts', {}).keys())
139
+ cli_bin = scripts[0] if scripts else dash
140
+
141
+ with open(os.environ['GITHUB_ENV'], 'a', encoding='utf-8') as env:
142
+ env.write(f"PROJECT_NAME={project}\n")
143
+ env.write(f"PACKAGE_MODULE={module}\n")
144
+ env.write(f"CLI_BIN={cli_bin}\n")
145
+ - name: Build wheel
146
+ run: |
147
+ python -m pip install --upgrade pip build
148
+ python -m build
149
+ - name: pipx install from wheel
150
+ run: |
151
+ python -m pip install pipx
152
+ pipx install dist/*.whl
153
+ "$CLI_BIN" --version 2>/dev/null || python -m "$PACKAGE_MODULE" --version
154
+ - name: Install uv
155
+ uses: astral-sh/setup-uv@v7
156
+ with:
157
+ enable-cache: true
158
+ - name: uv tool install
159
+ run: |
160
+ uv tool install .
161
+ "$CLI_BIN" --version 2>/dev/null || python -m "$PACKAGE_MODULE" --version
162
+
163
+ notebooks:
164
+ name: Execute notebooks (ubuntu, Python 3.13)
165
+ runs-on: ubuntu-latest
166
+ steps:
167
+ - uses: actions/checkout@v6
168
+ - uses: actions/setup-python@v6
169
+ with:
170
+ python-version: "3.13"
171
+ cache: 'pip'
172
+ cache-dependency-path: 'pyproject.toml'
173
+ - name: Install notebook runner deps
174
+ run: |
175
+ python -m pip install --upgrade pip
176
+ pip install nbclient nbformat ipykernel jupyter_client
177
+ python -m ipykernel install --user --name python3 --display-name "Python 3"
178
+ - name: Execute Quickstart notebook
179
+ env:
180
+ PIP_DISABLE_PIP_VERSION_CHECK: "1"
181
+ PIP_NO_INPUT: "1"
182
+ run: |
183
+ python - << 'PY'
184
+ from pathlib import Path
185
+
186
+ import nbformat
187
+ from nbclient import NotebookClient
188
+
189
+ nb_path = Path('notebooks/Quickstart.ipynb')
190
+ if not nb_path.exists():
191
+ raise SystemExit(f"Notebook not found: {nb_path}")
192
+
193
+ notebook = nbformat.read(nb_path, as_version=4)
194
+ client = NotebookClient(
195
+ notebook,
196
+ timeout=900,
197
+ kernel_name='python3',
198
+ allow_errors=False,
199
+ )
200
+ client.execute()
201
+
202
+ out_path = Path('notebooks/Quickstart-executed.ipynb')
203
+ nbformat.write(notebook, out_path)
204
+ print(f"Executed notebook written to: {out_path}")
205
+ PY
@@ -0,0 +1,39 @@
1
+ name: CodeQL
2
+
3
+ on:
4
+ push:
5
+ branches: [ main, master ]
6
+ pull_request:
7
+ branches: [ main, master ]
8
+ schedule:
9
+ - cron: '0 8 * * 1'
10
+
11
+ jobs:
12
+ analyze:
13
+ name: CodeQL Analyze
14
+ runs-on: ubuntu-latest
15
+ permissions:
16
+ actions: read
17
+ contents: read
18
+ security-events: write
19
+ strategy:
20
+ fail-fast: false
21
+ matrix:
22
+ language: [ 'python' ]
23
+
24
+ steps:
25
+ - name: Checkout repository
26
+ uses: actions/checkout@v6
27
+
28
+ - name: Initialize CodeQL
29
+ uses: github/codeql-action/init@v4
30
+ with:
31
+ languages: ${{ matrix.language }}
32
+
33
+ - name: Autobuild
34
+ uses: github/codeql-action/autobuild@v4
35
+
36
+ - name: Perform CodeQL Analysis
37
+ uses: github/codeql-action/analyze@v4
38
+ with:
39
+ category: "/language:${{ matrix.language }}"
@@ -0,0 +1,50 @@
1
+ name: Release
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ push:
7
+ tags:
8
+ - 'v*'
9
+ workflow_dispatch: {}
10
+
11
+ jobs:
12
+ build-and-publish:
13
+ runs-on: ubuntu-latest
14
+ permissions:
15
+ contents: read
16
+ steps:
17
+ - uses: actions/checkout@v6
18
+ - name: Verify PyPI token is set
19
+ run: |
20
+ if [ -z "${{ secrets.PYPI_API_TOKEN }}" ]; then
21
+ echo "::error title=Missing PyPI token::Set the PYPI_API_TOKEN secret in GitHub repository settings to enable PyPI publishing on releases."
22
+ echo "See: https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions"
23
+ exit 1
24
+ fi
25
+ - uses: actions/setup-python@v6
26
+ with:
27
+ python-version: '3.13'
28
+ cache: 'pip'
29
+ cache-dependency-path: 'pyproject.toml'
30
+ - name: Install uv
31
+ uses: astral-sh/setup-uv@v7
32
+ with:
33
+ enable-cache: true
34
+ - name: Build artifacts
35
+ run: |
36
+ python -m pip install --upgrade pip
37
+ uv pip install build --system
38
+ python -m build
39
+ - name: Publish to PyPI
40
+ # Use the rolling major tag to get latest Twine/standards support (e.g., Core Metadata 2.4)
41
+ uses: pypa/gh-action-pypi-publish@release/v1
42
+ with:
43
+ password: ${{ secrets.PYPI_API_TOKEN }}
44
+ attestations: false
45
+ skip-existing: true
46
+ - name: Upload artifacts
47
+ uses: actions/upload-artifact@v6
48
+ with:
49
+ name: dist
50
+ path: dist/*
@@ -0,0 +1,180 @@
1
+ # ====================================
2
+ # ROTEK SPEZIFISCH: Git commands you might run once
3
+ # git add .gitignore && git commit -m "Ignore IDE settings"
4
+ # git push
5
+ # git rm -r --cached .idea
6
+ # git commit -m "Remove .idea and add to .gitignore"
7
+ # git push
8
+ # alternative : BE CAREFUL: overwrites remote history
9
+ # git push origin master --force
10
+
11
+ # ====================================
12
+ # APP
13
+ # ====================================
14
+ website/build/
15
+ website/.docusaurus/
16
+ website/node_modules/
17
+ node_modules/
18
+ web-local-preview/
19
+ translation_app*.log
20
+ translation_web*.log
21
+ tmp_github_web_pages/
22
+ tmp_linkcheck_web_pages/
23
+ .eslintcache
24
+ .vitest/
25
+ npm-debug.log*
26
+ yarn-error.log*
27
+ pnpm-debug.log*
28
+ .env.*
29
+ !.env.example
30
+ todo.md
31
+ tmp_*
32
+
33
+ # ====================================
34
+ # IDEs & Editors
35
+ # ====================================
36
+ # IntelliJ, PyCharm, etc.
37
+ .idea/
38
+ # VS Code workspace settings
39
+ .vscode/
40
+ *.code-workspace
41
+
42
+ # ====================================
43
+ # Python bytecode & caches
44
+ # ====================================
45
+ # __pycache__: compiled .pyc files at any depth
46
+ # *.py[cod]: catches .pyc, .pyo, .pyd
47
+ __pycache__/
48
+ *.py[cod]
49
+ *$py.class # other compiled artifacts
50
+
51
+ # pytest, coverage, MyPy, Hypothesis
52
+ .pytest_cache/
53
+ .mypy_cache/
54
+ .pyright/
55
+ .coverage*
56
+ htmlcov/
57
+ nosetests.xml
58
+ coverage.xml
59
+ *.cover
60
+ .hypothesis/
61
+ .tox/
62
+ .nox/
63
+
64
+ # general cache directories (any project-level caching)
65
+ .cache/
66
+ .run/
67
+ .import_linter_cache/
68
+
69
+ # ====================================
70
+ # Build & distribution artifacts
71
+ # ====================================
72
+ # source/package builds
73
+ build/
74
+ dist/
75
+ *.egg-info/ # metadata for pip installs
76
+ *.egg
77
+ *.whl
78
+ pip-wheel-metadata/
79
+ *.manifest # PyInstaller metadata
80
+ *.spec # PyInstaller spec files
81
+
82
+ # Eggs, parts, wheels, sdist, etc.
83
+ develop-eggs/
84
+ .eggs/
85
+ parts/
86
+ sdist/
87
+ wheels/
88
+ downloads/
89
+ var/
90
+
91
+ # pip logs & installer leftovers
92
+ pip-log.txt
93
+ pip-delete-this-directory.txt
94
+ .installed.cfg
95
+
96
+ # ====================================
97
+ # Virtual environments & secrets
98
+ # ====================================
99
+ # common venv folder names
100
+ env/
101
+ venv/
102
+ ENV/
103
+ .venv/
104
+ # backups, alternate names
105
+ env.bak/
106
+ venv.bak/
107
+ # dotenv files with credentials
108
+ .env
109
+
110
+ # ====================================
111
+ # Project-specific & framework files
112
+ # ====================================
113
+ # Django logs & local overrides
114
+ *.log
115
+ local_settings.py
116
+
117
+ # Flask instance folder
118
+ instance/
119
+ .webassets-cache
120
+
121
+ # Scrapy cache
122
+ .scrapy
123
+
124
+ # Sphinx docs
125
+ docs/_build/
126
+
127
+ # PyBuilder output
128
+ target/
129
+
130
+ # Jupyter notebooks checkpoints
131
+ .ipynb_checkpoints
132
+
133
+ # pyenv Python version file
134
+ .python-version
135
+
136
+ # Celery beat schedule
137
+ celerybeat-schedule
138
+
139
+ # SageMath parsed files
140
+ *.sage.py
141
+
142
+ # Spyder IDE
143
+ .spyderproject
144
+ .spyproject
145
+
146
+ # Rope IDE
147
+ .ropeproject
148
+
149
+ # MkDocs static site folder
150
+ /site
151
+
152
+ # ====================================
153
+ # OS-specific files
154
+ # ====================================
155
+ # macOS
156
+ .DS_Store
157
+ # Windows
158
+ Thumbs.db
159
+ ehthumbs.db
160
+
161
+ # Archives
162
+ *.zip
163
+
164
+ # Thunderbird build artifact (created temporarily by pack script)
165
+ sources/manifest.json
166
+
167
+ # ====================================
168
+ # Tool-specific extras
169
+ # ====================================
170
+ # Codecov uploader script (downloaded during local uploads)
171
+ codecov.sh
172
+ codecov.xml
173
+
174
+ # Nix build result symlink
175
+ result
176
+
177
+ # Optional lockfiles (for alternative managers)
178
+ poetry.lock
179
+ pdm.lock
180
+ uv.lock
@@ -0,0 +1,2 @@
1
+ exclude_patterns = ["scripts/**"]
2
+ test_patterns = ["tests/**"]
@@ -0,0 +1,5 @@
1
+ # Snyk (https://snyk.io) policy file
2
+ exclude:
3
+ global:
4
+ - scripts/**
5
+ - tests/**