timevec 0.3.2__tar.gz → 0.4.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 (51) hide show
  1. timevec-0.4.0/.coveragerc +2 -0
  2. {timevec-0.3.2 → timevec-0.4.0}/.github/workflows/gitignore-in.yml +1 -6
  3. timevec-0.4.0/.github/workflows/happy.yml +10 -0
  4. {timevec-0.3.2 → timevec-0.4.0}/.github/workflows/octocov.yml +11 -4
  5. timevec-0.4.0/.github/workflows/pypi-publish.yml +59 -0
  6. {timevec-0.3.2 → timevec-0.4.0}/.github/workflows/python-test.yml +14 -16
  7. timevec-0.4.0/.github/workflows/spellcheck.yml +8 -0
  8. timevec-0.4.0/CHANGELOG.md +94 -0
  9. {timevec-0.3.2/timevec.egg-info → timevec-0.4.0}/PKG-INFO +55 -3
  10. {timevec-0.3.2 → timevec-0.4.0}/README.md +54 -2
  11. timevec-0.4.0/examples/plot.py +58 -0
  12. timevec-0.4.0/lefthook.yml +13 -0
  13. {timevec-0.3.2 → timevec-0.4.0}/pyproject.toml +18 -0
  14. {timevec-0.3.2 → timevec-0.4.0}/tests/test_builtin_math.py +32 -2
  15. {timevec-0.3.2 → timevec-0.4.0}/tests/test_many_dates.py +11 -2
  16. {timevec-0.3.2 → timevec-0.4.0}/tests/test_numpy.py +18 -1
  17. timevec-0.4.0/tests/test_numpy_datetime64.py +147 -0
  18. {timevec-0.3.2 → timevec-0.4.0}/tests/test_same_result.py +47 -7
  19. timevec-0.4.0/tests/test_util.py +187 -0
  20. {timevec-0.3.2 → timevec-0.4.0}/timevec/__init__.py +28 -8
  21. {timevec-0.3.2 → timevec-0.4.0}/timevec/_version.py +3 -3
  22. {timevec-0.3.2 → timevec-0.4.0}/timevec/builtin_math.py +43 -22
  23. {timevec-0.3.2 → timevec-0.4.0}/timevec/numpy.py +65 -28
  24. {timevec-0.3.2 → timevec-0.4.0}/timevec/numpy_datetime64.py +63 -19
  25. {timevec-0.3.2 → timevec-0.4.0}/timevec/util.py +42 -48
  26. {timevec-0.3.2 → timevec-0.4.0/timevec.egg-info}/PKG-INFO +55 -3
  27. {timevec-0.3.2 → timevec-0.4.0}/timevec.egg-info/SOURCES.txt +5 -1
  28. timevec-0.4.0/timevec.egg-info/scm_file_list.json +38 -0
  29. timevec-0.4.0/timevec.egg-info/scm_version.json +8 -0
  30. {timevec-0.3.2 → timevec-0.4.0}/uv.lock +96 -100
  31. timevec-0.3.2/.github/workflows/happy.yml +0 -18
  32. timevec-0.3.2/.github/workflows/pypi-publish.yml +0 -49
  33. timevec-0.3.2/.github/workflows/spellcheck.yml +0 -16
  34. timevec-0.3.2/examples/plot.py +0 -39
  35. timevec-0.3.2/mypy.ini +0 -19
  36. timevec-0.3.2/tests/test_numpy_datetime64.py +0 -60
  37. timevec-0.3.2/tests/test_util.py +0 -110
  38. {timevec-0.3.2 → timevec-0.4.0}/.github/renovate.json5 +0 -0
  39. {timevec-0.3.2 → timevec-0.4.0}/.gitignore +0 -0
  40. {timevec-0.3.2 → timevec-0.4.0}/.gitignore.in +0 -0
  41. {timevec-0.3.2 → timevec-0.4.0}/.octocov.yml +0 -0
  42. {timevec-0.3.2 → timevec-0.4.0}/LICENSE +0 -0
  43. {timevec-0.3.2 → timevec-0.4.0}/examples/day_vec.svg +0 -0
  44. {timevec-0.3.2 → timevec-0.4.0}/examples/month_vec.svg +0 -0
  45. {timevec-0.3.2 → timevec-0.4.0}/examples/week_vec.svg +0 -0
  46. {timevec-0.3.2 → timevec-0.4.0}/examples/year_vec.svg +0 -0
  47. {timevec-0.3.2 → timevec-0.4.0}/setup.cfg +0 -0
  48. {timevec-0.3.2 → timevec-0.4.0}/timevec/py.typed +0 -0
  49. {timevec-0.3.2 → timevec-0.4.0}/timevec.egg-info/dependency_links.txt +0 -0
  50. {timevec-0.3.2 → timevec-0.4.0}/timevec.egg-info/requires.txt +0 -0
  51. {timevec-0.3.2 → timevec-0.4.0}/timevec.egg-info/top_level.txt +0 -0
