d8s-timer 0.5.0__tar.gz → 0.6.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 (48) hide show
  1. {d8s_timer-0.5.0 → d8s_timer-0.6.0}/.coveragerc +0 -1
  2. d8s_timer-0.6.0/.github/dependabot.yml +8 -0
  3. d8s_timer-0.5.0/.github/workflows/pytest.yml → d8s_timer-0.6.0/.github/workflows/ci.yml +33 -17
  4. d8s_timer-0.6.0/.github/workflows/dependabot-auto-merge.yml +67 -0
  5. d8s_timer-0.6.0/.github/workflows/lint.yml +32 -0
  6. d8s_timer-0.6.0/.github/workflows/release-please.yml +51 -0
  7. d8s_timer-0.6.0/.release-please-manifest.json +3 -0
  8. d8s_timer-0.6.0/AGENTS.md +38 -0
  9. d8s_timer-0.6.0/CHANGELOG.md +8 -0
  10. d8s_timer-0.6.0/CLAUDE.md +1 -0
  11. d8s_timer-0.6.0/PKG-INFO +94 -0
  12. {d8s_timer-0.5.0 → d8s_timer-0.6.0}/README.md +1 -1
  13. d8s_timer-0.6.0/d8s_timer/__init__.py +5 -0
  14. {d8s_timer-0.5.0 → d8s_timer-0.6.0}/d8s_timer/timer.py +4 -3
  15. d8s_timer-0.6.0/docker/lint.sh +19 -0
  16. d8s_timer-0.6.0/pyproject.toml +67 -0
  17. d8s_timer-0.6.0/release-please-config.json +24 -0
  18. {d8s_timer-0.5.0 → d8s_timer-0.6.0}/tests/test_timer.py +5 -5
  19. d8s_timer-0.6.0/uv.lock +1621 -0
  20. d8s_timer-0.5.0/.github/dependabot.yml +0 -9
  21. d8s_timer-0.5.0/.github/workflows/lint.yaml +0 -26
  22. d8s_timer-0.5.0/.github/workflows/pypi-publish.yml +0 -34
  23. d8s_timer-0.5.0/Dockerfile +0 -9
  24. d8s_timer-0.5.0/PKG-INFO +0 -91
  25. d8s_timer-0.5.0/bumpversion.dockerfile +0 -9
  26. d8s_timer-0.5.0/d8s_timer/__init__.py +0 -5
  27. d8s_timer-0.5.0/d8s_timer.egg-info/PKG-INFO +0 -91
  28. d8s_timer-0.5.0/d8s_timer.egg-info/SOURCES.txt +0 -33
  29. d8s_timer-0.5.0/d8s_timer.egg-info/dependency_links.txt +0 -1
  30. d8s_timer-0.5.0/d8s_timer.egg-info/requires.txt +0 -5
  31. d8s_timer-0.5.0/d8s_timer.egg-info/top_level.txt +0 -2
  32. d8s_timer-0.5.0/d8s_timer.egg-info/zip-safe +0 -1
  33. d8s_timer-0.5.0/docker/lint.sh +0 -20
  34. d8s_timer-0.5.0/docker-compose.yml +0 -46
  35. d8s_timer-0.5.0/mypy.ini +0 -2
  36. d8s_timer-0.5.0/pyproject.toml +0 -20
  37. d8s_timer-0.5.0/requirements.txt +0 -3
  38. d8s_timer-0.5.0/requirements_dev.txt +0 -14
  39. d8s_timer-0.5.0/setup.cfg +0 -22
  40. d8s_timer-0.5.0/setup.py +0 -45
  41. {d8s_timer-0.5.0 → d8s_timer-0.6.0}/.editorconfig +0 -0
  42. {d8s_timer-0.5.0 → d8s_timer-0.6.0}/.github/workflows/new-issues-to-backlog-project.yml +0 -0
  43. {d8s_timer-0.5.0 → d8s_timer-0.6.0}/.gitignore +0 -0
  44. {d8s_timer-0.5.0 → d8s_timer-0.6.0}/COPYING +0 -0
  45. {d8s_timer-0.5.0 → d8s_timer-0.6.0}/COPYING.LESSER +0 -0
  46. {d8s_timer-0.5.0 → d8s_timer-0.6.0}/conftest.py +0 -0
  47. {d8s_timer-0.5.0 → d8s_timer-0.6.0}/d8s_timer/timer_temp_utils.py +0 -0
  48. {d8s_timer-0.5.0 → d8s_timer-0.6.0}/tests/__init__.py +0 -0
