confkit 2.0.0__tar.gz → 2.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 (103) hide show
  1. confkit-2.1.0/.github/workflows/docs.yml +88 -0
  2. confkit-2.1.0/.github/workflows/gitleaks.yml +28 -0
  3. confkit-2.1.0/.github/workflows/lint-public.yml +70 -0
  4. confkit-2.1.0/.github/workflows/lint.yml +66 -0
  5. {confkit-2.0.0 → confkit-2.1.0}/.github/workflows/test.yml +0 -2
  6. {confkit-2.0.0 → confkit-2.1.0}/.gitignore +0 -1
  7. {confkit-2.0.0 → confkit-2.1.0}/.pre-commit-config.yaml +12 -0
  8. {confkit-2.0.0 → confkit-2.1.0}/PKG-INFO +1 -1
  9. {confkit-2.0.0 → confkit-2.1.0}/examples/file_change_event.py +6 -5
  10. {confkit-2.0.0 → confkit-2.1.0}/examples/url_example.py +3 -1
  11. {confkit-2.0.0 → confkit-2.1.0}/pyproject.toml +5 -1
  12. {confkit-2.0.0 → confkit-2.1.0}/src/confkit/config.py +136 -136
  13. {confkit-2.0.0 → confkit-2.1.0}/src/confkit/data_types.py +132 -108
  14. {confkit-2.0.0 → confkit-2.1.0}/src/confkit/ext/parsers.py +54 -50
  15. {confkit-2.0.0 → confkit-2.1.0}/tests/test_data_types.py +67 -1
  16. {confkit-2.0.0 → confkit-2.1.0}/tests/test_on_file_change.py +3 -1
  17. confkit-2.1.0/uv.lock +1249 -0
  18. confkit-2.0.0/.github/workflows/docs.yml +0 -61
  19. confkit-2.0.0/.github/workflows/lint.yml +0 -40
  20. {confkit-2.0.0 → confkit-2.1.0}/.bumpversion.toml +0 -0
  21. {confkit-2.0.0 → confkit-2.1.0}/.github/FUNDING.yml +0 -0
  22. {confkit-2.0.0 → confkit-2.1.0}/.github/copilot-instructions.md +0 -0
  23. {confkit-2.0.0 → confkit-2.1.0}/.github/dependabot.yml +0 -0
  24. {confkit-2.0.0 → confkit-2.1.0}/.github/workflows/bump-version-by-labels.yml +0 -0
  25. {confkit-2.0.0 → confkit-2.1.0}/.github/workflows/coverage.yml +0 -0
  26. {confkit-2.0.0 → confkit-2.1.0}/.github/workflows/pypi.yml +0 -0
  27. {confkit-2.0.0 → confkit-2.1.0}/.github/workflows/release.yml +0 -0
  28. {confkit-2.0.0 → confkit-2.1.0}/.python-version +0 -0
  29. {confkit-2.0.0 → confkit-2.1.0}/.vscode/settings.json +0 -0
  30. {confkit-2.0.0 → confkit-2.1.0}/README.md +0 -0
  31. {confkit-2.0.0 → confkit-2.1.0}/docs/examples/argparse.md +0 -0
  32. {confkit-2.0.0 → confkit-2.1.0}/docs/examples/basic.md +0 -0
  33. {confkit-2.0.0 → confkit-2.1.0}/docs/examples/custom_data_type.md +0 -0
  34. {confkit-2.0.0 → confkit-2.1.0}/docs/examples/data_types.md +0 -0
  35. {confkit-2.0.0 → confkit-2.1.0}/docs/examples/decorators.md +0 -0
  36. {confkit-2.0.0 → confkit-2.1.0}/docs/examples/enums.md +0 -0
  37. {confkit-2.0.0 → confkit-2.1.0}/docs/examples/index.md +0 -0
  38. {confkit-2.0.0 → confkit-2.1.0}/docs/examples/list_types.md +0 -0
  39. {confkit-2.0.0 → confkit-2.1.0}/docs/examples/optional_values.md +0 -0
  40. {confkit-2.0.0 → confkit-2.1.0}/docs/index.md +0 -0
  41. {confkit-2.0.0 → confkit-2.1.0}/docs/reference/config.md +0 -0
  42. {confkit-2.0.0 → confkit-2.1.0}/docs/reference/data_types.md +0 -0
  43. {confkit-2.0.0 → confkit-2.1.0}/docs/reference/exceptions.md +0 -0
  44. {confkit-2.0.0 → confkit-2.1.0}/docs/reference/notes_two_instances.md +0 -0
  45. {confkit-2.0.0 → confkit-2.1.0}/docs/usage.md +0 -0
  46. {confkit-2.0.0 → confkit-2.1.0}/examples/api.ini +0 -0
  47. {confkit-2.0.0 → confkit-2.1.0}/examples/argparse_example.py +0 -0
  48. {confkit-2.0.0 → confkit-2.1.0}/examples/args.ini +0 -0
  49. {confkit-2.0.0 → confkit-2.1.0}/examples/basic.py +0 -0
  50. {confkit-2.0.0 → confkit-2.1.0}/examples/config.ini +0 -0
  51. {confkit-2.0.0 → confkit-2.1.0}/examples/custom_data_type.py +0 -0
  52. {confkit-2.0.0 → confkit-2.1.0}/examples/data_types.py +0 -0
  53. {confkit-2.0.0 → confkit-2.1.0}/examples/database.ini +0 -0
  54. {confkit-2.0.0 → confkit-2.1.0}/examples/decorators.py +0 -0
  55. {confkit-2.0.0 → confkit-2.1.0}/examples/enums.py +0 -0
  56. {confkit-2.0.0 → confkit-2.1.0}/examples/example.json +0 -0
  57. {confkit-2.0.0 → confkit-2.1.0}/examples/example.toml +0 -0
  58. {confkit-2.0.0 → confkit-2.1.0}/examples/example.yaml +0 -0
  59. {confkit-2.0.0 → confkit-2.1.0}/examples/list_types.py +0 -0
  60. {confkit-2.0.0 → confkit-2.1.0}/examples/multiple_configs.py +0 -0
  61. {confkit-2.0.0 → confkit-2.1.0}/examples/nested_config.py +0 -0
  62. {confkit-2.0.0 → confkit-2.1.0}/examples/nested_example.ini +0 -0
  63. {confkit-2.0.0 → confkit-2.1.0}/examples/nested_example.json +0 -0
  64. {confkit-2.0.0 → confkit-2.1.0}/examples/nested_example.toml +0 -0
  65. {confkit-2.0.0 → confkit-2.1.0}/examples/nested_example.yaml +0 -0
  66. {confkit-2.0.0 → confkit-2.1.0}/examples/optional_values.py +0 -0
  67. {confkit-2.0.0 → confkit-2.1.0}/examples/other_file_types.py +0 -0
  68. {confkit-2.0.0 → confkit-2.1.0}/examples/pydantic_example.py +0 -0
  69. {confkit-2.0.0 → confkit-2.1.0}/examples/references.py +0 -0
  70. {confkit-2.0.0 → confkit-2.1.0}/mkdocs.yml +0 -0
  71. {confkit-2.0.0 → confkit-2.1.0}/ruff.toml +0 -0
  72. {confkit-2.0.0 → confkit-2.1.0}/src/confkit/__init__.py +0 -0
  73. {confkit-2.0.0 → confkit-2.1.0}/src/confkit/exceptions.py +0 -0
  74. {confkit-2.0.0 → confkit-2.1.0}/src/confkit/ext/__init__.py +0 -0
  75. {confkit-2.0.0 → confkit-2.1.0}/src/confkit/ext/pydantic.py +0 -0
  76. {confkit-2.0.0 → confkit-2.1.0}/src/confkit/ext/reference.py +0 -0
  77. {confkit-2.0.0 → confkit-2.1.0}/src/confkit/parsers.py +0 -0
  78. {confkit-2.0.0 → confkit-2.1.0}/src/confkit/py.typed +0 -0
  79. {confkit-2.0.0 → confkit-2.1.0}/src/confkit/sentinels.py +0 -0
  80. {confkit-2.0.0 → confkit-2.1.0}/src/confkit/watcher.py +0 -0
  81. {confkit-2.0.0 → confkit-2.1.0}/tests/__init__.py +0 -0
  82. {confkit-2.0.0 → confkit-2.1.0}/tests/conftest.py +0 -0
  83. {confkit-2.0.0 → confkit-2.1.0}/tests/test_config.py +0 -0
  84. {confkit-2.0.0 → confkit-2.1.0}/tests/test_config_classvars.py +0 -0
  85. {confkit-2.0.0 → confkit-2.1.0}/tests/test_config_decorators.py +0 -0
  86. {confkit-2.0.0 → confkit-2.1.0}/tests/test_config_detect_parser.py +0 -0
  87. {confkit-2.0.0 → confkit-2.1.0}/tests/test_enum_allowed_values.py +0 -0
  88. {confkit-2.0.0 → confkit-2.1.0}/tests/test_enum_auto_conversion.py +0 -0
  89. {confkit-2.0.0 → confkit-2.1.0}/tests/test_env_parser.py +0 -0
  90. {confkit-2.0.0 → confkit-2.1.0}/tests/test_examples_run.py +0 -0
  91. {confkit-2.0.0 → confkit-2.1.0}/tests/test_list_type.py +0 -0
  92. {confkit-2.0.0 → confkit-2.1.0}/tests/test_metaclass.py +0 -0
  93. {confkit-2.0.0 → confkit-2.1.0}/tests/test_msgspec.py +0 -0
  94. {confkit-2.0.0 → confkit-2.1.0}/tests/test_msgspecparser_branches.py +0 -0
  95. {confkit-2.0.0 → confkit-2.1.0}/tests/test_msgspecparser_no_msgspec.py +0 -0
  96. {confkit-2.0.0 → confkit-2.1.0}/tests/test_msgspecparser_read.py +0 -0
  97. {confkit-2.0.0 → confkit-2.1.0}/tests/test_msgspecparser_sections.py +0 -0
  98. {confkit-2.0.0 → confkit-2.1.0}/tests/test_multiple_configurations.py +0 -0
  99. {confkit-2.0.0 → confkit-2.1.0}/tests/test_nested_config.py +0 -0
  100. {confkit-2.0.0 → confkit-2.1.0}/tests/test_pydantic_models.py +0 -0
  101. {confkit-2.0.0 → confkit-2.1.0}/tests/test_sentinel.py +0 -0
  102. {confkit-2.0.0 → confkit-2.1.0}/tests/test_two_instances.py +0 -0
  103. {confkit-2.0.0 → confkit-2.1.0}/tests/test_unreachable_paths.py +0 -0
