birling 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 (44) hide show
  1. birling-0.1.0/.github/workflows/ci.yml +69 -0
  2. birling-0.1.0/.gitignore +41 -0
  3. birling-0.1.0/.python-version +1 -0
  4. birling-0.1.0/.readthedocs.yaml +21 -0
  5. birling-0.1.0/CHANGELOG.md +22 -0
  6. birling-0.1.0/LICENSE.txt +21 -0
  7. birling-0.1.0/PKG-INFO +82 -0
  8. birling-0.1.0/README.md +56 -0
  9. birling-0.1.0/birling/__init__.py +6 -0
  10. birling-0.1.0/birling/__main__.py +7 -0
  11. birling-0.1.0/birling/analysis.py +489 -0
  12. birling-0.1.0/birling/cli.py +109 -0
  13. birling-0.1.0/birling/config.py +273 -0
  14. birling-0.1.0/birling/measurement.py +240 -0
  15. birling-0.1.0/birling/py.typed +0 -0
  16. birling-0.1.0/birling/recognition.py +239 -0
  17. birling-0.1.0/birling/report.py +136 -0
  18. birling-0.1.0/birling/runtime.py +48 -0
  19. birling-0.1.0/birling/syntax.py +114 -0
  20. birling-0.1.0/docs/changelog.md +1 -0
  21. birling-0.1.0/docs/configuration.md +66 -0
  22. birling-0.1.0/docs/how-it-works.md +69 -0
  23. birling-0.1.0/docs/index.md +59 -0
  24. birling-0.1.0/docs/reference.md +61 -0
  25. birling-0.1.0/docs/usage.md +103 -0
  26. birling-0.1.0/justfile +83 -0
  27. birling-0.1.0/mkdocs.yml +47 -0
  28. birling-0.1.0/pyproject.toml +199 -0
  29. birling-0.1.0/release-notes/README.md +35 -0
  30. birling-0.1.0/scripts/extract_changelog.py +43 -0
  31. birling-0.1.0/tests/__init__.py +0 -0
  32. birling-0.1.0/tests/unit/__init__.py +0 -0
  33. birling-0.1.0/tests/unit/conftest.py +33 -0
  34. birling-0.1.0/tests/unit/test_analysis.py +519 -0
  35. birling-0.1.0/tests/unit/test_cli.py +189 -0
  36. birling-0.1.0/tests/unit/test_config.py +207 -0
  37. birling-0.1.0/tests/unit/test_main.py +16 -0
  38. birling-0.1.0/tests/unit/test_measurement.py +467 -0
  39. birling-0.1.0/tests/unit/test_package.py +20 -0
  40. birling-0.1.0/tests/unit/test_recognition.py +243 -0
  41. birling-0.1.0/tests/unit/test_report.py +171 -0
  42. birling-0.1.0/tests/unit/test_runtime.py +46 -0
  43. birling-0.1.0/tests/unit/test_syntax.py +133 -0
  44. birling-0.1.0/uv.lock +1418 -0