@@ -0,0 +1,2 @@
1
+ [run]
2
+ branch = True
@@ -1,16 +1,11 @@
1
1
  name: Update gitignore file
2
-
3
2
  on:
4
3
  schedule:
5
4
  # daily at 00:00
6
5
  - cron: '0 0 * * *'
7
-
8
6
  permissions:
9
7
  contents: write
10
8
  pull-requests: write
11
-
12
9
  jobs:
13
10
  update-gitignore:
14
- runs-on: ubuntu-latest
15
- steps:
16
- - uses: gitignore-in/gh-action@v0.2.3
11
+ uses: kitsuyui/gh-actions-workflows/.github/workflows/gitignore-in.yml@3717c78af3a5e594b7a81b063276e15fac7e08fc
@@ -0,0 +1,10 @@
1
+ name: happy-commit
2
+ on:
3
+ - pull_request
4
+ permissions:
5
+ contents: read
6
+ pull-requests: write
7
+ issues: write
8
+ jobs:
9
+ happy:
10
+ uses: kitsuyui/gh-actions-workflows/.github/workflows/happy-commit.yml@3717c78af3a5e594b7a81b063276e15fac7e08fc
@@ -5,6 +5,10 @@ on:
5
5
  branches:
6
6
  - main
7
7
 
8
+ concurrency:
9
+ group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }}
10
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
11
+
8
12
  permissions:
9
13
  contents: read
10
14
  pull-requests: write
@@ -20,16 +24,19 @@ jobs:
20
24
 
21
25
  steps:
22
26
  - name: Checkout
23
- uses: actions/checkout@v6
27
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
24
28
 
25
29
  - name: Set up Python
26
30
  id: setup-python
27
- uses: actions/setup-python@v6
31
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
28
32
  with:
29
33
  python-version: "${{ matrix.python }}"
30
34
 
31
35
  - name: Set up uv
32
- uses: astral-sh/setup-uv@v7
36
+ uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
37
+ with:
38
+ enable-cache: true
39
+ cache-dependency-glob: uv.lock
33
40
 
34
41
  - name: Install dependencies
35
42
  run: |
@@ -44,7 +51,7 @@ jobs:
44
51
 
45
52
  # See also: https://github.com/k1LoW/octocov-action
46
53
  - name: Report coverage with octocov
47
- uses: k1LoW/octocov-action@v1
54
+ uses: k1LoW/octocov-action@b3b6ee60482a667950f87553abf1df63217235d9 # v1
48
55
  with:
49
56
  github-token: ${{ secrets.GITHUB_TOKEN }}
50
57
  config: .octocov.yml