@@ -0,0 +1,88 @@
1
+ name: Docs
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+ types: [ opened, reopened, synchronize, closed ]
9
+ workflow_dispatch:
10
+
11
+ permissions: read-all
12
+
13
+ # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
14
+ # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
15
+ concurrency:
16
+ group: "pages-${{ github.ref_name }}"
17
+ cancel-in-progress: false
18
+
19
+ jobs:
20
+ build-docs:
21
+ runs-on: ubuntu-latest
22
+ permissions:
23
+ contents: write # Required to allow pr-preview-action to push to `gh-pages`
24
+ pull-requests: write # Required to allow pr-preview-action to add comments with the link in the PR
25
+ pages: write # Required to upload-pages-artifact op master
26
+ steps:
27
+ - uses: actions/checkout@v4
28
+
29
+ - uses: actions/setup-python@v5
30
+ if: github.event.action != 'closed'
31
+ with:
32
+ python-version: '3.12'
33
+
34
+ - name: Install uv
35
+ if: github.event.action != 'closed'
36
+ uses: astral-sh/setup-uv@v7
37
+ with:
38
+ enable-cache: true
39
+
40
+ - name: Setup Pages
41
+ if: github.event.action != 'closed'
42
+ uses: actions/configure-pages@v5
43
+
44
+ - name: Generate docs (pdoc + mkdocs)
45
+ if: github.event.action != 'closed'
46
+ env:
47
+ DOCS_BASE_URL: ${{ github.event_name == 'pull_request' && format('https://github.io{0}', github.event.number) || 'https://herogold.github.io/confkit' }}
48
+ run: |
49
+ uv sync --group docs
50
+ uv run pdoc confkit -o docs/api
51
+
52
+ # Replace all links to the production site with the PR preview URL for PRs, or leave them as-is for pushes to master
53
+ find docs/api -name "*.md" -type f -exec sed -i "s|https://herogold.github.io/confkit|$DOCS_BASE_URL|g" {} +
54
+
55
+ uv run mkdocs build -d site
56
+
57
+ # Only upload artifact if the push is on the master branch
58
+ - name: Upload artifact
59
+ if: github.ref == 'refs/heads/master'
60
+ uses: actions/upload-pages-artifact@v3
61
+ with:
62
+ path: site
63
+
64
+ # Deploy the PR preview on open/sync/reopen; remove it when the PR is closed.
65
+ # pr-preview-action defaults to `action: auto`, which detects the `closed`
66
+ # event and deletes the preview directory from gh-pages.
67
+ - name: Deploy PR Preview
68
+ if: github.event_name == 'pull_request'
69
+ uses: rossjrw/pr-preview-action@v1
70
+ with:
71
+ source-dir: site
72
+ preview-branch: gh-pages
73
+ umbrella-dir: pr-previews
74
+
75
+ deploy:
76
+ if: github.ref == 'refs/heads/master'
77
+ environment:
78
+ name: github-pages
79
+ url: ${{ steps.deployment.outputs.page_url }}
80
+ runs-on: ubuntu-latest
81
+ needs: build-docs
82
+ permissions:
83
+ pages: write # Required to update the Pages site
84
+ id-token: write # Required to OIDC verification of the deployment
85
+ steps:
86
+ - name: Deploy to GitHub Pages
87
+ id: deployment
88
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,28 @@
1
+ name: Gitleaks
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+ branches: [master]
8
+ workflow_dispatch:
9
+ workflow_call:
10
+
11
+ concurrency: gitleaks-${{ github.ref }}
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ jobs:
17
+ gitleaks:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - name: Checkout code
21
+ uses: actions/checkout@v4
22
+ with:
23
+ fetch-depth: 0
24
+
25
+ - name: Run Gitleaks
26
+ uses: gitleaks/gitleaks-action@v2
27
+ env:
28
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,70 @@
1
+ name: Type Check Public API
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+ branches: [master]
8
+ workflow_dispatch:
9
+ workflow_call:
10
+
11
+ concurrency:
12
+ group: lint-public-${{ github.ref }}
13
+ cancel-in-progress: true
14
+
15
+ permissions:
16
+ contents: read
17
+
18
+ jobs:
19
+ setup:
20
+ runs-on: ubuntu-latest
21
+ steps:
22
+ - name: Checkout code
23
+ uses: actions/checkout@v4
24
+
25
+ - name: Install uv
26
+ uses: astral-sh/setup-uv@v5
27
+ with:
28
+ enable-cache: true
29
+
30
+ - name : Install dependencies
31
+ run: uv sync --dev
32
+
33
+ lint:
34
+ needs: setup
35
+ runs-on: ubuntu-latest
36
+ strategy:
37
+ fail-fast: false
38
+ matrix:
39
+ include:
40
+ - tool: ruff
41
+ args: "check ./examples"
42
+ - tool: ty
43
+ args: "check ./examples --ignore no-matching-overload"
44
+ - tool: pyrefly
45
+ args: "check ./examples"
46
+ - tool: zuban
47
+ args: "check ./examples"
48
+ - tool: mypy
49
+ args: "./examples"
50
+ - tool: pyright
51
+ args: "./examples"
52
+ steps:
53
+ - name: Checkout code
54
+ uses: actions/checkout@v4
55
+
56
+ - name: Install uv (Should be cached from setup job)
57
+ uses: astral-sh/setup-uv@v5
58
+ with:
59
+ enable-cache: true
60
+
61
+ - name: Cache lint results
62
+ uses: actions/cache@v4
63
+ with:
64
+ path: .lint_cache
65
+ key: ${{ runner.os }}-lint-${{matrix.tool}}-${{ hashFiles('**/tests/**/*.py', 'src/**') }}
66
+ restore-keys: |
67
+ ${{ runner.os }}-lint-${{matrix.tool}}
68
+
69
+ - name: Run type checking - ${{matrix.tool}}
70
+ run: uv add ${{matrix.tool}} && uv run ${{matrix.tool}} ${{matrix.args}}
@@ -0,0 +1,66 @@
1
+ name: Lint & Type Check
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+ branches: [master]
8
+ workflow_dispatch:
9
+ workflow_call:
10
+
11
+ concurrency: lint-${{ github.ref }}
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ jobs:
17
+ setup:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - name: Checkout code
21
+ uses: actions/checkout@v4
22
+
23
+ - name: Install uv
24
+ uses: astral-sh/setup-uv@v5
25
+ with:
26
+ enable-cache: true
27
+
28
+ - name : Install dependencies
29
+ run: uv sync --dev
30
+
31
+ lint-and-check:
32
+ needs: setup
33
+ runs-on: ubuntu-latest
34
+ strategy:
35
+ fail-fast: false
36
+ matrix:
37
+ include:
38
+ - tool: ruff
39
+ args: "check ."
40
+ cache_path: ".ruff_cache"
41
+ - tool: ty
42
+ args: "check . --ignore no-matching-overload"
43
+ cache_path: ".ty_cache"
44
+ - tool: undersort
45
+ args: ". --check"
46
+ cache_path: ".undersort_cache"
47
+
48
+ steps:
49
+ - uses: actions/checkout@v4
50
+
51
+ - name: Cache lint results
52
+ id: cache-lint
53
+ uses: actions/cache@v4
54
+ with:
55
+ path: .lint_cache
56
+ key: ${{ runner.os }}-${{ matrix.tool }}-${{ hashFiles('**/tests/**/*.py', 'src/**') }}
57
+ restore-keys: |
58
+ ${{ runner.os }}-${{ matrix.tool }}-
59
+
60
+ - name: Install uv
61
+ uses: astral-sh/setup-uv@v7
62
+ with:
63
+ enable-cache: true
64
+
65
+ - name: Run ${{ matrix.tool }}
66
+ run: uv add ${{ matrix.tool }} && uv run ${{ matrix.tool }} ${{ matrix.args }}
@@ -30,8 +30,6 @@ jobs:
30
30
  with:
