Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/cifuzz.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
path: ./out/artifacts
- name: Upload Sarif
if: always() && steps.build.outcome == 'success'
uses: github/codeql-action/upload-sarif@v2
uses: github/codeql-action/upload-sarif@v4
with:
# Path to SARIF file relative to the root of the repository
sarif_file: cifuzz-sarif/results.sarif
Expand Down
11 changes: 11 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ on:
pull_request:
branches:
- master
# Called by the Nightly workflow, which re-runs these same legs daily. The
# schedule lives there and not here because GitHub disables a workflow that
# has a schedule after 60 days without repository activity, and a disabled
# workflow answers none of its triggers, which would take pull request runs
# down with it.
workflow_call:
jobs:
build:
name: Build
Expand All @@ -20,6 +26,7 @@ jobs:
toxenv: min
- python-version: "3.10"
toxenv: min-all
- python-version: "3.10"
- python-version: "3.11"
- python-version: "3.12"
- python-version: "3.14"
Expand Down Expand Up @@ -53,6 +60,10 @@ jobs:
TZ=${{ matrix.timezone || 'UTC' }} echo "Running tests with timezone: $TZ"
TZ=${{ matrix.timezone || 'UTC' }} tox -e ${{ matrix.toxenv || 'py' }}
- name: Upload coverage.xml to codecov
# A nightly run, scheduled or dispatched, re-tests a commit that already
# has a coverage report, so uploading again only repeats the Codecov
# notification for that SHA.
if: github.event_name == 'push' || github.event_name == 'pull_request'
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
79 changes: 79 additions & 0 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: Nightly
on:
# Dependency, time zone database and calendar drift arrives with no commit
# behind it, and tests that only fail on the 31st of a month need a run on
# every date; a fixed weekday lands on a 31st about once a year. Off the hour,
# which GitHub names as a high-load window, and early in the UTC day so that
# the Pacific/Auckland and Pacific/Fiji legs stay on the same calendar date as
# the rest of the matrix.
schedule:
- cron: "17 4 * * *"
# Runs the same legs on demand, which is also the only way to exercise the
# reporting below before it is needed. GitHub disables this workflow after 60
# days without repository activity; re-enable it from the Actions tab or with
# `gh workflow enable nightly.yml`, since a disabled workflow answers no
# triggers at all.
workflow_dispatch:

# The called matrix only checks out and tests; the report job below asks for
# the one extra scope it needs.
permissions:
contents: read

jobs:
build:
uses: ./.github/workflows/main.yml
secrets: inherit

report:
name: Report failure
needs: build
# A push or pull request failure is already in front of whoever caused it.
# A failure with no commit behind it has nowhere to land but a single
# notification email to whoever last edited the schedule. A cancelled build
# counts, since a leg that hangs until GitHub kills it is a failure too.
# Master only, so that a dispatch on a work branch can neither file a
# report nor mask the real one.
if: >-
(needs.build.result == 'failure' || needs.build.result == 'cancelled')
&& github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: File a tracking issue unless one is already open
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
TITLE: The nightly build is failing
LABEL: nightly-failure
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
SHA: ${{ github.sha }}
run: |
set -euo pipefail
# One issue per outage: a daily comment stream would only be one more
# signal to ignore. The label, not the title, identifies the tracking
# issue, so retitling it to record the cause does not defeat the
# check; --force makes creating the label idempotent. A transient
# listing failure must not stop the report, since a duplicate issue
# is cheaper than silence.
gh label create "$LABEL" --force --color d93f0b \
--description "Filed by the Nightly workflow"
existing="$(gh issue list --state open --label "$LABEL" --limit 1 \
--json number --jq '.[0].number // empty' || true)"
if [ -n "$existing" ]; then
echo "Already tracked in #$existing."
exit 0
fi
gh issue create --title "$TITLE" --label "$LABEL" \
--label "Type: Maintenance" --body-file - <<EOF
The nightly run of the Build workflow failed on master at $SHA:
$RUN_URL

It tested a commit that was already on master, so this is most likely
drift in an unpinned dependency, drift in the CI toolchain, or a test
that only fails on this date.

Filed once per outage, with no follow-up comments. Close it once a
nightly run is green again.
EOF
4 changes: 4 additions & 0 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ installed, this is how you set up your fork for local development::

Bare ``pytest`` runs the ``tests/`` directory. Optional calendar and language
detection tests require ``pip install -e '.[calendars,langdetect]'``.
The suite turns warnings into errors (``filterwarnings`` in ``pytest.ini``),
so a new deprecation warning fails the run: use ``pytest -W default`` to see
such a warning without failing, fix it when it comes from dateparser itself,
and otherwise add a narrowly scoped ``ignore:`` line to ``pytest.ini``.
The ruff formatter uses its default line length of 88; the linter does not
enforce a maximum line length.

Expand Down
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ serialize = ["{major}.{minor}"]
[tool.ruff]
exclude = ["date_translation_data"]

[tool.ruff.lint]
# An invalid string escape warns at compile time, which pip's byte-compilation
# absorbs before the test suite's warnings-as-errors setting can see it.
extend-select = ["W605"]

[tool.ruff.lint.per-file-ignores]
"dateparser/data/__init__.py" = ["F401"]
"dateparser/languages/__init__.py" = ["F401"]
14 changes: 14 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -1,2 +1,16 @@
[pytest]
testpaths = tests
# Warnings are errors: warning-class problems have repeatedly reached users
# instead of CI (#1246, #1013, #506). The suite emits no warnings at all today.
# When an upstream deprecation turns the suite red, fix it if it comes from
# dateparser, and otherwise add the narrowest possible ignore *after* `error`,
# since the last matching filter wins.
#
# The exemptions below are environmental, not code: tzlocal warns when the host
# has no usable time zone configuration or a stale one, which CI never sees
# because it always sets TZ, and pytest warns when it cannot write its cache.
filterwarnings =
error
ignore:Can not find any timezone configuration:UserWarning
ignore:Timezone offset does not match system offset:UserWarning
ignore::pytest.PytestCacheWarning
14 changes: 13 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ deps =
pytz==2024.2
regex==2024.9.11
tzlocal==0.2
# tzlocal 0.2 contains invalid string escapes, which pytest.ini turns into an
# error. Installers that byte-compile, pip included, absorb that warning before
# pytest starts, but the ones that do not turn it into an import-time
# SyntaxError, so ignore that one message for the environments pinned to it. No
# category: it is a DeprecationWarning up to Python 3.11 and a SyntaxWarning
# from 3.12 on.
set_env =
PYTEST_ADDOPTS = -W "ignore:invalid escape sequence"

[testenv:min-all]
basepython = {[testenv:min]basepython}
Expand All @@ -38,6 +46,7 @@ deps =
convertdate==2.2.1
hijridate==2.3.0
langdetect==1.0.0
set_env = {[testenv:min]set_env}

[testenv:scripts]
deps =
Expand Down Expand Up @@ -87,5 +96,8 @@ passenv =
# instruction counts CodSpeed compares.
set_env =
PYTHONHASHSEED = 0
# pytest-codspeed reports a measurement hook that failed to start or stop as a
# RuntimeWarning; pytest.ini would turn that runner glitch into a red CodSpeed
# check that says nothing about dateparser.
commands =
pytest tests/benchmarks/ --no-cov --codspeed
pytest -W "ignore::RuntimeWarning:pytest_codspeed" tests/benchmarks/ --no-cov --codspeed
Loading