@@ -0,0 +1,59 @@
1
+ name: Packaging
2
+
3
+ on:
4
+ pull_request:
5
+ types: [opened, synchronize, reopened]
6
+ release:
7
+ # "released" events are emitted either when directly be released or be edited from pre-released.
8
+ types: [prereleased, released]
9
+
10
+ concurrency:
11
+ group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.event.release.id || github.ref }}
12
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
13
+
14
+ permissions:
15
+ contents: read
16
+
17
+ jobs:
18
+ deploy:
19
+ runs-on: ubuntu-latest
20
+ permissions:
21
+ contents: read
22
+ id-token: write
23
+ attestations: write
24
+ steps:
25
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
26
+
27
+ - name: Set up Python
28
+ id: setup-python
29
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
30
+ with:
31
+ python-version: "3.14"
32
+
33
+ - name: Set up uv
34
+ uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
35
+ with:
36
+ enable-cache: true
37
+ cache-dependency-glob: uv.lock
38
+
39
+ - name: Install dependencies
40
+ run: uv sync
41
+
42
+ - name: Build
43
+ run: uv build
44
+
45
+ - name: Attest build provenance
46
+ if: github.event_name == 'release' && !github.event.release.prerelease
47
+ uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
48
+ with:
49
+ subject-path: dist/*
50
+
51
+ - name: Publish distribution to Test PyPI
52
+ uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1
53
+ if: github.event_name == 'release' && github.event.release.prerelease
54
+ with:
55
+ repository-url: https://test.pypi.org/legacy/
56
+
57
+ - name: Publish distribution to PyPI
58
+ if: github.event_name == 'release' && !github.event.release.prerelease
59
+ uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1
@@ -8,21 +8,16 @@ on:
8
8
  branches:
9
9
  - main
10
10
 
11
- jobs:
12
- actionlint:
13
- runs-on: ubuntu-latest
14
- steps:
15
- - name: Checkout
16
- uses: actions/checkout@v6
11
+ concurrency:
12
+ group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }}
13
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
17
14
 
18
- - name: Set up Go
19
- uses: actions/setup-go@v5
20
- with:
21
- go-version: stable
22
-
23
- - name: Run actionlint
24
- run: go run github.com/rhysd/actionlint/cmd/actionlint@v1.7.12
15
+ permissions:
16
+ contents: read
25
17
 
18
+ jobs:
19
+ actionlint:
20
+ uses: kitsuyui/gh-actions-workflows/.github/workflows/actionlint.yml@3717c78af3a5e594b7a81b063276e15fac7e08fc # main
26
21
  test:
27
22
  runs-on: ubuntu-latest
28
23
  strategy:
@@ -31,16 +26,19 @@ jobs:
31
26
  python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
32
27
  steps:
33
28
  - name: Checkout
34
- uses: actions/checkout@v6
29
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
35
30
 
36
31
  - name: Set up Python
37
32
  id: setup-python
38
- uses: actions/setup-python@v6
33
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
39
34
  with:
40
35
  python-version: "${{ matrix.python }}"
41
36
 
42
37
  - name: Set up uv
43
- uses: astral-sh/setup-uv@v7
38
+ uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
39
+ with:
40
+ enable-cache: true
41
+ cache-dependency-glob: uv.lock
44
42
 
45
43
  - name: Install dependencies
46
44
  run: |
@@ -0,0 +1,8 @@
1
+ name: Spellcheck
2
+ on:
3
+ - pull_request
4
+ permissions:
5
+ contents: read
6
+ jobs:
7
+ check:
8
+ uses: kitsuyui/gh-actions-workflows/.github/workflows/spellcheck.yml@3717c78af3a5e594b7a81b063276e15fac7e08fc # main
@@ -0,0 +1,94 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.3.2] - 2026-05-03
11
+
12
+ ### Changed
13
+ - Add workflow concurrency groups to CI
14
+
15
+ ## [0.3.1] - 2025-02-01
16
+
17
+ ### Changed
18
+ - Migrate package manager from Poetry to uv
19
+ - Set minimal permissions in CI publish workflow
20
+ - Add actionlint check to CI
21
+
22
+ ### Fixed
23
+ - Fix decade range near datetime minimum
24
+
25
+ ## [0.3.0] - 2024-10-16
26
+
27
+ ### Added
28
+ - Add Python 3.13 support
29
+
30
+ ## [0.2.0] - 2023-10-06
31
+
32
+ ### Added
33
+ - Add Python 3.12 support
34
+
35
+ ## [0.1.7] - 2023-07-17
36
+
37
+ ### Changed
38
+ - Minor refactor: convert comments to docstrings
39
+
40
+ ## [0.1.6] - 2023-02-18
41
+
42
+ ### Added
43
+ - Add `py.typed` marker for PEP 561 compliance
44
+
45
+ ## [0.1.5] - 2023-02-08
46
+
47
+ ### Changed
48
+ - Rewrite vector ↔ time conversion logic
49
+ - Add additional tests for time/vector round-trips
50
+
51
+ ## [0.1.4] - 2023-01-26
52
+
53
+ ### Added
54
+ - Reverse conversion: create datetime from time vector
55
+ - Add tests for many dates
56
+
57
+ ## [0.1.3] - 2023-01-24
58
+
59
+ ### Added
60
+ - Add `numpy.datetime64` vector support
61
+ - Unify date conversion between `builtin_math` and `numpy` submodules
62
+
63
+ ## [0.1.2] - 2023-01-23
64
+
65
+ ### Fixed
66
+ - Fix boundary value bug in edge cases
67
+
68
+ ## [0.1.1] - 2023-01-23
69
+
70
+ ### Changed
71
+ - Abstract common logic across `year_vec`, `month_vec`, `day_vec`, `week_vec`
72
+ - Add figure to README illustrating vector representation
73
+
74
+ ## [0.1.0] - 2023-01-21
75
+
76
+ ### Added
77
+ - Initial release
78
+ - Time vector representation using cos/sin for periodicity
79
+ - `builtin_math` submodule (no NumPy dependency)
80
+ - `numpy` submodule (optional NumPy support)
81
+
82
+ [Unreleased]: https://github.com/kitsuyui/python-timevec/compare/v0.3.2...HEAD
83
+ [0.3.2]: https://github.com/kitsuyui/python-timevec/compare/v0.3.1...v0.3.2
84
+ [0.3.1]: https://github.com/kitsuyui/python-timevec/compare/v0.3.0...v0.3.1
85
+ [0.3.0]: https://github.com/kitsuyui/python-timevec/compare/v0.2.0...v0.3.0
86
+ [0.2.0]: https://github.com/kitsuyui/python-timevec/compare/v0.1.7...v0.2.0
87
+ [0.1.7]: https://github.com/kitsuyui/python-timevec/compare/v0.1.6...v0.1.7
88
+ [0.1.6]: https://github.com/kitsuyui/python-timevec/compare/v0.1.5...v0.1.6
89
+ [0.1.5]: https://github.com/kitsuyui/python-timevec/compare/v0.1.4...v0.1.5
90
+ [0.1.4]: https://github.com/kitsuyui/python-timevec/compare/v0.1.3...v0.1.4
91
+ [0.1.3]: https://github.com/kitsuyui/python-timevec/compare/v0.1.2...v0.1.3
92
+ [0.1.2]: https://github.com/kitsuyui/python-timevec/compare/v0.1.1...v0.1.2
93
+ [0.1.1]: https://github.com/kitsuyui/python-timevec/compare/v0.1.0...v0.1.1
94
+ [0.1.0]: https://github.com/kitsuyui/python-timevec/releases/tag/v0.1.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: timevec
3
- Version: 0.3.2
3
+ Version: 0.4.0
4
4
  Summary: Get some usable vector representations of datetime.
5
5
  Author-email: Yui KITSU <kitsuyui+github@kitsuyui.com>
6
6
  License: Copyright 2023-2025 Kitsu Yui
@@ -56,15 +56,39 @@ This is called a time vector.
56
56
 
57
57
  # Installation
58
58
 
59
+ The base package has no NumPy dependency and supports
60
+ `timevec.builtin_math`:
61
+
59
62
  ```sh
60
63
  pip install timevec
61
64
  ```
62
65
 
66
+ Install the `numpy` extra when you use `timevec.numpy` or
67
+ `timevec.numpy_datetime64`:
68
+
69
+ ```sh
70
+ pip install "timevec[numpy]"
71
+ ```
72
+
63
73
  # Usage
64
74
 
75
+ With the base install:
76
+
77
+ ```python
78
+ import datetime
79
+ import timevec.builtin_math as tv
80
+
81
+ dt = datetime.datetime(2020, 1, 1, 0, 0, 0)
82
+ vec = tv.year_vec(dt)
83
+ # (1.0, 0.0)
84
+ ```
85
+
86
+ With the `numpy` extra:
87
+
65
88
  ```python
66
- import timevec.numpy as tv
67
89
  import datetime
90
+ import timevec.numpy as tv
91
+
68
92
  dt = datetime.datetime(2020, 1, 1, 0, 0, 0)
69
93
  vec = tv.year_vec(dt)
70
94
  # array([1., 0.])
@@ -130,11 +154,39 @@ You can express periodicity such as morning, noon, and night.
130
154
 
131
155
  ## Others
132
156
 
133
- - `long_time_vec` ... 1 to 5001 years period
157
+ - `long_time_vec` ... `datetime.min` to `datetime.max` period
134
158
  - `millennium_vec` ... one millennium (1000 years) period
135
159
  - `century_vec` ... one century (100 years) period
136
160
  - `decade_vec` ... one decade (10 years) period
137
161
 
162
+ ## Development
163
+
164
+ This repository uses [lefthook](https://lefthook.dev/) to run the same checks as CI
165
+ locally, so problems surface before they reach CI.
166
+
167
+ ```sh
168
+ # Install dependencies
169
+ uv sync
170
+
171
+ # Install the Git hooks (once; requires lefthook on your PATH)
172
+ lefthook install
173
+ ```
174
+
175
+ Once installed, the hooks run automatically:
176
+
177
+ - **pre-commit**: `uv run poe check`
178
+ - **pre-push**: `uv run poe check` and `uv run poe test`
179
+
180
+ You can also run the checks manually:
181
+
182
+ ```sh
183
+ uv run poe check
184
+ uv run poe test
185
+ ```
186
+
187
+ CI still runs the full matrix (see `.github/workflows/`); the hooks only bring that
188
+ feedback earlier on your machine.
189
+
138
190
  # License
139
191
 
140
192
  BSD 3-Clause License
@@ -22,15 +22,39 @@ This is called a time vector.
22
22
 
23
23
  # Installation
24
24
 
25
+ The base package has no NumPy dependency and supports
26
+ `timevec.builtin_math`:
27
+
25
28
  ```sh
26
29
  pip install timevec
27
30
  ```
28
31
 
32
+ Install the `numpy` extra when you use `timevec.numpy` or
33
+ `timevec.numpy_datetime64`:
34
+
35
+ ```sh
36
+ pip install "timevec[numpy]"
37
+ ```
38
+
29
39
  # Usage
30
40
 
41
+ With the base install:
42
+
43
+ ```python
44
+ import datetime
45
+ import timevec.builtin_math as tv
46
+
47
+ dt = datetime.datetime(2020, 1, 1, 0, 0, 0)
48
+ vec = tv.year_vec(dt)
49
+ # (1.0, 0.0)
50
+ ```
51
+
52
+ With the `numpy` extra:
53
+
31
54
  ```python
32
- import timevec.numpy as tv
33
55
  import datetime
56
+ import timevec.numpy as tv
57
+
34
58
  dt = datetime.datetime(2020, 1, 1, 0, 0, 0)
35
59
  vec = tv.year_vec(dt)
36
60
  # array([1., 0.])
@@ -96,11 +120,39 @@ You can express periodicity such as morning, noon, and night.
96
120
 
97
121
  ## Others
98
122
 
99
- - `long_time_vec` ... 1 to 5001 years period
123
+ - `long_time_vec` ... `datetime.min` to `datetime.max` period
100
124
  - `millennium_vec` ... one millennium (1000 years) period
101
125
  - `century_vec` ... one century (100 years) period
102
126
  - `decade_vec` ... one decade (10 years) period
103
127
 
128
+ ## Development
129
+
130
+ This repository uses [lefthook](https://lefthook.dev/) to run the same checks as CI
131
+ locally, so problems surface before they reach CI.
132
+
133
+ ```sh
134
+ # Install dependencies
135
+ uv sync
136
+
137
+ # Install the Git hooks (once; requires lefthook on your PATH)
138
+ lefthook install
139
+ ```
140
+
141
+ Once installed, the hooks run automatically:
142
+
143
+ - **pre-commit**: `uv run poe check`
144
+ - **pre-push**: `uv run poe check` and `uv run poe test`
145
+
146
+ You can also run the checks manually:
147
+
148
+ ```sh
149
+ uv run poe check
150
+ uv run poe test
151
+ ```
152
+
153
+ CI still runs the full matrix (see `.github/workflows/`); the hooks only bring that
154
+ feedback earlier on your machine.
155
+
104
156
  # License
105
157
 
106
158
  BSD 3-Clause License
@@ -0,0 +1,58 @@
1
+ # ja: 実際に year_vec がどのような値を返すかのグラフを描き、わかりやすくします。
2
+
3
+ import datetime
4
+ from collections.abc import Callable
5
+
6
+ import matplotlib.pyplot as plt
7
+ import numpy as np
8
+
9
+ import timevec.numpy as tv
10
+
11
+
12
+ def plot_func_vec(
13
+ func: Callable[[datetime.datetime], np.ndarray],
14
+ dates: list[datetime.datetime],
15
+ ) -> None:
16
+ vecs = np.array([func(dt) for dt in dates])
17
+ _fig, _ax = plt.subplots()
18
+ plt.plot(vecs)
19
+ plt.savefig(f"examples/{func.__name__}.svg")
20
+
21
+
22
+ def main() -> None:
23
+ plot_func_vec(
24
+ tv.year_vec,
25
+ dates=[
26
+ datetime.datetime(2023, 1, 1, 0, 0, 0)
27
+ + datetime.timedelta(days=day)
28
+ for day in range(365 * 2)
29
+ ],
30
+ )
31
+ plot_func_vec(
32
+ tv.month_vec,
33
+ dates=[
34
+ datetime.datetime(2023, 1, 1, 0, 0, 0)
35
+ + datetime.timedelta(days=day)
36
+ for day in range(31 * 2)
37
+ ],
38
+ )
39
+ plot_func_vec(
40
+ tv.week_vec,
41
+ dates=[
42
+ datetime.datetime(2023, 1, 1, 0, 0, 0)
43
+ + datetime.timedelta(hours=h)
44
+ for h in range(24 * 7 * 2)
45
+ ],
46
+ )
47
+ plot_func_vec(
48
+ tv.day_vec,
49
+ dates=[
50
+ datetime.datetime(2023, 1, 1, 0, 0, 0)
51
+ + datetime.timedelta(hours=h)
52
+ for h in range(24 * 2)
53
+ ],
54
+ )
55
+
56
+
57
+ if __name__ == "__main__":
58
+ main()
@@ -0,0 +1,13 @@
1
+ # Clear Git hook environment variables before running checks so nested or sibling
2
+ # repositories are not affected: https://git-scm.com/docs/githooks
3
+ pre-commit:
4
+ jobs:
5
+ - name: check
6
+ run: for name in $(env | sed -n 's/^\(GIT_[A-Za-z0-9_]*\)=.*/\1/p'); do unset "$name"; done; uv run poe check
7
+
8
+ pre-push:
9
+ jobs:
10
+ - name: check
11
+ run: for name in $(env | sed -n 's/^\(GIT_[A-Za-z0-9_]*\)=.*/\1/p'); do unset "$name"; done; uv run poe check
12
+ - name: test
13
+ run: for name in $(env | sed -n 's/^\(GIT_[A-Za-z0-9_]*\)=.*/\1/p'); do unset "$name"; done; uv run poe test
@@ -131,3 +131,21 @@ max-complexity = 4
131
131
  [tool.mypy]