31
31
  path: .pytest_cache
32
32
  key: ${{ runner.os }}-pytest-${{ matrix.python-version }}-${{ hashFiles('**/tests/**/*.py', 'src/**') }}
33
- restore-keys: |
34
- ${{ runner.os }}-pytest-${{ matrix.python-version }}-
35
33
 
36
34
  - name: Install uv
37
35
  if: steps.cache-pytest.outputs.cache-hit != 'true'
@@ -206,5 +206,4 @@ __marimo__/
206
206
  # Custom ignores
207
207
  *test.ini
208
208
  .secrets
209
- uv.lock
210
209
  docs/api/
@@ -49,6 +49,12 @@ repos:
49
49
  - id: debug-statements
50
50
  files: ^src/.*\.py$
51
51
 
52
+ # Security scanning
53
+ - repo: https://github.com/gitleaks/gitleaks
54
+ rev: v8.24.2
55
+ hooks:
56
+ - id: gitleaks
57
+
52
58
  # Validate packaging metadata early
53
59
  - repo: https://github.com/abravalheri/validate-pyproject
54
60
  rev: v0.24.1
@@ -82,6 +88,12 @@ repos:
82
88
  types: [python]
83
89
  pass_filenames: false
84
90
  always_run: true
91
+ - id: undersort
92
+ name: undersort
93
+ entry: undersort
94
+ language: python
95
+ types: [python]
96
+ additional_dependencies: ["undersort"]
85
97
 
