Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file

version: 2
updates:
# Enable version updates for GitHub Actions
- package-ecosystem: "github-actions"
groups:
actions:
patterns:
- "*"
directory: "/"
schedule:
# Check for updates to GitHub Actions every week
interval: "weekly"

# Enable version updates for pre-commit hooks
- package-ecosystem: "pre-commit"
directory: "/"
schedule:
interval: "weekly"
groups:
pre-commit:
patterns:
- "*"
11 changes: 6 additions & 5 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ on:
permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
check:
runs-on: ubuntu-latest
Expand All @@ -16,19 +20,16 @@ jobs:

steps:
- uses: actions/checkout@v5
- name: Set up Python 3.12
uses: actions/setup-python@v6
with:
python-version: "3.12"

- name: Install uv
uses: astral-sh/setup-uv@v6
with:
python-version: "3.12"
enable-cache: true
cache-dependency-glob: "pyproject.toml"

- name: Install package with check dependencies
run: uv sync --extra check
run: uv sync --group check

# check with ruff
- name: Run ruff
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ name: Upload Python Package
on:
release:
types: [published]
# allow manually running on main
workflow_dispatch:

permissions:
contents: read
Expand Down
14 changes: 9 additions & 5 deletions .github/workflows/unit_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ permissions:
contents: read
id-token: write

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

on:
push:
branches:
Expand Down Expand Up @@ -34,23 +38,23 @@ jobs:

# use github python action instead of uv to take advantage of caching
- name: Set up Python ${{ matrix.python }}
uses: actions/setup-python@v6
uses: astral-sh/setup-uv@v8.1.0
with:
python-version: ${{ matrix.python }}
cache: 'pip'
cache-dependency-path: '**/pyproject.toml'

- name: Install package with dependencies
run: pip install -e ".[test]"
- name: Install package with check dependencies
run: uv sync --group test

# for all versions but the one we use for code coverage, run normally
- name: Run unit tests without code coverage
run: pytest
run: uv run pytest
if: ${{ matrix.python != env.COV_PYTHON_VERSION }}

# run code coverage in one version only
- name: Run unit tests with code coverage reporting
run: pytest --cov=.
run: uv run pytest --cov=.
if: ${{ matrix.python == env.COV_PYTHON_VERSION }}

- name: Upload coverage to Codecov
Expand Down
30 changes: 27 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,22 +1,46 @@
files: \.py
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

pre-commit config top-level files regex semantics default applied to hooks

💡 Result:

In pre-commit's .pre-commit-config.yaml, top-level 'files' and 'exclude' options are Python regular expressions matched against file paths relative to the repository root using re.search semantics (substring match anywhere in the path, not full path anchored unless ^/$ used). - 'files': optional global include pattern (default: empty string ''). An empty regex matches all files (re.search('', path) succeeds for any path). - 'exclude': optional global exclude pattern (default: '^$', which matches only empty strings, excluding nothing). These apply before hook-level filters. Global 'files' selects candidates, then global 'exclude' removes matches from them, then hook-specific 'files'/'exclude' etc. apply. Hook-level 'files'/'exclude' use the same regex semantics. Source: Official pre-commit docs confirm defaults and top-level application; regex section explicitly states "The patterns for files and exclude are python regular expressions and are matched with re.search." Examples show multiline (?x) regexes for complex patterns.

Citations:


🏁 Script executed:

cat -n .pre-commit-config.yaml

Repository: dh-tech/undate-python

Length of output: 1716


Critical: top-level files: \.py silently disables every new non-Python hook.

The global files regex on line 1 applies to every hook that does not override it. check-merge-conflict, check-yaml, yamlfmt, codespell, and action-validator have no local files overrides and will only match files ending in .py, rendering them no-ops—these tools are meant to validate YAML, workflows, text, and merge conflicts, not Python source.

Remove the top-level filter (recommended—individual hooks already declare types/types_or appropriately) or override files per-hook that needs non-Python coverage.

Proposed fix
-files: \.py
 repos:

If a subset of existing hooks really did need to be restricted to *.py, re-declare files: on those individual hooks instead of globally.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
files: \.py
repos:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.pre-commit-config.yaml at line 1, The top-level "files: \.py" entry in
.pre-commit-config.yaml is restricting all hooks (including
check-merge-conflict, check-yaml, yamlfmt, codespell, action-validator) to
Python files only; remove the global "files: \.py" key or delete that line and
instead add per-hook "files:" filters only on the specific hooks that truly need
Python-only filtering (or leave hooks without a files filter so they respect
their own types/types_or), ensuring YAML/workflow/text hooks run on non-.py
files.