132
132
  strict = true
133
133
  ignore_missing_imports = false
134
+
135
+ [[tool.mypy.overrides]]
136
+ module = "tests.*"
137
+ disallow_untyped_defs = false
138
+ warn_return_any = false
139
+ ignore_missing_imports = true
140
+
141
+ [[tool.mypy.overrides]]
142
+ module = "numpy"
143
+ ignore_missing_imports = true
144
+
145
+ [[tool.mypy.overrides]]
146
+ module = "scipy.*"
147
+ ignore_missing_imports = true
148
+
149
+ [[tool.mypy.overrides]]
150
+ module = "sympy"
151
+ ignore_missing_imports = true
@@ -48,8 +48,14 @@ def assert_range_vector_value(
48
48
  ) -> None:
49
49
  assert fn(range.begin) == pytest.approx((1.0, 0.0), abs=abs)
50
50
  assert fn(range.end_of_first_quarter) == pytest.approx((0.0, 1.0), abs=abs)
51
- assert fn(range.end_of_second_quarter) == pytest.approx((-1.0, 0.0), abs=abs)
52
- assert fn(range.end_of_third_quarter) == pytest.approx((0.0, -1.0), abs=abs)
51
+ assert fn(range.end_of_second_quarter) == pytest.approx(
52
+ (-1.0, 0.0),
53
+ abs=abs,
54
+ )
55
+ assert fn(range.end_of_third_quarter) == pytest.approx(
56
+ (0.0, -1.0),
57
+ abs=abs,
58
+ )
53
59
  assert fn(range.end) == pytest.approx((1.0, 0.0), abs=abs)