86
98
  # Spell checking (global)
87
99
  - repo: https://github.com/shellcheck-py/shellcheck-py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: confkit
3
- Version: 2.0.0
3
+ Version: 2.1.0
4
4
  Summary: Lightweight and Easy to use configuration manager for Python projects
5
5
  Author: HEROgold
6
6
  Requires-Python: >=3.11
@@ -3,6 +3,7 @@
3
3
  Basic example showing how to use the on_file_change() hook to detect changes in the configuration file.
4
4
  Copy of basic.py
5
5
  """
6
+ from typing import Literal, Any
6
7
  from random import randint
7
8
 
8
9
  from configparser import ConfigParser
@@ -17,13 +18,13 @@ Config.set_file(Path("config.ini"))
17
18
  Config.write_on_edit = True
18
19
 
19
20
 
20
- def on_api_change(origin: str, old: str, new: str) -> None:
21
+ def on_api_change(origin: Literal["get", "set"], old: str | None, new: str | None) -> None:
21
22
  if origin == "get":
22
23
  print(f"[on_file_change] API key accessed. Current value: '{new}' (previous: '{old}')")
23
24
  elif origin == "set":
24
25
  print(f"[on_file_change] API key changed from '{old}' to '{new}'. Reconnecting to API...")
25
26
 
26
- def print_change(origin, old, new) -> None:
27
+ def print_change(origin: Literal["get", "set"], old: bool, new: bool) -> None:
27
28
  print(f"Configuration file has changed! {origin=} {old=} {new=}")
28
29
 
29
30
  class AppConfig:
@@ -44,8 +45,8 @@ class AppConfig:
44
45
  # Optional string (can be empty)
45
46
  api_key = Config("", optional=True)
46
47
 
47
- debug.on_file_change = print_change
48
- api_key.on_file_change = on_api_change
48
+ debug.on_file_change = print_change # type: ignore[method-assign]
49
+ api_key.on_file_change = on_api_change # type: ignore[method-assign]
49
50
 
50
51
 
51
52
  if __name__ == "__main__":
@@ -60,4 +61,4 @@ if __name__ == "__main__":
60
61
  # This automatically saves to config.ini when write_on_edit is True
61
62
  cfg.debug = not cfg.debug
62
63
  # Set the API key
63
- cfg.api_key = randint(100000, 999999)
64
+ cfg.api_key = "my-secret-api"
@@ -1,4 +1,5 @@
1
1
  """Example of using a custom URL data type with confkit."""
2
+ from typing_extensions import override
2
3
  from pathlib import Path
3
4
  from configparser import ConfigParser
4
5
 
@@ -10,6 +11,7 @@ Config.set_file(Path("config.ini"))
10
11
  class URL(BaseDataType[ParseResult]):
11
12
  """A config value that is a URL."""
12
13
 
14
+ @override
13
15
  def convert(self, value: str) -> ParseResult:
14
16
  """Convert a string value to a URL."""
15
17
  return urlparse(value)
@@ -29,6 +31,6 @@ if __name__ == "__main__":
29
31
  print("Docs path:", app_config.docs.path)
30
32
 
31
33
  # You can also assign a new URL string
32
- app_config.homepage = "https://example.com/newpage"
34
+ app_config.homepage = urlparse("https://example.com/newpage")
33
35
  print("Updated homepage:", app_config.homepage)
34
36
  print("Updated homepage netloc:", app_config.homepage.netloc)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "confkit"
3
- version = "2.0.0"
3
+ version = "2.1.0"
4
4
  description = "Lightweight and Easy to use configuration manager for Python projects"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -56,3 +56,7 @@ exclude = ["tests"]
56
56
 
57
57
  [tool.ty.rules]
58
58
  invalid-assignment = "ignore"
59
+
60
+ [tool.undersort]
61
+ order = ["public", "protected", "private"]
62
+ method_type_order = ["instance", "class", "static"]