@@ -0,0 +1,69 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ tags: ["[0-9]+.[0-9]+.[0-9]+*"]
7
+ pull_request:
8
+
9
+ concurrency:
10
+ group: ${{ github.workflow }}-${{ github.ref }}
11
+ cancel-in-progress: true
12
+
13
+ jobs:
14
+ checks:
15
+ name: checks + docs
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@v7
19
+ - uses: astral-sh/setup-uv@v10.3.0
20
+ with:
21
+ enable-cache: true
22
+ - uses: extractions/setup-just@v4
23
+ - run: just check
24
+ - run: just docs-build
25
+
26
+ test:
27
+ name: test (${{ matrix.toxenv }})
28
+ runs-on: ubuntu-latest
29
+ strategy:
30
+ fail-fast: false
31
+ matrix:
32
+ toxenv: [py311, py312, py313, py314, py315]
33
+ steps:
34
+ - uses: actions/checkout@v7
35
+ - uses: astral-sh/setup-uv@v10.3.0
36
+ with:
37
+ enable-cache: true
38
+ - run: uv run tox run -e ${{ matrix.toxenv }}
39
+
40
+ publish:
41
+ name: publish
42
+ needs: [checks, test]
43
+ if: startsWith(github.ref, 'refs/tags/')
44
+ runs-on: ubuntu-latest
45
+ environment: pypi
46
+ permissions:
47
+ contents: write # create the GitHub release
48
+ id-token: write # publish to PyPI as a trusted publisher
49
+ steps:
50
+ - uses: actions/checkout@v7
51
+ with:
52
+ fetch-depth: 0 # the version comes from the tag
53
+ - uses: astral-sh/setup-uv@v10.3.0
54
+ # Outside the checkout, so the source package does not pick it up.
55
+ - run: uv run python scripts/extract_changelog.py "$GITHUB_REF_NAME" > "$RUNNER_TEMP/notes.md"
56
+ - run: uv build
57
+ # Skips files already on PyPI, so a rerun of a failed job can finish the release.
58
+ - run: uv publish --trusted-publishing always --check-url https://pypi.org/simple/birling/
59
+ - name: Create or update the GitHub release
60
+ env:
61
+ GH_TOKEN: ${{ github.token }}
62
+ run: |
63
+ PRERELEASE=""
64
+ if [[ "$GITHUB_REF_NAME" =~ (a|b|rc)[0-9]+$ ]]; then PRERELEASE="--prerelease"; fi
65
+ if gh release view "$GITHUB_REF_NAME" >/dev/null 2>&1; then
66
+ gh release edit "$GITHUB_REF_NAME" --notes-file "$RUNNER_TEMP/notes.md" $PRERELEASE
67
+ else
68
+ gh release create "$GITHUB_REF_NAME" --notes-file "$RUNNER_TEMP/notes.md" $PRERELEASE
69
+ fi
@@ -0,0 +1,41 @@
1
+ # Python bytecode
2
+ __pycache__/
3
+ *.py[cod]
4
+
5
+ # Packaging and build output
6
+ build/
7
+ dist/
8
+ wheels/
9
+ *.egg-info/
10
+ requirements.txt
11
+
12
+ # Environments
13
+ .venv/
14
+ .env
15
+
16
+ # Tests and coverage
17
+ .pytest_cache/
18
+ .tox/
19
+ .hypothesis/
20
+ .coverage
21
+ .coverage.*
22
+ htmlcov/
23
+ coverage.xml
24
+ test-reports/
25
+
26
+ # Documentation build output
27
+ site/
28
+
29
+ # Tool caches
30
+ .ruff_cache/
31
+ .pyrefly_cache/
32
+
33
+ # Editors and OS
34
+ .idea/
35
+ .vscode/
36
+ .DS_Store
37
+
38
+ # Agent instructions and settings, kept per checkout
39
+ CLAUDE.md
40
+ AGENTS.md
41
+ .claude/
@@ -0,0 +1 @@
1
+ 3.14
@@ -0,0 +1,21 @@
1
+ # Read the Docs configuration file
2
+ # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
3
+
4
+ version: 2
5
+
6
+ build:
7
+ os: ubuntu-lts-latest
8
+ tools:
9
+ python: "latest"
10
+ jobs:
11
+ pre_create_environment:
12
+ - asdf plugin add uv
13
+ - asdf install uv latest
14
+ - asdf global uv latest
15
+ create_environment:
16
+ - uv venv "${READTHEDOCS_VIRTUALENV_PATH}"
17
+ install:
18
+ - UV_PROJECT_ENVIRONMENT="${READTHEDOCS_VIRTUALENV_PATH}" uv sync --frozen --no-default-groups --group docs
19
+
20
+ mkdocs:
21
+ configuration: mkdocs.yml
@@ -0,0 +1,22 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ Unreleased changes are kept as news fragments in `release-notes/`, and collated into a dated section by towncrier at release time.
8
+
9
+ <!-- towncrier release notes start -->
10
+
11
+ ## [0.1.0] - 2026-10-13
12
+
13
+ ### Added
14
+
15
+ - The `birling` command, which finds the branches in a project's code that should log, checks whether each holds a log call, and reports a score for each module and in total:
16
+
17
+ - A minimum score, `fail-under` in the configuration or `--fail-under`, below which the command exits with status 1, so that a CI run can hold to it.
18
+ - Configuration in the `[tool.birling]` table of `pyproject.toml`: which kinds of branch should log, which exceptions never need a log, and how log calls are recognised, covering `logging`, structlog, loguru and a project's own helpers.
19
+ - A `# birling: ignore` comment on the line that opens a branch, which accepts that branch without a log.
20
+ - `--show-unlogged`, which lists each unlogged branch as `path:line`, with its unit and how the branch is selected.
21
+ - `--coverage-file`, which marks the unlogged branches that ran in the tests, read from coverage.py's data; it needs the `coverage` extra.
22
+ - A Python interface, `measure_source()` and `measure_paths()`, which the command is built on.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026-present Berislav Lopac <berislav@lopac.net>
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.
birling-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,82 @@
1
+ Metadata-Version: 2.5
2
+ Name: birling
3
+ Version: 0.1.0
4
+ Summary: Measure how well Python code is covered by log calls.
5
+ Project-URL: documentation, https://birling.readthedocs.io
6
+ Project-URL: repository, https://github.com/berislavlopac/birling
7
+ Project-URL: issues, https://github.com/berislavlopac/birling/issues
8
+ Project-URL: changelog, https://birling.readthedocs.io/en/stable/changelog.html
9
+ Author-email: Berislav Lopac <berislav@lopac.net>
10
+ License-Expression: MIT
11
+ License-File: LICENSE.txt
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Programming Language :: Python
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
18
+ Classifier: Programming Language :: Python :: 3.15
19
+ Classifier: Programming Language :: Python :: Implementation :: CPython
20
+ Classifier: Topic :: Software Development :: Quality Assurance
21
+ Classifier: Topic :: System :: Logging
22
+ Requires-Python: >=3.11
23
+ Provides-Extra: coverage
24
+ Requires-Dist: coverage>=7.16.2; extra == 'coverage'
25
+ Description-Content-Type: text/markdown
26
+
27
+ # birling
28
+
29
+ birling measures log coverage in Python projects: how well the code is covered by log calls, whether through the standard [`logging`](https://docs.python.org/3/library/logging.html) module, [structlog](https://www.structlog.org/), [loguru](https://github.com/Delgan/loguru) or a project's own helpers, the way [coverage.py](https://coverage.readthedocs.io/) measures how well it is covered by tests.
30
+
31
+ A handled exception that leaves no log is a failure nobody hears about. birling finds the places in the code where something should be logged, checks whether a log call is there, and gives the project a score that a CI run can hold to a minimum. By default, those places are `except` handlers that do not raise again.
32
+
33
+ ```shell
34
+ $ birling shop
35
+ Name Branches Logged Score Unlogged
36
+ ---------------------------------------------------
37
+ shop/orders.py 2 1 50% 12
38
+ shop/payments.py 2 1 50% 12
39
+ ---------------------------------------------------
40
+ TOTAL 4 2 50%
41
+ ```
42
+
43
+ ## Installation
44
+
45
+ birling needs Python 3.11 or later and has no dependencies of its own. Install it from PyPI:
46
+
47
+ ```shell
48
+ pip install birling
49
+ ```
50
+
51
+ The `coverage` extra, `birling[coverage]`, adds coverage.py, which the command needs to mark the unlogged branches that ran in the tests.
52
+
53
+ ## Usage
54
+
55
+ ```shell
56
+ birling PATH... [--config FILE] [--fail-under SCORE] [--coverage-file FILE] [--show-unlogged]
57
+ ```
58
+
59
+ The command reads its configuration from the `[tool.birling]` table of `pyproject.toml`, and exits with status 1 when the score is below the minimum:
60
+
61
+ ```toml
62
+ [tool.birling]
63
+ fail-under = 80
64
+ ```
65
+
66
+ The standard `logging` module needs no configuration; other logging libraries and a project's own logging helpers are described in the table.
67
+
68
+ ## Documentation
69
+
70
+ The documentation covers the command, the configuration, how branches and log calls are found, and the Python interface. It is in `docs/`; `just docs` serves it locally.
71
+
72
+ ## The name
73
+
74
+ > Log rolling, sometimes called birling, is a sparring sport involving two competitors, each standing on one end of a free-floating log in a body of water. The two battle to dislodge each other from the log while keeping their own footing on it by spinning and kicking it and various other means.
75
+ >
76
+ > — Wikipedia, [Logrolling (sport)](https://en.wikipedia.org/wiki/Logrolling_%28sport%29)
77
+
78
+ The lumberjacks' sport lends its name to a tool for keeping on top of a project's logs.
79
+
80
+ ## Status
81
+
82
+ birling is experimental: its interface may change before the first release.
@@ -0,0 +1,56 @@
1
+ # birling
2
+
3
+ birling measures log coverage in Python projects: how well the code is covered by log calls, whether through the standard [`logging`](https://docs.python.org/3/library/logging.html) module, [structlog](https://www.structlog.org/), [loguru](https://github.com/Delgan/loguru) or a project's own helpers, the way [coverage.py](https://coverage.readthedocs.io/) measures how well it is covered by tests.
4
+
5
+ A handled exception that leaves no log is a failure nobody hears about. birling finds the places in the code where something should be logged, checks whether a log call is there, and gives the project a score that a CI run can hold to a minimum. By default, those places are `except` handlers that do not raise again.
6
+
7
+ ```shell
8
+ $ birling shop
9
+ Name Branches Logged Score Unlogged
10
+ ---------------------------------------------------
11
+ shop/orders.py 2 1 50% 12
12
+ shop/payments.py 2 1 50% 12
13
+ ---------------------------------------------------
14
+ TOTAL 4 2 50%
15
+ ```
16
+
17
+ ## Installation
18
+
19
+ birling needs Python 3.11 or later and has no dependencies of its own. Install it from PyPI:
20
+
21
+ ```shell
22
+ pip install birling
23
+ ```
24
+
25
+ The `coverage` extra, `birling[coverage]`, adds coverage.py, which the command needs to mark the unlogged branches that ran in the tests.
26
+
27
+ ## Usage
28
+
29
+ ```shell
30
+ birling PATH... [--config FILE] [--fail-under SCORE] [--coverage-file FILE] [--show-unlogged]
31
+ ```
32
+
33
+ The command reads its configuration from the `[tool.birling]` table of `pyproject.toml`, and exits with status 1 when the score is below the minimum:
34
+
35
+ ```toml
36
+ [tool.birling]
37
+ fail-under = 80
38
+ ```
39
+
40
+ The standard `logging` module needs no configuration; other logging libraries and a project's own logging helpers are described in the table.
41
+
42
+ ## Documentation
43
+
44
+ The documentation covers the command, the configuration, how branches and log calls are found, and the Python interface. It is in `docs/`; `just docs` serves it locally.
45
+
46
+ ## The name
47
+
48
+ > Log rolling, sometimes called birling, is a sparring sport involving two competitors, each standing on one end of a free-floating log in a body of water. The two battle to dislodge each other from the log while keeping their own footing on it by spinning and kicking it and various other means.
49
+ >
50
+ > — Wikipedia, [Logrolling (sport)](https://en.wikipedia.org/wiki/Logrolling_%28sport%29)
51
+
52
+ The lumberjacks' sport lends its name to a tool for keeping on top of a project's logs.
53
+
54
+ ## Status
55
+
56
+ birling is experimental: its interface may change before the first release.
@@ -0,0 +1,6 @@
1
+ """Measure how well Python code is covered by log calls."""
2
+
3
+ from importlib.metadata import version
4
+
5
+ __version__ = version("birling")
6
+ """The installed distribution's version, derived from the git tag it was built from."""
@@ -0,0 +1,7 @@
1
+ """Run the `birling` command as `python -m birling`."""
2
+
3
+ import sys
4
+
5
+ from birling.cli import main
6
+
7
+ sys.exit(main())