54
60
 
55
61
 
@@ -156,6 +162,15 @@ def test_day_vec() -> None:
156
162
  assert (x, y) == pytest.approx((1.0, 0.0), abs=1e-6)
157
163
 
158
164
 
165
+ def test_ratio_to_vec_rejects_nan_and_inf() -> None:
166
+ with pytest.raises(ValueError, match="finite"):
167
+ tv.ratio_to_vec(float("nan"))
168
+ with pytest.raises(ValueError, match="finite"):
169
+ tv.ratio_to_vec(float("inf"))
170
+ with pytest.raises(ValueError, match="finite"):
171
+ tv.ratio_to_vec(float("-inf"))
172
+
173
+
159
174
  def test_edge_cases() -> None:
160
175
  # beginning of year
161
176
  dt = datetime.datetime(2023, 1, 1, 0, 0, 0)
@@ -178,3 +193,18 @@ def test_edge_cases() -> None:
178
193
  dt = datetime.datetime(2023, 12, 31, 23, 59, 59, 999999)
179
194
  x, y = tv.year_vec(dt)
180
195
  assert (x, y) == pytest.approx((1.0, 0.0), abs=1e-6)
196
+
197
+
198
+ def test_vec_to_ratio_zero_vector_raises() -> None:
199
+ with pytest.raises(ValueError):
200
+ tv.vec_to_ratio(0.0, 0.0)
201
+
202
+
203
+ def test_datetime_from_vecs_empty_raises() -> None:
204
+ with pytest.raises(ValueError, match="No recognized time targets"):
205
+ tv.datetime_from_vecs({})
206
+
207
+
208
+ def test_datetime_from_vecs_unrecognized_keys_raises() -> None:
209
+ with pytest.raises(ValueError, match="No recognized time targets"):
210
+ tv.datetime_from_vecs({"unknown_key": (0.5, 0.5)}) # type: ignore[dict-item]
@@ -23,7 +23,16 @@ def test_many_dates() -> None:
23
23
  "week",