repos:
# ruff for linting and formatting python
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.3.4
rev: v0.12.7
hooks:
- id: ruff
args: [ --fix, --exit-non-zero-on-fix ]
- id: ruff-check
args: [ --fix, --show-fixes, --exit-non-zero-on-fix ]
- id: ruff-format
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
hooks:
- id: check-case-conflict
- id: check-merge-conflict
- id: check-executables-have-shebangs
- id: debug-statements
- id: end-of-file-fixer
- id: mixed-line-ending
- id: trailing-whitespace
- id: check-yaml
- id: name-tests-test
args: [--pytest-test-first]

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.13.0
hooks:
- id: mypy
additional_dependencies: [numpy]
# yamlfmt for formatting YAML files
- repo: https://github.com/google/yamlfmt
rev: v0.17.2
hooks:
- id: yamlfmt
# Codespell for spell checking
- repo: https://github.com/codespell-project/codespell
rev: v2.4.1
hooks:
- id: codespell
additional_dependencies:
- tomli
exclude_types: ["css", "html", "javascript", "json"]
# Validate GitHub Actions workflow files
- repo: https://github.com/mpalmer/action-validator
rev: v0.8.0
hooks:
- id: action-validator
10 changes: 5 additions & 5 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ sphinx:
configuration: docs/conf.py

python:
install:
- method: pip
path: .
extra_requirements:
- docs
install:
- method: uv
command: sync
groups:
- docs
8 changes: 7 additions & 1 deletion DEVELOPER_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,15 @@ source .venv/bin/activate
Install an editable version of the local package along with python dependencies needed for testing and development.

```sh
pip install -e ".[dev]"
pip install -e . --group=dev
```
Comment thread
rlskoeser marked this conversation as resolved.

If using `uv`, use

```sh
uv sync --group test
```

### Install pre-commit hooks