@@ -1,5 +1,4 @@
1
1
  [run]
2
2
  omit =
3
3
  tests/*
4
- setup.py
5
4
  conftest.py
@@ -0,0 +1,8 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "uv"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ commit-message:
8
+ prefix: "deps"
@@ -9,48 +9,64 @@ on:
9
9
  pull_request:
10
10
  branches: [ main ]
11
11
 
12
+ concurrency:
13
+ group: ${{ github.workflow }}-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
12
16
  jobs:
13
- build_multi_os:
17
+ build_smoke:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - name: Set up Python 3.14
22
+ uses: actions/setup-python@v5
23
+ with:
24
+ python-version: '3.14'
25
+ - name: Set up uv
26
+ uses: astral-sh/setup-uv@v6
27
+ - name: Build package
28
+ run: uv build
14
29
 
30
+ build_multi_os:
15
31
  runs-on: ${{ matrix.os }}
16
32
  strategy:
17
33
  matrix:
18
34
  os: [macos-latest, windows-latest, ubuntu-latest]
19
- python-version: [3.9]
35
+ python-version: ['3.14']
20
36
 
21
37
  steps:
22
- - uses: actions/checkout@v2
38
+ - uses: actions/checkout@v4
23
39
  - name: Set up Python ${{ matrix.python-version }}
24
- uses: actions/setup-python@v2
40
+ uses: actions/setup-python@v5
25
41
  with:
26
42
  python-version: ${{ matrix.python-version }}
43
+ - name: Set up uv
44
+ uses: astral-sh/setup-uv@v6
27
45
  - name: Install dependencies
28
- run: |
29
- python -m pip install -r requirements.txt
30
- python -m pip install -r requirements_dev.txt
46
+ run: uv sync --locked --group dev
31
47
  - name: Run pytest
32
48
  run: |
33
- pytest
34
- codecov
49
+ uv run pytest
50
+ uv run codecov
35
51
 
36
52
  build_multi_py_versions:
37
53
  runs-on: ${{ matrix.os }}
38
54
  strategy:
39
55
  matrix:
40
56
  os: [ubuntu-latest]
41
- python-version: [3.6, 3.7, 3.8, 3.9]
57
+ python-version: ['3.10', '3.11', '3.12', '3.13', '3.14']
42
58
 
43
59
  steps:
44
- - uses: actions/checkout@v2
60
+ - uses: actions/checkout@v4
45
61
  - name: Set up Python ${{ matrix.python-version }}
46
- uses: actions/setup-python@v2
62
+ uses: actions/setup-python@v5
47
63
  with:
48
64
  python-version: ${{ matrix.python-version }}
65
+ - name: Set up uv
66
+ uses: astral-sh/setup-uv@v6
49
67
  - name: Install dependencies
50
- run: |
51
- python -m pip install -r requirements.txt
52
- python -m pip install -r requirements_dev.txt
68
+ run: uv sync --locked --group dev
53
69
  - name: Run pytest
54
70
  run: |
55
- pytest
56
- codecov
71
+ uv run pytest
72
+ uv run codecov
@@ -0,0 +1,67 @@
1
+ name: Dependabot auto-merge
2
+
3
+ on:
4
+ pull_request_target:
5
+ schedule:
6
+ - cron: "11 11 * * *"
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: write
11
+ pull-requests: write
12
+
13
+ jobs:
14
+ label:
15
+ if: github.event_name == 'pull_request_target' && github.actor == 'dependabot[bot]'
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - name: Fetch Dependabot metadata
19
+ id: meta
20
+ uses: dependabot/fetch-metadata@v2
21
+
22
+ - name: Ensure labels exist
23
+ env:
24
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
25
+ run: |
26
+ gh label create auto-merge-candidate --color ededed --description "Dependabot dev-dep PR eligible for auto-merge after soak" --force --repo "$GITHUB_REPOSITORY"
27
+ gh label create needs-manual-merge --color d93f0b --description "Dependabot PR not eligible for auto-merge; needs manual review" --force --repo "$GITHUB_REPOSITORY"
28
+
29
+ - name: Label auto-merge candidates
30
+ if: steps.meta.outputs.dependency-type == 'direct:development' && (steps.meta.outputs.update-type == 'version-update:semver-patch' || steps.meta.outputs.update-type == 'version-update:semver-minor')
31
+ env:
32
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
33
+ PR_URL: ${{ github.event.pull_request.html_url }}
34
+ run: gh pr edit "$PR_URL" --add-label auto-merge-candidate
35
+
36
+ - name: Label PRs needing manual review
37
+ if: ${{ !(steps.meta.outputs.dependency-type == 'direct:development' && (steps.meta.outputs.update-type == 'version-update:semver-patch' || steps.meta.outputs.update-type == 'version-update:semver-minor')) }}
38
+ env:
39
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
40
+ PR_URL: ${{ github.event.pull_request.html_url }}
41
+ run: gh pr edit "$PR_URL" --add-label needs-manual-merge
42
+
43
+ soak-and-merge:
44
+ if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
45
+ runs-on: ubuntu-latest
46
+ env:
47
+ SOAK_DAYS: 3
48
+ steps:
49
+ - name: Enable auto-merge on soaked PRs
50
+ env:
51
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
52
+ run: |
53
+ cutoff=$(date -u -d "${SOAK_DAYS} days ago" +%Y-%m-%dT%H:%M:%SZ)
54
+ gh pr list \
55
+ --repo "$GITHUB_REPOSITORY" \
56
+ --author "app/dependabot" \
57
+ --label auto-merge-candidate \
58
+ --state open \
59
+ --json number,createdAt,autoMergeRequest \
60
+ --jq ".[] | select(.createdAt < \"$cutoff\") | .number" \
61
+ | while read -r pr; do
62
+ auto=$(gh pr view "$pr" --repo "$GITHUB_REPOSITORY" --json autoMergeRequest --jq .autoMergeRequest)
63
+ if [ "$auto" = "null" ] || [ -z "$auto" ]; then
64
+ echo "Enabling auto-merge on PR #$pr"
65
+ gh pr merge "$pr" --auto --squash --repo "$GITHUB_REPOSITORY" || echo "Failed to enable auto-merge on PR #$pr"
66
+ fi
67
+ done
@@ -0,0 +1,32 @@
1
+ # This workflow will install Python dependencies and lint the code with ruff and mypy
2
+ # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
3
+
4
+ name: Lint
5
+
6
+ on:
7
+ push:
8
+ branches: [ main ]
9
+ pull_request:
10
+ branches: [ main ]
11
+
12
+ concurrency:
13
+ group: ${{ github.workflow }}-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ jobs:
17
+ build:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - name: Set up Python
22
+ uses: actions/setup-python@v5
23
+ with:
24
+ python-version: '3.14'
25
+ - name: Set up uv
26
+ uses: astral-sh/setup-uv@v6
27
+ - name: Install dependencies
28
+ run: uv sync --locked --group dev
29
+ - name: Lint
30
+ env:
31
+ CONTEXT: ci
32
+ run: ./docker/lint.sh
@@ -0,0 +1,51 @@
1
+ # Conventional-commit release automation.
2
+ # On every push to main, release-please maintains a release PR (CHANGELOG +
3
+ # version bump in pyproject.toml + d8s_lists/__init__.py). Merging that PR
4
+ # tags vX.Y.Z and creates the GitHub Release; this same run then builds and
5
+ # publishes to PyPI via OIDC.
6
+ #
7
+ # Publish is folded into THIS workflow on purpose: a tag pushed by
8
+ # release-please uses GITHUB_TOKEN, which does NOT trigger a separate
9
+ # tag-triggered workflow. Gating on release_created keeps OIDC (no PAT/secrets).
10
+
11
+ name: release-please
12
+
13
+ on:
14
+ push:
15
+ branches:
16
+ - main
17
+
18
+ permissions:
19
+ contents: write # create release PR, tag, and GitHub Release
20
+ pull-requests: write # open/update the release PR
21
+
22
+ jobs:
23
+ release-please:
24
+ runs-on: ubuntu-latest
25
+ outputs:
26
+ release_created: ${{ steps.release.outputs.release_created }}
27
+ tag_name: ${{ steps.release.outputs.tag_name }}
28
+ steps:
29
+ - uses: googleapis/release-please-action@v4
30
+ id: release
31
+ with:
32
+ config-file: release-please-config.json
33
+ manifest-file: .release-please-manifest.json
34
+
35
+ publish:
36
+ needs: release-please
37
+ if: needs.release-please.outputs.release_created == 'true'
38
+ runs-on: ubuntu-latest
39
+ permissions:
40
+ id-token: write # required for OIDC trusted publishing
41
+ contents: read
42
+ steps:
43
+ - uses: actions/checkout@v4
44
+ with:
45
+ ref: ${{ needs.release-please.outputs.tag_name }}
46
+ - name: Set up uv
47
+ uses: astral-sh/setup-uv@v6
48
+ - name: Build
49
+ run: uv build
50
+ - name: Publish to PyPI
51
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.6.0"
3
+ }
@@ -0,0 +1,38 @@
1
+ # AGENTS.md
2
+
3
+ ## Commit messages: use Conventional Commits
4
+
5
+ Releases are automated by [release-please](https://github.com/googleapis/release-please).
6
+ It reads commit messages to bump the version, write `CHANGELOG.md`, tag, and publish to
7
+ PyPI. **Non-conventional commits are silently ignored** — no version bump, absent from the
8
+ changelog.
9
+
10
+ Format: `type: description` (optionally `type(scope): description`).
11
+
12
+ Common types and their effect on the release:
13
+
14
+ | Type | Effect | Changelog section |
15
+ |------|--------|-------------------|
16
+ | `feat:` | minor bump (0.8.0 → 0.9.0) | Features |
17
+ | `fix:` | patch bump (0.8.0 → 0.8.1) | Bug Fixes |
18
+ | `perf:` | patch bump | Performance Improvements |
19
+ | `deps:` | no bump (rides next release) | Dependencies |
20
+ | `docs:` `refactor:` `test:` `chore:` `ci:` `build:` `style:` | no bump | hidden |
21
+
22
+ Breaking change: append `!` (`feat!: ...`) or add a `BREAKING CHANGE:` footer → major bump.
23
+
24
+ Examples:
25
+
26
+ ```
27
+ feat: add iterable_chunk
28
+ fix: cycle() returns empty when length is 0
29
+ feat!: rename list_flatten to iterable_flatten
30
+ ```
31
+
32
+ Prefer squash-merging PRs so the PR title becomes the single conventional commit.
33
+
34
+ ## Releasing
35
+
36
+ Don't bump versions, edit `CHANGELOG.md`, or create tags by hand — release-please owns all
37
+ three. To cut a release, merge the open `chore: release X.Y.Z` PR; that tags the version,
38
+ creates the GitHub Release, and publishes to PyPI via OIDC.
@@ -0,0 +1,8 @@
1
+ # Changelog
2
+
3
+ ## [0.6.0](https://github.com/democritus-project/d8s-timer/compare/v0.5.0...v0.6.0) (2026-07-01)
4
+
5
+
6
+ ### Features
7
+
8
+ * modernize tooling and release automation ([6020b86](https://github.com/democritus-project/d8s-timer/commit/6020b860d7e64a169542727a9eb4bd30ea4056bd))
@@ -0,0 +1 @@
1
+ Read AGENTS.md in the repository root and follow it.
@@ -0,0 +1,94 @@
1
+ Metadata-Version: 2.4
2
+ Name: d8s_timer
3
+ Version: 0.6.0
4
+ Summary: Democritus functions for working with timers.
5
+ Project-URL: Source, https://github.com/democritus-project/d8s-timer
6
+ Project-URL: Issues, https://github.com/democritus-project/d8s-timer/issues
7
+ Author: Floyd Hightower
8
+ License: GNU Lesser General Public License v3
9
+ License-File: COPYING
10
+ License-File: COPYING.LESSER
11
+ Keywords: clock,democritus,python,time,timers,timers-utility,utility
12
+ Classifier: Development Status :: 2 - Pre-Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)
15
+ Classifier: Natural Language :: English
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Requires-Python: >=3.10
23
+ Requires-Dist: d8s-dates<1.0,>=0.7.0
24
+ Requires-Dist: d8s-uuids<1.0,>=0.6.0
25
+ Description-Content-Type: text/markdown
26
+
27
+ # Democritus Timer
28
+
29
+ [![PyPI](https://img.shields.io/pypi/v/d8s-timer.svg)](https://pypi.python.org/pypi/d8s-timer)
30
+ [![CI](https://github.com/democritus-project/d8s-timer/workflows/CI/badge.svg)](https://github.com/democritus-project/d8s-timer/actions)
31
+ [![Lint](https://github.com/democritus-project/d8s-timer/workflows/Lint/badge.svg)](https://github.com/democritus-project/d8s-timer/actions)
32
+ [![codecov](https://codecov.io/gh/democritus-project/d8s-timer/branch/main/graph/badge.svg?token=V0WOIXRGMM)](https://codecov.io/gh/democritus-project/d8s-timer)
33
+ [![The Democritus Project uses semver version 2.0.0](https://img.shields.io/badge/-semver%20v2.0.0-22bfda)](https://semver.org/spec/v2.0.0.html)
34
+ [![The Democritus Project uses ruff to format and lint code](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
35
+ [![License: LGPL v3](https://img.shields.io/badge/License-LGPL%20v3-blue.svg)](https://choosealicense.com/licenses/lgpl-3.0/)
36
+
37
+ Democritus functions<sup>[1]</sup> for working with timers.
38
+
39
+ [1] Democritus functions are <i>simple, effective, modular, well-tested, and well-documented</i> Python functions.
40
+
41
+ We use `d8s` (pronounced "dee-eights") as an abbreviation for `democritus` (you can read more about this [here](https://github.com/democritus-project/roadmap#what-is-d8s)).
42
+
43
+ ## Installation
44
+
45
+ ```
46
+ pip install d8s-timer
47
+ ```
48
+
49
+ ## Usage
50
+
51
+ You import the library like:
52
+
53
+ ```python
54
+ from d8s_timer import *
55
+ ```
56
+
57
+ Once imported, you can use any of the functions listed below.
58
+
59
+ ## Functions
60
+
61
+ - ```python
62
+ def timer_start(name: str = None) -> str:
63
+ """Start a timer with the given name. Timers can be stopped with the `timer_stop` function."""
64
+ ```
65
+ - ```python
66
+ def timer_get_time(name: str) -> float:
67
+ """Get the current time for the timer with the given name."""
68
+ ```
69
+ - ```python
70
+ def timer_stop(name: str) -> float:
71
+ """Stop a timer (you can start a timer with the `timer_start` function)."""
72
+ ```
73
+ - ```python
74
+ def time_it(func):
75
+ """Return the time it takes func to execute."""
76
+ ```
77
+
78
+ ## Development
79
+
80
+ 👋 &nbsp;If you want to get involved in this project, we have some short, helpful guides below:
81
+
82
+ - [contribute to this project 🥇][contributing]
83
+ - [test it 🧪][local-dev]
84
+ - [lint it 🧹][local-dev]
85
+ - [explore it 🔭][local-dev]
86
+
87
+ If you have any questions or there is anything we did not cover, please raise an issue and we'll be happy to help.
88
+
89
+ ## Credits
90
+
91
+ This package was created with [Cookiecutter](https://github.com/audreyr/cookiecutter) and Floyd Hightower's [Python project template](https://github.com/fhightower-templates/python-project-template).
92
+
93
+ [contributing]: https://github.com/democritus-project/.github/blob/main/CONTRIBUTING.md#contributing-a-pr-
94
+ [local-dev]: https://github.com/democritus-project/.github/blob/main/CONTRIBUTING.md#local-development-
@@ -5,7 +5,7 @@
5
5
  [![Lint](https://github.com/democritus-project/d8s-timer/workflows/Lint/badge.svg)](https://github.com/democritus-project/d8s-timer/actions)
6
6
  [![codecov](https://codecov.io/gh/democritus-project/d8s-timer/branch/main/graph/badge.svg?token=V0WOIXRGMM)](https://codecov.io/gh/democritus-project/d8s-timer)
7
7
  [![The Democritus Project uses semver version 2.0.0](https://img.shields.io/badge/-semver%20v2.0.0-22bfda)](https://semver.org/spec/v2.0.0.html)
8
- [![The Democritus Project uses black to format code](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
8
+ [![The Democritus Project uses ruff to format and lint code](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
9
9
  [![License: LGPL v3](https://img.shields.io/badge/License-LGPL%20v3-blue.svg)](https://choosealicense.com/licenses/lgpl-3.0/)
10
10
 
11
11
  Democritus functions<sup>[1]</sup> for working with timers.
@@ -0,0 +1,5 @@
1
+ from .timer import *
2
+
3
+ __version__ = "0.6.0"
4
+ __author__ = """Floyd Hightower"""
5
+ __email__ = "floyd.hightower27@gmail.com"
@@ -1,4 +1,5 @@
1
1
  import functools
2
+ from typing import Optional
2
3
 
3
4
  from d8s_dates import time_now
4
5
  from d8s_uuids import uuid4
@@ -26,7 +27,7 @@ class Timer:
26
27
  _timer_object = Timer()
27
28
 
28
29
 
29
- def timer_start(name: str = None) -> str:
30
+ def timer_start(name: Optional[str] = None) -> str:
30
31
  """Start a timer with the given name. Timers can be stopped with the `timer_stop` function."""
31
32
  # if there is no name given, use a generic name
32
33
  if name is None:
@@ -54,7 +55,7 @@ def _get_time_difference(timer_time: int) -> float:
54
55
  def timer_get_time(name: str) -> float:
55
56
  """Get the current time for the timer with the given name."""
56
57
  if not _timer_object.has_timer(name, print_errors=True):
57
- message = f'There is no timer with the name {name}'
58
+ message = f"There is no timer with the name {name}"
58
59
  raise ValueError(message)
59
60
 
60
61
  time_difference = _get_time_difference(_timer_object.timers[name])
@@ -64,7 +65,7 @@ def timer_get_time(name: str) -> float:
64
65
  def timer_stop(name: str) -> float:
65
66
  """Stop a timer (you can start a timer with the `timer_start` function)."""
66
67
  if not _timer_object.has_timer(name, print_errors=True):
67
- message = f'There is no timer with the name {name}'
68
+ message = f"There is no timer with the name {name}"
68
69
  raise ValueError(message)
69
70
 
70
71
  time_difference = _get_time_difference(_timer_object.timers[name])
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -euxo pipefail
4
+
5
+ echo "Running linters and formatters..."
6
+
7
+ uv run ruff check --fix d8s_timer/ tests/
8
+ uv run ruff format d8s_timer/ tests/
9
+
10
+ # if the CONTEXT env var is "ci" (which is set in .github/workflows/lint.yml), validate that none of the files
11
+ # have been changed by the previous lint steps
12
+ if [ "${CONTEXT:-local}" = "ci" ]; then
13
+ (git status | grep "nothing to commit") || { echo "Lint steps have changed files"; exit 1; };
14
+ fi
15
+
16
+ uv run mypy d8s_timer/ tests/
17
+ uv run ruff check d8s_timer/ tests/
18
+
19
+ echo "Done ✨ 🎉 ✨"
@@ -0,0 +1,67 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "d8s_timer"
7
+ version = "0.6.0"
8
+ description = "Democritus functions for working with timers."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "GNU Lesser General Public License v3" }
12
+ authors = [{ name = "Floyd Hightower" }]
13
+ keywords = ["democritus", "utility", "python", "timers", "timers-utility", "time", "clock"]
14
+ classifiers = [
15
+ "Development Status :: 2 - Pre-Alpha",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)",
18
+ "Natural Language :: English",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Programming Language :: Python :: 3.14",
25
+ ]
26
+ dependencies = [
27
+ "d8s-dates>=0.7.0,<1.0",
28
+ "d8s-uuids>=0.6.0,<1.0",
29
+ ]
30
+
31
+ [project.urls]
32
+ Source = "https://github.com/democritus-project/d8s-timer"
33
+ Issues = "https://github.com/democritus-project/d8s-timer/issues"
34
+
35
+ [dependency-groups]
36
+ dev = [
37
+ "codecov>=2.1.13,<3.0",
38
+ "d8s-file-system>=0.10.0,<1.0",
39
+ "d8s-python>=0.9.0,<1.0",
40
+ "d8s-strings>=0.5.0,<1.0",
41
+ "ipython>=8.18.0,<10.0",
42
+ "mypy>=2.0,<3.0",
43
+ "pytest>=9.0,<10.0",
44
+ "pytest-cov>=7.0,<8.0",
45
+ "ruff>=0.15.0,<0.16.0",
46
+ ]
47
+
48
+ [tool.hatch.build.targets.wheel]
49
+ packages = ["d8s_timer"]
50
+
51
+ [tool.ruff]
52
+ line-length = 120
53
+ target-version = "py310"
54
+
55
+ [tool.ruff.lint]
56
+ select = ["E", "F", "I"]
57
+
58
+ [tool.ruff.lint.per-file-ignores]
59
+ "d8s_timer/__init__.py" = ["F401", "F403"]
60
+ "tests/*" = ["E501"]
61
+
62
+ [tool.mypy]
63
+ ignore_missing_imports = true
64
+
65
+ [tool.pytest.ini_options]
66
+ addopts = "-v --cov=. --cov-report term-missing --cov-fail-under 90"
67
+ python_files = "tests/test_*.py"
@@ -0,0 +1,24 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
3
+ "packages": {
4
+ ".": {
5
+ "release-type": "python",
6
+ "package-name": "d8s_timer",
7
+ "include-component-in-tag": false,
8
+ "changelog-sections": [
9
+ { "type": "feat", "section": "Features" },
10
+ { "type": "fix", "section": "Bug Fixes" },
11
+ { "type": "perf", "section": "Performance Improvements" },
12
+ { "type": "deps", "section": "Dependencies" },
13
+ { "type": "revert", "section": "Reverts" },
14
+ { "type": "docs", "section": "Documentation", "hidden": true },
15
+ { "type": "chore", "section": "Miscellaneous", "hidden": true },
16
+ { "type": "refactor", "section": "Code Refactoring", "hidden": true },
17
+ { "type": "style", "section": "Styles", "hidden": true },
18
+ { "type": "test", "section": "Tests", "hidden": true },
19
+ { "type": "build", "section": "Build System", "hidden": true },
20
+ { "type": "ci", "section": "Continuous Integration", "hidden": true }
21
+ ]
22
+ }
23
+ }
24
+ }
@@ -6,7 +6,7 @@ from d8s_timer import time_it, timer_get_time, timer_start, timer_stop
6
6
 
7
7
 
8
8
  def test_timer_get_time_1():
9
- timer_name = 'foo'
9
+ timer_name = "foo"
10
10
  timer_start(timer_name)
11
11
  time.sleep(2)
12
12
  current_time = timer_get_time(timer_name)
@@ -16,7 +16,7 @@ def test_timer_get_time_1():
16
16
 
17
17
  def test_timer_get_time__invalid_name():
18
18
  with pytest.raises(ValueError):
19
- timer_get_time('foo')
19
+ timer_get_time("foo")
20
20
 
21
21
 
22
22
  def test_generic_timer_1():
@@ -31,7 +31,7 @@ def test_generic_timer__invalid_name():
31
31
  timer_name = timer_start()
32
32
 
33
33
  with pytest.raises(ValueError):
34
- timer_stop('foo')
34
+ timer_stop("foo")
35
35
 
36
36
  timer_stop(timer_name)
37
37
 
@@ -42,7 +42,7 @@ def test_named_timer_1():
42
42
  with pytest.raises(RuntimeError):
43
43
  timer_start(timer_name)
44
44
 
45
- timer_start('bar')
45
+ timer_start("bar")
46
46
 
47
47
  time.sleep(2)
48
48
 
@@ -51,7 +51,7 @@ def test_named_timer_1():
51
51
 
52
52
  time.sleep(2)
53
53
 
54
- bar_elapsed_time = timer_stop('bar')
54
+ bar_elapsed_time = timer_stop("bar")
55
55
  assert 4 < bar_elapsed_time < 5
56
56
 
57
57