24
24
  "day",
25
25
  ]
26
- ] = ["long_time", "millennium", "century", "decade", "year", "month", "week", "day"]
26
+ ] = [
27
+ "long_time",
28
+ "millennium",
29
+ "century",
30
+ "decade",
31
+ "year",
32
+ "month",
33
+ "week",
34
+ "day",
35
+ ]
27
36
  minimal: Iterable[Literal["long_time", "century", "year", "day"]] = [
28
37
  "long_time",
29
38
  "century",
@@ -57,5 +66,5 @@ def test_many_dates() -> None:
57
66
  vecs7 = tv64.datetime64_to_vecs(np.datetime64(dt), minimal)
58
67
  tv64.datetime64_from_vecs(vecs7)
59
68
 
60
- # tested up to 2100-01-01
69
+ # tested beyond 2400-01-01
61
70
  assert dt >= datetime.datetime(2400, 1, 1, 0, 0, 0)
@@ -11,7 +11,7 @@ def test_long_time_vec() -> None:
11
11
  vec = tvn.long_time_vec(dt)
12
12
  assert vec == pytest.approx(np.array([1.0, 0.0]), abs=1e-6)
13
13
 
14
- dt = datetime.datetime(5001, 1, 1, 0, 0, 0)
14
+ dt = datetime.datetime.max
15
15
  vec = tvn.long_time_vec(dt)
16
16
  assert vec == pytest.approx(np.array([1.0, 0.0]), abs=1e-6)
17
17
 
@@ -139,3 +139,20 @@ def test_edge_cases() -> None:
139
139
  dt = datetime.datetime(2023, 1, 31, 23, 59, 59, 999999)
140
140
  vec = tvn.month_vec(dt)
141
141
  assert vec == pytest.approx(np.array([1.0, 0.0]), abs=1e-5)
142
+
143
+
144
+ def test_vec_to_ratio_zero_vector_raises() -> None:
145
+ with pytest.raises(ValueError):
146
+ tvn.vec_to_ratio(np.array([0.0, 0.0]))
147
+
148
+
149
+ def test_datetime_from_vecs_empty_raises() -> None:
150
+ with pytest.raises(ValueError, match="No recognized time targets"):
151
+ tvn.datetime_from_vecs({})
152
+
153
+
154
+ def test_datetime_from_vecs_unrecognized_keys_raises() -> None:
155
+ with pytest.raises(ValueError, match="No recognized time targets"):
156
+ tvn.datetime_from_vecs(
157
+ {"unknown_key": np.array([0.5, 0.5])}, # type: ignore[dict-item]
158
+ )