We use [pre-commit](https://pre-commit.com/) for automated checks and consistent formatting. If you're planning to contribute, please install these when you set up your local development.
Expand Down
29 changes: 17 additions & 12 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ dynamic = ["version"]
dependencies = [
"lark[interegular]",
"numpy",
"convertdate",
"convertdate>=2.4,<2.4.1", # changes syntax, deprecation warning
"strenum; python_version < '3.11'",
]
authors = [
Expand Down Expand Up @@ -42,7 +42,6 @@ classifiers = [
"Programming Language :: Python :: 3.13",
"Intended Audience :: Developers",
"Intended Audience :: Science/Research",
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Scientific/Engineering",
Expand All @@ -51,21 +50,20 @@ classifiers = [

]

[project.optional-dependencies]
[dependency-groups]
docs = ["sphinx>=7.0.0", "alabaster", "myst-parser", "myst-parser[linkify]"]
test = ["pytest>=7.2", "pytest-ordering", "pytest-cov"]
test = ["pytest>=9", "pytest-ordering", "pytest-cov"]
notebooks = ["jupyterlab", "pandas", "treon", "altair"]
check = ["undate[docs]", "undate[notebooks]", "mypy", "ruff"]
check = [ { include-group = "docs" }, {include-group = "notebooks"}, "mypy", "ruff"]
dev = [
"pre-commit>=2.20.0",
"twine",
"wheel",
"build",
"undate[check]",
"undate[docs]",
"undate[test]",
{ include-group = "test" },
{ include-group = "check" },
{ include-group = "docs" }
]
Comment thread
rlskoeser marked this conversation as resolved.
all = ["undate", "undate[dev]"]

[project.urls]
Homepage = "https://github.com/dh-tech/undate-python"
Expand All @@ -87,9 +85,16 @@ dependencies = ["babel"]
[tool.hatch.envs.codegen.scripts]
generate = "python scripts/generate_gregorian_grammar.py"

[tool.pytest.ini_options]
pythonpath = "src/"
testpaths = ["tests/"]
[tool.pytest]
minversion = "9"
log_level = "INFO"
strict = true
addopts = ["-ra"]
filterwarnings = ["error"]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

filterwarnings = ["error"] can make CI brittle against transitive warnings.

Combined with pytest>=9, escalating every warning to an error means any DeprecationWarning from numpy, convertdate, lark, or Python itself (e.g. on minor version bumps) will fail the suite even when the project code is fine. Consider scoping to your own warning categories and whitelisting known-noisy third-party ones, e.g.:

filterwarnings = [
    "error",
    "default::DeprecationWarning:convertdate.*",
    "default::DeprecationWarning:lark.*",
]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pyproject.toml` at line 93, The current pyproject.toml setting filterwarnings
= ["error"] escalates all warnings (including third-party DeprecationWarnings)
to errors; update the filterwarnings entry to keep tests strict for your
project-only warnings while whitelisting noisy third-party modules (e.g., scope
"error" to your package's warnings and add
default::DeprecationWarning:<module_pattern> entries for known noisy libs like
convertdate and lark) so pytest>=9 upgrades don’t break CI from transitive
warnings.

pythonpath = [ "src/" ]
testpaths = [
"tests",
]
markers = [
"last : run marked tests after all others",
"first : run marked tests before all others",
Expand Down
2 changes: 1 addition & 1 deletion src/undate/converters/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def import_converters(cls) -> int:
logger.debug("Loading converters under undate.converters")
import undate.converters

# load packages under this path with curent package prefix
# load packages under this path with current package prefix
converter_path = undate.converters.__path__
converter_prefix = f"{undate.converters.__name__}."

Expand Down
2 changes: 1 addition & 1 deletion src/undate/converters/calendars/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
__all__ = [
"GregorianDateConverter",
"HebrewDateConverter",
"IslamicDateConverter",
"IslamicDateConverter",
"SeleucidDateConverter",
]
2 changes: 1 addition & 1 deletion src/undate/converters/calendars/hebrew/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,4 @@ def parse(self, value: str) -> Union[Undate, UndateInterval]:
raise ValueError(f"Could not parse '{value}' as a Hebrew date") from err

# do we need to support conversion the other direction?
# i.e., generate a Hebrew date from an abitrary undate or undate interval?
# i.e., generate a Hebrew date from an arbitrary undate or undate interval?
2 changes: 1 addition & 1 deletion src/undate/converters/iso8601.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def _undate_to_string(self, undate: Undate) -> str:

elif date_portion == "year":
# if year is not known, add '-' for year portion,
# to genereate --MM-DD unknown year format
# to generate --MM-DD unknown year format
date_parts.append("-")
# TODO: fix type error: "list[str | None]" is incompatible with "Iterable[str]"
return "-".join(date_parts) # type: ignore
2 changes: 1 addition & 1 deletion src/undate/date.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ class DatePrecision(IntEnum):
of the date is known."""

# NOTE: values MUST be ordered based on the relative size or
# precison of the time unit. That is, the smaller the unit, the more precise
# precision of the time unit. That is, the smaller the unit, the more precise
# it is: a day is more precise than a month, a month is more precise than a year,
# (DatePrecision.year < DatePrecision.month)

Expand Down
2 changes: 1 addition & 1 deletion src/undate/undate.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ def calculate_earliest_latest(self, year, month, day):
# if we have no day or partial day, calculate min / max
min_day = 1 # is min day ever anything other than 1 ?
rel_year = year if year and isinstance(year, int) else max_year
# use month if it is an integer; otherwise use previusly determined
# use month if it is an integer; otherwise use previously determined
# max month (which may not be 12 depending if partially unknown)
rel_month = month if month and isinstance(month, int) else latest_month

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def test_islamic_undate():
# examples from ISMI data (reformatted to day month year)
# Rabi 1 = month 3
("14 Rabīʿ I 901", IslamicUndate(901, 3, 14), DatePrecision.DAY),
("Rabīʿ I 490", IslamicUndate(490, 3), DatePrecision.MONTH),
("Rabīʿ I 490", IslamicUndate(490, 3), DatePrecision.MONTH),
("884", IslamicUndate(884), DatePrecision.YEAR),
# Gregorian: UndateInterval(Undate(1479, 4, 3), Undate(1480, 3, 21)),
# add when we support parsing ranges:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_converters/test_combined_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
("Epiphany 1921", Undate(1921, 1, 6)),
("Pentecost 2016", Undate(2016, 5, 15)),
("Ash Wednesday 2000", Undate(2000, 3, 8)),
("Whit Monday 2023", Undate(2023, 5, 29)),
("Whit Monday 2023", Undate(2023, 5, 29)), # codespell:ignore whit
]


Expand Down
6 changes: 5 additions & 1 deletion tests/test_converters/test_holidays.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ def test_fixed_holidays(self, input_string, expected):
("Ascension 1988", Undate(1988, 5, 12), Weekday.THURSDAY),
("Ascension Day 1999", Undate(1999, 5, 13), Weekday.THURSDAY),
("Pentecost 2016", Undate(2016, 5, 15), Weekday.SUNDAY),
("whit monday 2005", Undate(2005, 5, 16), Weekday.MONDAY),
(
"whit monday 2005", # codespell:ignore whit
Undate(2005, 5, 16),
Weekday.MONDAY,
),
("whitsun monday 2023", Undate(2023, 5, 29), Weekday.MONDAY),
("trinity 1978", Undate(1978, 5, 21), Weekday.SUNDAY),
("Trinity Sunday 1967", Undate(1967, 5, 21), Weekday.SUNDAY),
Expand Down
Loading