Compare commits

..
61 Commits
Author SHA1 Message Date
Stan b0c6753462 Release v1.11.1 2026-08-26 04:46:29 +02:00
David Macario d97b27901b Fix cluster requesting hardcoded unix-only fork context (#347) 2026-08-26 04:39:33 +02:00
Stan Triepels fa935f89ab Show test coverage in github pull request comment (#344) 2026-08-14 17:26:55 +02:00
Stan Triepels 9e576b85e6 Swap localstorage to ministack (#343) 2026-08-14 05:37:10 +02:00
Stan 1941f1e3f0 Release v1.11.0 2026-08-10 04:17:05 +02:00
tugofpeasandTug of Peas 97ea3c89a5 Postpone SECRET_KEY evaluation to the qcluster command execution (#332)
* Suppress ImproperlyConfigured within Conf, allowing the exception to be raised specifically during the 'qcluster' command instead.

This ensures build scripts and workflows can freely execute other Django commands (e.g., 'python manage.py collectstatic') without failing due to a missing/empty secret key.

* Closes #279

Co-authored-by: Tug of Peas <19413623+tugofpeas@users.noreply.github.com>
2026-08-09 03:20:51 +02:00
Stan Triepels b2651ce86c Add django 6.1 support (#340) 2026-08-06 03:00:32 +02:00
Stan Triepels fc81787612 Add support for python 3.13 and 3.14 (#338)
* update matrix

* add support for 3.14
2026-08-02 03:46:04 +02:00
Stan Triepels ea839ab664 Migrate poetry to uv (#337) 2026-08-01 05:11:49 +02:00
Paul Backhouse 0e4c163d79 Add croniter as optional extra. (#336)
Allows django-q2[croniter] to be specified in a dependant's pyproject.toml.
Required because dependant may not explicitly use croniter in code
and so it can be flagged as unused.
2026-07-22 15:37:18 +02:00
Andy Galasso 480b77dfe4 AttributeError when start_event is None, and guard process faster stop (#305)
* AttributeError when start_event is None, and guard process faster stop

This commit has two related fixes that come into play when frequently
shutting down and restarting the cluster.

If a SIGINT or SIGTERM signal is received while the main process is
waiting for the sentinel process to set start_event, the signal
handler sets start_event to None, and the loop that polls start_event
will raise an unhandled AttributeError attempting to check
start_event.is_set().

The second issue is that the guard process sleeps for the guard cycle
interval in each iteration before checking the stop event, preventing
the guard cycle from terminating until the sleep completes. The
cluster can be made more responsive to a shutdown request by using
the event's wait(cycle) method rather than time.sleep(cycle) so the
process wakes immediately when the event is set.

The commit also fixes the case where the guard process sleeps for an
extra cycle when the cycle counter happens to have been reset to zero
on the loop iterations when the scheduler is called.

This fix helps in our environment where we are frequently stopping
and starting the cluster and where we have increased the guard
cycle setting to several seconds.

* Add sentinel premature death check while waiting for sentinel to start.

Suggested by github copilot [here](https://github.com/django-q2/django-q2/pull/305/changes#r3143964420)

* Add test case test_cluster_early_stop

Add a test case to validate stopping the cluster before the
sentinel has set the cluster's start_event.

The test deterministically triggers the AttributeError when
start_event is None (without the PR's fix in cluster.py).

As requested by copilot: https://github.com/django-q2/django-q2/pull/305#discussion_r3143964399

* Add test test_cluster_stop_responsive

Ensure that stopping the cluster is responsive and does not wait for a full
GUARD_CYCLE to stop the cluster.

As requested by copilot: https://github.com/django-q2/django-q2/pull/305/changes#r3143964414

* Address copilot review comments.

1. Do not raise RuntimeError if sentinel early exit was caused by
   SIGINT/SIGTERM stopping the cluster while waiting for the
   sentinel to start.
   Addresses https://github.com/django-q2/django-q2/pull/305#discussion_r3298618046

2. Ensure that the monkeypatched broker instance remains pickleable
   so the test_cluster_early_stop test will also work on platforms
   that use the spawn Process start method.
   Addresses https://github.com/django-q2/django-q2/pull/305#discussion_r3298618086

3. Do not allow the test_cluster_early_stop test to hang if the
   sentinel process or main test process terminates unexpectedly
   without setting the sentinel_event or test_event.
   Addresses https://github.com/django-q2/django-q2/pull/305#discussion_r3298618102
2026-05-26 00:07:53 +02:00
Stan a699578c34 Release v1.10.0 2026-05-01 19:34:38 +02:00
Islam AsabaevandCopilot 5975a2d081 feat: add ru locale and improve translations (#320)
* Add ru locale

* fix

* fix: remove duplicate

* Add field labels and continue ru locale

* fix: Add ru gettext for queue columns, short result column, and OrmQ field labels

* fix: locale paths in translation files

* chore: format code with ruff

* chore: format code with ruff

* fix: correct time_taken usage in admin

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update django_q/locale/de/LC_MESSAGES/django.po

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update django_q/locale/tr/LC_MESSAGES/django.po

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix: clear fuzzy markers

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-25 01:06:07 +02:00
Islam Asabaev 936fdd10b1 Update Python base image to 3.9-slim-bookworm (#325)
* issue: gh-324
2026-04-18 16:48:55 +02:00
Nick YuanandClaude Opus 4.6 fab97463c2 Fix unbounded growth of Broker.set_stat cluster master list (#322)
Prune stale entries from the master list on new cluster registration
and only write the list when membership changes (with timeout=None).

Before this fix, set_stat was append-only — dead cluster keys accumulated
forever because the only cleanup path (get_stats) runs only from the
monitor UIs. On DatabaseCache backends this rewrote the growing pickled
list to Postgres on every heartbeat, producing measurable egress.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 00:24:43 +02:00
Sophile 1abdc5b653 Convert queue size and count to string in monitor (#319) 2026-03-27 23:00:35 +01:00
Seba 01df35c923 Don't close DB connection if async_task was called with sync=True (#301) 2026-03-12 15:33:19 +01:00
Niko 573b8da528 Update Django Q2 compatibility information (#316) 2026-02-16 22:59:51 +01:00
Yibo Li 8a563d289d feat:add Simplified Chinese Translation (#314) 2026-01-14 23:58:54 +01:00
Marcin Bachry 1b0f71a39b Fix BadSignature after the default Django cache expires (#311)
* async_iter: fix BadSignature after the default Django cache expires

* lint
2026-01-08 23:27:03 +01:00
prollings b51575a4b0 Add post_execute_in_worker signal (#309) 2025-12-10 16:54:14 +01:00
xuheng.zongandStan Triepels fd927087f1 fix: Fix incorrect signal import (#308)
* fix: Fix incorrect signal import

* lint

---------

Co-authored-by: Stan Triepels <1939656+GDay@users.noreply.github.com>
2025-12-08 21:10:10 +01:00
Stan 386e04171b Release v1.9.0 2025-12-04 23:04:52 +01:00
Luke Plant 0054535624 Django 6.0 support (#307)
* Remove upper bound on Django version.

This allows it to be installed alongside Django 6 and later.

See https://iscinumpy.dev/post/bound-version-constraints/

* Run tests on Django 6.0 / Python 3.12
2025-12-04 17:15:18 +01:00
Salvo 'LtWorf' Tomaselli 09e65da5b3 Fix to make tests work with redis-py > 5 (#282) 2025-07-04 02:13:46 +02:00
Stan 65d2548e98 Release v1.8.0 2025-04-25 16:30:51 +02:00
Stan Triepels cbe51f995c Move timeout function from ORM broker into class to allow easy customization (#274)
* move timeout function to class to allow customization

* format

* fix format
2025-04-23 15:44:37 +02:00
Adam JohnsonandStan Triepels 0090a6f411 Update tested versions, add python 3.13 support and django 5.2 support. Drop python 3.8 support (#271)
* Update tested versions

* Remove f string

* Fix second `format_html`

---------

Co-authored-by: Stan Triepels <1939656+GDay@users.noreply.github.com>
2025-04-16 01:48:51 +02:00
Fernando Karchiloff a154fd658a Avoid creating task run on Scheduler creation (#268) 2025-03-12 23:31:00 +01:00
Adam Johnson 81f2531e3e Remove disque from CI (#270) 2025-03-12 23:28:59 +01:00
Stan Triepels c464751ae9 Delete deprecated imports and unwrapping (#261)
* delete old code

* remove imports
2025-01-12 03:40:18 +01:00
Stan 144536cbe4 Release v1.7.6 2025-01-12 02:25:29 +01:00
Stan Triepels 7e72b68c7f Make poetry version fixed in CI (#260) 2025-01-12 02:22:14 +01:00
Stan 404932117e Release v1.7.5 2025-01-12 01:57:13 +01:00
Anthony Hivert ddc1aa2de1 perf: avoid checking success tasks when save limit is disabled (#255)
- avoid extra queries when checking the count of success in db
2025-01-04 02:31:30 +01:00
mhaehnel 351bf66d71 Fix install path for CHANGELOG.md (#258)
The file should not be installed directly in site-packages. Use the
correct include syntax to include them into the source distribution
package only.
2025-01-02 01:52:07 +01:00
Stan ccd760a69f Release v1.7.4 2024-11-03 15:26:11 +01:00
Alberto fb23b6b825 Fix 'receive_message_wait_time_seconds' SQS broker management (#243)
* Fix 'receive_message_wait_time_seconds' SQS broker management

* Remove socket volume from localstack container
2024-11-03 15:04:35 +01:00
P-EB 35c911080b Fix BROKER_CLASS monkeypatch in test_brokers (#239) 2024-10-21 17:51:27 +02:00
P-EB 81058fc1cf Decrease the MAX_RSS set in test_cluster::test_max_rss (#240) 2024-10-21 17:50:30 +02:00
Stan 505eb8d537 Release v1.7.3 2024-10-15 04:17:28 +02:00
blockisecandStan Triepels dcfe5b6650 Fix missing ack_id when finishing task (#224)
* Update monitor.py

* format

---------

Co-authored-by: Stan Triepels <1939656+GDay@users.noreply.github.com>
2024-10-11 15:03:18 +02:00
Paulo CoutinhoandStan Triepels c3b49cca25 Only trigger prometheus if configured (#231)
* fix prometheus integration

* fix prometheus integration

* Add also lowercase option

As they seem to support that too: https://github.com/prometheus/client_python/blob/d7c9cd88c7f50097cd86869974301df7615bc9c0/prometheus_client/multiprocess.py#L166-L167

* format

---------

Co-authored-by: Stan Triepels <1939656+GDay@users.noreply.github.com>
2024-10-11 04:09:17 +02:00
Knuth c1e00b09cb Fix type check for args in scheduler.py E721 (#233) 2024-10-10 16:10:43 +02:00
Knuth 8e403d0136 Refactor timeout handling to handle AttributeError and ValueError for Windows users (#234) 2024-10-10 16:09:57 +02:00
Stan Triepels 337a5782d9 Catch missing SEGALRM with AttributeError instead of ValueError (#223) 2024-09-22 04:12:38 +02:00
Stan 2c456cd0aa Release v1.7.2 2024-09-10 00:16:18 +02:00
Stan Triepels 8f54e5d5ae Add twine check and fix readme (#216)
* Add twine check

* add poetry to install

* move up remove black/flake formatting

* fix path

* fix?

* fix rst?

* add rstcheck

* test all files?

* all

* remove complaining image

* only check readme

* remove not needed dependencies
2024-09-10 00:10:14 +02:00
Stan 689c881178 Release v1.7.1 2024-09-08 04:20:13 +02:00
Stan 923c5daa73 Release v1.7.0 2024-09-08 03:52:37 +02:00
Stan Triepels 69e794f1af Add index on succeeded tasks (#164)
* Add index on task table

* also add models file

* add make commands and limit index

* format
2024-09-08 03:37:28 +02:00
Stan Triepels 2191897825 Add example project (#215)
* add example project

* format

* fix format
2024-09-08 03:13:49 +02:00
Andrii Yurchuk af505e8d70 Call mark_process_dead on worker pid if prometheus_client is installed (#212) 2024-09-03 22:29:00 +02:00
kimihito 48123af09d chore: Add Support Django 5.1 (#207) 2024-08-13 14:14:40 +02:00
kimihito faaa57be93 chore: Update CI for Django 4.2 Python 3.12 support (#208) 2024-08-13 14:14:11 +02:00
jv3ga 5015d8ee4d fix: Oracle ORM backend compatibility #180 (#186) 2024-08-13 04:40:54 +02:00
Stan Triepels cb253357fb Fix repeating task after timeout (#184) 2024-06-23 22:36:29 +02:00
GDay efa0d6d9e4 ignore fuff formating 2024-05-11 03:06:58 +02:00
Stan Triepels ad4d24e17c Replace black/isort with ruff (#188)
* Replace black/isort with ruff

* fix typo
2024-05-11 03:04:32 +02:00
Stan Triepels 1d1d0a9aa5 Fix max attempts for value 1 (#185) 2024-05-06 17:28:27 +02:00
Stan Triepels 5e4aa65f62 Remove support for Django 3.2 and 4.1 (#183) 2024-05-05 00:42:09 +02:00
79 changed files with 5172 additions and 2681 deletions
+2
View File
@@ -1,2 +1,4 @@
# flake8, black, isort # flake8, black, isort
b1d000d007f3f77069719523268a0c6256dc0860 b1d000d007f3f77069719523268a0c6256dc0860
# move to ruff formatting/linting
ad4d24e17c9424b17cd8ae65c2def7ecc74e63c1
+5 -3
View File
@@ -23,9 +23,11 @@ jobs:
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get -y install gettext sudo apt-get -y install gettext
python -m pip install pip setuptools django poetry pip install uv==0.12.1 django==5.2
# compile messages to get .mo files # compile messages to get .mo files
django-admin compilemessages uv run django-admin compilemessages
- name: Build and publish package - name: Build and publish package
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
run: poetry --build --username=__token__ --password=${{ secrets.PYPI_TOKEN }} publish run: |
uv build
uv publish --token ${{ secrets.PYPI_TOKEN }}
+69 -53
View File
@@ -6,36 +6,64 @@ on:
pull_request: pull_request:
branches: branches:
- master - master
# for code coverage comment
permissions:
contents: read
pull-requests: write
env:
MONGO_HOST: "127.0.0.1"
REDIS_HOST: "127.0.0.1"
AWS_ENDPOINT_URL: http://localhost:4566
AWS_REGION: "us-east-1"
AWS_ACCESS_KEY_ID: "test"
AWS_SECRET_ACCESS_KEY: "test"
AWS_DEFAULT_REGION: "us-east-1"
jobs: jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Lint with ruff
run: |
pipx install ruff==0.4.10
ruff format . --check && ruff check .
- name: Check twine
run: |
python -m pip install twine poetry rstcheck
poetry build
rstcheck README.rst
twine check dist/*
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12.0-rc.3" ] python-version:
django: [ "3.2", "4.1", "4.2", "5.0a1"] - "3.10"
- "3.11"
- "3.12"
- "3.13"
- "3.14"
django:
- "5.2"
- "6.0"
- "6.1"
exclude: exclude:
# django 5.0 does not support 3.8 and 3.9 # django 6.0 does not support earlier than 3.12
- python-version: "3.8" - python-version: "3.10"
django: "5.0a1" django: "6.0"
- python-version: "3.9"
django: "5.0a1"
# django 4.2 does not support 3.12
- python-version: "3.12.0-rc.3"
django: "4.2"
# django 4.1 does not support 3.12
- python-version: "3.12.0-rc.3"
django: "4.1"
# django 3.2 does not support 3.11 and 3.12
- python-version: "3.11" - python-version: "3.11"
django: "3.2" django: "6.0"
- python-version: "3.12.0-rc.3" # django 6.1 does not support earlier than 3.12
django: "3.2" - python-version: "3.10"
django: "6.1"
- python-version: "3.11"
django: "6.1"
services: services:
disque:
image: efrecon/disque:1.0-rc1
ports:
- '7711:7711/tcp'
mongodb: mongodb:
image: mongo image: mongo
ports: ports:
@@ -55,6 +83,13 @@ jobs:
ports: ports:
- 6379:6379 - 6379:6379
options: --entrypoint redis-server options: --entrypoint redis-server
aws:
image: ministackorg/ministack:1.4.16
env:
SERVICES: sqs
MINISTACK_HOST: aws
ports:
- 4566:4566
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }} - name: Set up Python ${{ matrix.python-version }}
@@ -63,38 +98,19 @@ jobs:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
- name: Install dependencies with Django ${{ matrix.django }} - name: Install dependencies with Django ${{ matrix.django }}
run: | run: |
python -m pip install --upgrade pip python -m pip install uv==0.12.1
pip install poetry uv sync --extra testing --python ${{ matrix.python-version }}
poetry add "django==${{ matrix.django }}" --python=${{ matrix.python-version }} uv pip install "django~=${{ matrix.django }}a1"
poetry install -E testing - name: Create SQS queue
run: aws sqs create-queue --queue-name testing
- name: Run Tests - name: Run Tests
run: | run: |
poetry run pytest --cov=./django_q --cov-report=xml uv run pytest --cov=./django_q --cov-report=xml --junitxml=pytest.xml --cov-report=term-missing:skip-covered | tee pytest-coverage.txt
env:
MONGO_HOST: "127.0.0.1"
REDIS_HOST: "127.0.0.1"
- name: Upload to coveralls
run: |
python -m pip install coveralls
coveralls --service=github
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COVERALLS_FLAG_NAME: python-${{ matrix.python-version }}-django-${{ matrix.django }}
COVERALLS_PARALLEL: true
finish: - name: Coverage comment
needs: test if: matrix.python-version == '3.13' && matrix.django == '5.2' && github.event_name == 'pull_request'
runs-on: ubuntu-latest uses: MishaKav/pytest-coverage-comment@v1
container: python:3.11-bookworm with:
steps: pytest-coverage-path: ./pytest-coverage.txt
- name: Upload to coveralls junitxml-path: ./pytest.xml
run: | report-only-changed-files: true
python -m pip install --upgrade pip
python -m pip install coveralls flake8 black
coveralls --service=github --finish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Check flake8/black
run: |
flake8 .
black --check .
+91
View File
@@ -1,5 +1,96 @@
# Changelog # Changelog
## [v1.11.1](https://github.com/django-q2/django-q2/tree/v1.11.1) (2026-08-26)
- Swap localstorage to ministack (#343) https://github.com/django-q2/django-q2/pull/343
- Show test coverage in github pull request comment (#344) https://github.com/django-q2/django-q2/pull/344
- Fix cluster requesting hardcoded unix-only fork context (#347) https://github.com/django-q2/django-q2/pull/347
## [v1.11.0](https://github.com/django-q2/django-q2/tree/v1.11.0) (2026-08-10)
- AttributeError when start_event is None, and guard process faster stop (#305) https://github.com/django-q2/django-q2/pull/305
- Add croniter as optional extra. (#336) https://github.com/django-q2/django-q2/pull/336
- Migrate poetry to uv (#337) https://github.com/django-q2/django-q2/pull/337
- Add support for python 3.13 and 3.14 (#338) https://github.com/django-q2/django-q2/pull/338
- Add django 6.1 support (#340) https://github.com/django-q2/django-q2/pull/340
- Postpone SECRET_KEY evaluation to the qcluster command execution (#332) https://github.com/django-q2/django-q2/pull/332
## [v1.10.0](https://github.com/django-q2/django-q2/tree/v1.10.0) (2026-05-01)
- fix: Fix incorrect signal import (#308) https://github.com/django-q2/django-q2/pull/308
- Add post_execute_in_worker signal (#309) https://github.com/django-q2/django-q2/pull/309
- Fix BadSignature after the default Django cache expires (#311) https://github.com/django-q2/django-q2/pull/311
- feat:add Simplified Chinese Translation (#314) https://github.com/django-q2/django-q2/pull/314
- Update Django Q2 compatibility information (#316) https://github.com/django-q2/django-q2/pull/316
- Don't close DB connection if async_task was called with sync=True (#301) https://github.com/django-q2/django-q2/pull/301
- Convert queue size and count to string in monitor (#319) https://github.com/django-q2/django-q2/pull/319
- Fix unbounded growth of Broker.set_stat cluster master list (#322) https://github.com/django-q2/django-q2/pull/322
- Update Python base image to 3.9-slim-bookworm (#325) https://github.com/django-q2/django-q2/pull/325
- feat: add ru locale and improve translations (#320) https://github.com/django-q2/django-q2/pull/320
## [v1.9.0](https://github.com/django-q2/django-q2/tree/v1.9.0) (2025-12-04)
- Django 6.0 support https://github.com/django-q2/django-q2/pull/307
- Fix to make tests work with redis-py > 5 https://github.com/django-q2/django-q2/pull/282
## [v1.8.0](https://github.com/django-q2/django-q2/tree/v1.8.0) (2025-04-25)
- Delete deprecated imports and unwrapping https://github.com/django-q2/django-q2/pull/261
- Remove disque from CI https://github.com/django-q2/django-q2/pull/270
- Avoid creating task run on Scheduler creation https://github.com/django-q2/django-q2/pull/268
- Update tested versions, add python 3.13 support and django 5.2 support. Drop python 3.8 support https://github.com/django-q2/django-q2/pull/271
- Move timeout function from ORM broker into class to allow easy customization https://github.com/django-q2/django-q2/pull/274
## [v1.7.6](https://github.com/django-q2/django-q2/tree/v1.7.6) (2025-01-12)
- Make poetry version fixed in CI https://github.com/django-q2/django-q2/pull/260
## [v1.7.5](https://github.com/django-q2/django-q2/tree/v1.7.5) (2025-01-12)
- perf: avoid checking success tasks when save limit is disabled https://github.com/django-q2/django-q2/pull/255
- Fix install path for CHANGELOG.md https://github.com/django-q2/django-q2/pull/258
## [v1.7.4](https://github.com/django-q2/django-q2/tree/v1.7.4) (2024-11-03)
- Decrease the MAX_RSS set in test_cluster::test_max_rss https://github.com/django-q2/django-q2/pull/240
- Fix BROKER_CLASS monkeypatch in test_brokers https://github.com/django-q2/django-q2/pull/239
- Fix 'receive_message_wait_time_seconds' SQS broker management https://github.com/django-q2/django-q2/pull/243
## [v1.7.3](https://github.com/django-q2/django-q2/tree/v1.7.3) (2024-10-15)
- Catch missing SEGALRM with AttributeError instead of ValueError https://github.com/django-q2/django-q2/pull/223
- Refactor timeout handling to handle AttributeError and ValueError for Windows users https://github.com/django-q2/django-q2/pull/234
- Fix type check for args in scheduler.py E721 https://github.com/django-q2/django-q2/pull/233
- Only trigger prometheus if configured https://github.com/django-q2/django-q2/pull/231
- Fix missing ack_id when finishing task https://github.com/django-q2/django-q2/pull/224
## [v1.7.2](https://github.com/django-q2/django-q2/tree/v1.7.2) (2024-09-09)
- Fix twine check
## [v1.7.1](https://github.com/django-q2/django-q2/tree/v1.7.1) (2024-09-08)
- Fixed date of v1.7.0
- Fixed README.rst formatting which is blocking release of latest version
## [v1.7.0](https://github.com/django-q2/django-q2/tree/v1.7.0) (2024-09-08)
**Merged pull requests:**
- Remove support for Django 3.2 and 4.1 https://github.com/django-q2/django-q2/pull/183
- Fix max attempts for value 1 https://github.com/django-q2/django-q2/pull/185
- Replace black/isort with ruff https://github.com/django-q2/django-q2/pull/188
- Fix repeating task after timeout https://github.com/django-q2/django-q2/pull/184
- fix: Oracle ORM backend compatibility #180 https://github.com/django-q2/django-q2/pull/186
- chore: Update CI for Django 4.2 Python 3.12 support https://github.com/django-q2/django-q2/pull/208
- chore: Add Support Django 5.1 https://github.com/django-q2/django-q2/pull/207
- Call mark_process_dead on worker pid if prometheus_client is installed https://github.com/django-q2/django-q2/pull/212
- Add example project https://github.com/django-q2/django-q2/pull/215
- Add index on succeeded tasks https://github.com/django-q2/django-q2/pull/164
## [v1.6.2](https://github.com/django-q2/django-q2/tree/v1.6.2) (2024-03-05) ## [v1.6.2](https://github.com/django-q2/django-q2/tree/v1.6.2) (2024-03-05)
**Merged pull requests:** **Merged pull requests:**
+1 -1
View File
@@ -1,4 +1,4 @@
FROM python:3.9 FROM python:3.12
ENV PYTHONUNBUFFERED 1 ENV PYTHONUNBUFFERED 1
RUN mkdir -p /app RUN mkdir -p /app
+7 -10
View File
@@ -1,5 +1,5 @@
# Sets the python version # Sets the python version
FROM python:3.9.5-slim FROM python:3.13-slim-bookworm
# Allows the logs generated by python apps to be rendered in the terminal # Allows the logs generated by python apps to be rendered in the terminal
ENV PYTHONUNBUFFERED 1 ENV PYTHONUNBUFFERED 1
@@ -7,18 +7,15 @@ ENV PYTHONUNBUFFERED 1
# Sets the default shell to bash # Sets the default shell to bash
ENV SHELL /bin/bash ENV SHELL /bin/bash
# Upgrades pip RUN set -ex \
RUN pip install --upgrade pip && apt update \
&& apt-get install gcc gettext python3-dev --yes
# Install poetry # Install UV
RUN pip install poetry RUN pip install uv==0.12.1
WORKDIR /app WORKDIR /app
COPY . . COPY . .
RUN poetry lock --no-update RUN uv sync --extra testing
RUN poetry config virtualenvs.create false
RUN poetry install -E testing
+31
View File
@@ -0,0 +1,31 @@
dev:
docker compose -f web-docker-compose.yaml up
build-test:
docker compose -f test-services-docker-compose.yaml build --no-cache
lock:
docker compose -f test-services-docker-compose.yaml run --rm django-q2 uv lock
test:
docker compose -f test-services-docker-compose.yaml run --rm django-q2 uv run pytest
shell:
docker compose -f test-services-docker-compose.yaml run --rm django-q2 uv run python manage.py shell
makemigrations:
docker compose -f test-services-docker-compose.yaml run --rm django-q2 uv run python manage.py makemigrations
migrate:
docker compose -f test-services-docker-compose.yaml run --rm django-q2 uv run python manage.py migrate
build-package:
docker compose -f test-services-docker-compose.yaml run --rm django-q2 uv run django-admin compilemessages
docker compose -f test-services-docker-compose.yaml run --rm django-q2 uv build
createsuperuser:
docker compose -f web-docker-compose.yaml run --rm web python manage.py createsuperuser
format:
docker compose -f test-services-docker-compose.yaml run --rm django-q2 uv run ruff format .
docker compose -f test-services-docker-compose.yaml run --rm django-q2 uv run ruff check . --fix
+24 -14
View File
@@ -1,7 +1,7 @@
A multiprocessing distributed task queue for Django A multiprocessing distributed task queue for Django
--------------------------------------------------- ---------------------------------------------------
|image0| |image1| |docs| |downloads| |image0| |image1| |downloads|
Django Q2 is a fork of Django Q. Big thanks to Ilan Steemers for starting this project. Unfortunately, development has stalled since June 2021. Django Q2 is the new updated version of Django Q, with dependencies updates, docs updates and several bug fixes. Original repository: https://github.com/Koed00/django-q Django Q2 is a fork of Django Q. Big thanks to Ilan Steemers for starting this project. Unfortunately, development has stalled since June 2021. Django Q2 is the new updated version of Django Q, with dependencies updates, docs updates and several bug fixes. Original repository: https://github.com/Koed00/django-q
@@ -35,10 +35,13 @@ See the `changelog <https://github.com/GDay/django-q2/blob/master/CHANGELOG.md>`
Requirements Requirements
~~~~~~~~~~~~ ~~~~~~~~~~~~
- `Django <https://www.djangoproject.com>`__ > = 3.2 - `Django <https://www.djangoproject.com>`__ 5.2, 6.0 and 6.1
- `Django-picklefield <https://github.com/gintas/django-picklefield>`__ - `Django-picklefield <https://github.com/gintas/django-picklefield>`__
Tested with: Python 3.8, 3.9, 3.10, 3.11 and 3.12. Works with Django 3.2.X, 4.1.X, 4.2.X and 5.0.X Tested with:
* Python 3.10 to 3.14.
* Django 5.2, 6.0 and 6.1.
Brokers Brokers
~~~~~~~ ~~~~~~~
@@ -197,6 +200,23 @@ Admin page or directly from your code:
For more info check the `Schedules <https://django-q2.readthedocs.org/en/latest/schedules.html>`__ documentation. For more info check the `Schedules <https://django-q2.readthedocs.org/en/latest/schedules.html>`__ documentation.
Development
~~~~~~~~~~~
There is an example project that you can use to develop with. Docker (compose) is being used to set everything up.
Please note that you will have to restart the django-q container when changes have been made to tasks or django-q.
You can start the example project with:
.. code:: bash
make dev
Create a superuser with:
.. code:: bash
make createsuperuser
Testing Testing
~~~~~~~ ~~~~~~~
@@ -204,7 +224,7 @@ Running tests is easy with docker compose, it will also start the necessary data
.. code:: bash .. code:: bash
docker-compose -f test-services-docker-compose.yaml run --rm django-q2 poetry run pytest make test
Locale Locale
~~~~~~ ~~~~~~
@@ -212,12 +232,6 @@ Locale
Currently available in English, German, Turkish, and French. Currently available in English, German, Turkish, and French.
Translation pull requests are always welcome. Translation pull requests are always welcome.
Todo
~~~~
- Better tests and coverage
- Less dependencies?
Acknowledgements Acknowledgements
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
@@ -234,9 +248,5 @@ Acknowledgements
:target: https://github.com/GDay/django-q2/actions?query=workflow%3Atests :target: https://github.com/GDay/django-q2/actions?query=workflow%3Atests
.. |image1| image:: https://coveralls.io/repos/github/GDay/django-q2/badge.svg?branch=master .. |image1| image:: https://coveralls.io/repos/github/GDay/django-q2/badge.svg?branch=master
:target: https://coveralls.io/github/GDay/django-q2?branch=master :target: https://coveralls.io/github/GDay/django-q2?branch=master
.. |docs| image:: https://readthedocs.org/projects/docs/badge/?version=latest
:alt: Documentation Status
:scale: 100
:target: https://django-q2.readthedocs.org/
.. |downloads| image:: https://img.shields.io/pypi/dm/django-q2 .. |downloads| image:: https://img.shields.io/pypi/dm/django-q2
:target: https://img.shields.io/pypi/dm/django-q2 :target: https://img.shields.io/pypi/dm/django-q2
@@ -0,0 +1 @@
aws sqs create-queue --queue-name testing
+1 -6
View File
@@ -1,8 +1,3 @@
import django VERSION = (1, 11, 1)
VERSION = (1, 6, 2)
if django.VERSION < (3, 2):
default_app_config = "django_q.apps.DjangoQConfig"
__all__ = ["conf", "cluster", "models", "tasks"] __all__ = ["conf", "cluster", "models", "tasks"]
+11 -1
View File
@@ -1,6 +1,8 @@
"""Admin module for Django.""" """Admin module for Django."""
from django.contrib import admin from django.contrib import admin
from django.db.models.expressions import OuterRef, Subquery from django.db.models.expressions import OuterRef, Subquery
from django.template.defaultfilters import truncatechars
from django.urls import reverse from django.urls import reverse
from django.utils.html import format_html from django.utils.html import format_html
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
@@ -59,6 +61,10 @@ class TaskAdmin(admin.ModelAdmin):
"""Set all fields readonly.""" """Set all fields readonly."""
return list(self.readonly_fields) + [field.name for field in obj._meta.fields] return list(self.readonly_fields) + [field.name for field in obj._meta.fields]
@admin.display(description=_("Time Taken"))
def time_taken(self, obj):
return obj.time_taken()
class FailAdmin(admin.ModelAdmin): class FailAdmin(admin.ModelAdmin):
"""model admin for failed tasks.""" """model admin for failed tasks."""
@@ -86,6 +92,10 @@ class FailAdmin(admin.ModelAdmin):
"""Set all fields readonly.""" """Set all fields readonly."""
return list(self.readonly_fields) + [field.name for field in obj._meta.fields] return list(self.readonly_fields) + [field.name for field in obj._meta.fields]
@admin.display(description=_("Short result"))
def short_result(self, obj):
return truncatechars(obj.result, 100)
class ScheduleAdmin(admin.ModelAdmin): class ScheduleAdmin(admin.ModelAdmin):
"""model admin for schedules""" """model admin for schedules"""
@@ -137,7 +147,7 @@ class ScheduleAdmin(admin.ModelAdmin):
url = reverse("admin:django_q_success_change", args=(obj.task_id,)) url = reverse("admin:django_q_success_change", args=(obj.task_id,))
else: else:
url = reverse("admin:django_q_failure_change", args=(obj.task_id,)) url = reverse("admin:django_q_failure_change", args=(obj.task_id,))
return format_html(f'<a href="{url}">[{obj.task_name}]</a>') return format_html('<a href="{}">[{}]</a>', url, obj.task_name)
return None return None
get_last_run.allow_tags = True get_last_run.allow_tags = True
+7 -2
View File
@@ -106,8 +106,13 @@ class Broker:
return return
key_list = self.cache.get(Conf.Q_STAT, []) key_list = self.cache.get(Conf.Q_STAT, [])
if key not in key_list: if key not in key_list:
# Prune stale entries whose per-stat value has expired, so the
# master list cannot grow without bound across cluster restarts.
key_list = [k for k in key_list if self.cache.get(k) is not None]
key_list.append(key) key_list.append(key)
self.cache.set(Conf.Q_STAT, key_list) # timeout=None: master list lifetime is managed by membership
# changes, not by TTL refresh on every heartbeat.
self.cache.set(Conf.Q_STAT, key_list, None)
return self.cache.set(key, value, timeout) return self.cache.set(key, value, timeout)
def get_stat(self, key: str): def get_stat(self, key: str):
@@ -182,7 +187,7 @@ def get_broker(list_key: str = None) -> Broker:
return ironmq.IronMQBroker(list_key=list_key) return ironmq.IronMQBroker(list_key=list_key)
# SQS # SQS
elif type(Conf.SQS) == dict: elif isinstance(Conf.SQS, dict):
from django_q.brokers import aws_sqs from django_q.brokers import aws_sqs
return aws_sqs.Sqs(list_key=list_key) return aws_sqs.Sqs(list_key=list_key)
+9 -7
View File
@@ -1,3 +1,5 @@
import copy
from boto3 import Session from boto3 import Session
from botocore.client import ClientError from botocore.client import ClientError
@@ -78,15 +80,15 @@ class Sqs(Broker):
@staticmethod @staticmethod
def get_connection(list_key: str = None) -> Session: def get_connection(list_key: str = None) -> Session:
config = Conf.SQS config_cloned = copy.deepcopy(Conf.SQS)
if "aws_region" in config: if "aws_region" in config_cloned:
config["region_name"] = config["aws_region"] config_cloned["region_name"] = config_cloned["aws_region"]
del config["aws_region"] del config_cloned["aws_region"]
if "receive_message_wait_time_seconds" in config: if "receive_message_wait_time_seconds" in config_cloned:
del config["receive_message_wait_time_seconds"] del config_cloned["receive_message_wait_time_seconds"]
return Session(**config) return Session(**config_cloned)
def get_queue(self): def get_queue(self):
self.sqs = self.connection.resource("sqs") self.sqs = self.connection.resource("sqs")
+4 -5
View File
@@ -10,10 +10,6 @@ from django_q.conf import Conf, logger
from django_q.models import OrmQ from django_q.models import OrmQ
def _timeout():
return timezone.now() + timedelta(seconds=Conf.RETRY)
class ORM(Broker): class ORM(Broker):
@staticmethod @staticmethod
def get_connection(list_key: str = None): def get_connection(list_key: str = None):
@@ -28,6 +24,9 @@ class ORM(Broker):
logger.debug("Broker in an atomic transaction") logger.debug("Broker in an atomic transaction")
return OrmQ.objects.using(Conf.ORM) return OrmQ.objects.using(Conf.ORM)
def timeout(self, task):
return timezone.now() + timedelta(seconds=Conf.RETRY)
def queue_size(self) -> int: def queue_size(self) -> int:
return ( return (
self.get_connection() self.get_connection()
@@ -75,7 +74,7 @@ class ORM(Broker):
if ( if (
self.get_connection() self.get_connection()
.filter(id=task.id, lock=task.lock) .filter(id=task.id, lock=task.lock)
.update(lock=_timeout()) .update(lock=self.timeout(task))
): ):
task_list.append((task.pk, task.payload)) task_list.append((task.pk, task.payload))
# else don't process, as another cluster has been faster than us on # else don't process, as another cluster has been faster than us on
+56 -6
View File
@@ -1,4 +1,6 @@
# Standard # Standard
import multiprocessing
import os
import signal import signal
import socket import socket
import uuid import uuid
@@ -21,7 +23,14 @@ from django.utils.translation import gettext_lazy as _
# Local # Local
from django_q.brokers import Broker, get_broker from django_q.brokers import Broker, get_broker
from django_q.conf import Conf, get_ppid, logger, psutil, setproctitle from django_q.conf import (
Conf,
get_ppid,
logger,
prometheus_multiprocess,
psutil,
setproctitle,
)
from django_q.humanhash import humanize from django_q.humanhash import humanize
from django_q.monitor import monitor from django_q.monitor import monitor
from django_q.pusher import pusher from django_q.pusher import pusher
@@ -31,6 +40,13 @@ from django_q.status import Stat, Status
from django_q.worker import worker from django_q.worker import worker
def get_mp_context():
if "fork" in multiprocessing.get_all_start_methods():
return multiprocessing.get_context("fork")
else:
return multiprocessing.get_context()
class Cluster: class Cluster:
def __init__(self, broker: Broker = None): def __init__(self, broker: Broker = None):
# Cluster do not need an init or default broker except for testing, # Cluster do not need an init or default broker except for testing,
@@ -52,7 +68,7 @@ class Cluster:
# Start Sentinel # Start Sentinel
self.stop_event = Event() self.stop_event = Event()
self.start_event = Event() self.start_event = Event()
self.sentinel = Process( self.sentinel = get_mp_context().Process(
target=Sentinel, target=Sentinel,
name=f"Process-{uuid.uuid4().hex}", name=f"Process-{uuid.uuid4().hex}",
args=( args=(
@@ -65,7 +81,30 @@ class Cluster:
) )
self.sentinel.start() self.sentinel.start()
logger.info(_("Q Cluster %(name)s starting.") % {"name": self.name}) logger.info(_("Q Cluster %(name)s starting.") % {"name": self.name})
while not self.start_event.is_set(): # Wait for the sentinel to set start_event by polling the event's state. We
# cannot call wait() as that will deadlock if a signal is received while blocked
# in wait(), as the sentinel will block in start_event.set() while this process
# is blocked in sentinel.join(). It is also necessary to check for start_event
# being set to None by the signal handler.
while self.start_event and not self.start_event.is_set():
# While waiting for the sentinel to start, also check for sentinel premature
# death
if not self.sentinel.is_alive():
if self.sentinel.exitcode == 0:
# the cluster was stopped via SIGTERM/SIGINT and sentinel early
# termination was intentional -- exit quietly
break
logger.error(
_(
"Q Cluster %(name)s failed to start. Sentinel exited "
"with exit code %(exitcode)s."
)
% {"name": self.name, "exitcode": self.sentinel.exitcode}
)
raise RuntimeError(
f"Q Cluster {self.name} failed to start: sentinel exited "
f"with code {self.sentinel.exitcode}"
)
sleep(0.1) sleep(0.1)
return self.pid return self.pid
@@ -182,7 +221,9 @@ class Sentinel:
""" """
:type target: function or class :type target: function or class
""" """
p = Process(target=target, args=args, name=f"Process-{uuid.uuid4().hex}") p = get_mp_context().Process(
target=target, args=args, name=f"Process-{uuid.uuid4().hex}"
)
p.daemon = True p.daemon = True
if target == worker: if target == worker:
p.daemon = Conf.DAEMONIZE_WORKERS p.daemon = Conf.DAEMONIZE_WORKERS
@@ -223,6 +264,14 @@ class Sentinel:
% {"name": process.name} % {"name": process.name}
) )
else: else:
# check if prometheus is proper configurated
prometheus_path = os.getenv(
"PROMETHEUS_MULTIPROC_DIR", os.getenv("prometheus_multiproc_dir")
)
if prometheus_multiprocess and prometheus_path:
prometheus_multiprocess.mark_process_dead(process.pid)
self.pool.remove(process) self.pool.remove(process)
self.spawn_worker() self.spawn_worker()
if process.timer.value == 0: if process.timer.value == 0:
@@ -297,7 +346,7 @@ class Sentinel:
counter = 0 counter = 0
cycle = Conf.GUARD_CYCLE # guard loop sleep in seconds cycle = Conf.GUARD_CYCLE # guard loop sleep in seconds
# Guard loop. Runs at least once # Guard loop. Runs at least once
while not self.stop_event.is_set() or not counter: while True:
# Check Workers # Check Workers
for p in self.pool: for p in self.pool:
with p.timer.get_lock(): with p.timer.get_lock():
@@ -321,7 +370,8 @@ class Sentinel:
scheduler(broker=self.broker) scheduler(broker=self.broker)
# Save current status # Save current status
Stat(self).save() Stat(self).save()
sleep(cycle) if self.stop_event.wait(cycle):
break
self.stop() self.stop()
def stop(self): def stop(self):
+13 -3
View File
@@ -1,12 +1,13 @@
import logging import logging
import os import os
import signal
import sys import sys
from copy import deepcopy from copy import deepcopy
from multiprocessing import cpu_count from multiprocessing import cpu_count
from signal import signal
from warnings import warn from warnings import warn
from django.conf import settings from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django_q.queues import Queue from django_q.queues import Queue
@@ -38,6 +39,11 @@ try:
except ModuleNotFoundError: except ModuleNotFoundError:
setproctitle = None setproctitle = None
try:
from prometheus_client import multiprocess as prometheus_multiprocess
except ModuleNotFoundError:
prometheus_multiprocess = None
class Conf: class Conf:
""" """
@@ -206,7 +212,12 @@ class Conf:
# Use the secret key for package signing # Use the secret key for package signing
# Django itself should raise an error if it's not configured # Django itself should raise an error if it's not configured
SECRET_KEY = settings.SECRET_KEY # but suppress the exception early to allow other parts of the app to still run.
# For example any "python manage.py ..." command still runs even if SECRET_KEY is not set.
try:
SECRET_KEY = settings.SECRET_KEY
except ImproperlyConfigured:
SECRET_KEY = None
# The redis stats key # The redis stats key
Q_STAT = f"django_q:{PREFIX}:cluster" Q_STAT = f"django_q:{PREFIX}:cluster"
@@ -263,7 +274,6 @@ if not logger.hasHandlers():
# Error Reporting Interface # Error Reporting Interface
class ErrorReporter: class ErrorReporter:
# initialize with iterator of reporters (better name, targets?) # initialize with iterator of reporters (better name, targets?)
def __init__(self, reporters): def __init__(self, reporters):
self.targets = [target for target in reporters] self.targets = [target for target in reporters]
+8 -3
View File
@@ -2,17 +2,22 @@ import datetime
import time import time
import zlib import zlib
import django from django.core.signing import (
from django.core.signing import BadSignature, JSONSerializer, SignatureExpired BadSignature,
JSONSerializer,
SignatureExpired,
b64_decode,
dumps,
)
from django.core.signing import Signer as Sgnr from django.core.signing import Signer as Sgnr
from django.core.signing import TimestampSigner as TsS from django.core.signing import TimestampSigner as TsS
from django.core.signing import b64_decode, dumps
try: try:
from django.core.signing import b62_decode from django.core.signing import b62_decode
except ImportError: except ImportError:
# fallback for django 3.x # fallback for django 3.x
from django.utils.baseconv import base62 from django.utils.baseconv import base62
b62_decode = base62.decode b62_decode = base62.decode
from django.utils.crypto import constant_time_compare from django.utils.crypto import constant_time_compare
+7
View File
@@ -0,0 +1,7 @@
class TimeoutException(SystemExit):
"""
Exception for when a worker takes too long to complete a task
Raising SystemExit will make sure the function terminates gracefully.
"""
pass
+1 -4
View File
@@ -4,6 +4,7 @@ humanhash: Human-readable representations of digests.
The simplest ways to use this module are the :func:`humanize` and :func:`uuid` The simplest ways to use this module are the :func:`humanize` and :func:`uuid`
functions. For tighter control over the output, see :class:`HumanHasher`. functions. For tighter control over the output, see :class:`HumanHasher`.
""" """
import operator import operator
import uuid as uuidlib import uuid as uuidlib
from argparse import ArgumentError from argparse import ArgumentError
@@ -270,7 +271,6 @@ DEFAULT_WORDLIST = (
class HumanHasher: class HumanHasher:
""" """
Transforms hex digests to human-readable strings. Transforms hex digests to human-readable strings.
@@ -290,7 +290,6 @@ class HumanHasher:
self.wordlist = wordlist self.wordlist = wordlist
def humanize(self, hexdigest, words=4, separator="-"): def humanize(self, hexdigest, words=4, separator="-"):
""" """
Humanize a given hexadecimal digest. Humanize a given hexadecimal digest.
@@ -314,7 +313,6 @@ class HumanHasher:
@staticmethod @staticmethod
def compress(bytes, target): def compress(bytes, target):
""" """
Compress a list of byte values to a fixed target length. Compress a list of byte values to a fixed target length.
@@ -353,7 +351,6 @@ class HumanHasher:
return checksums return checksums
def uuid(self, **params): def uuid(self, **params):
""" """
Generate a UUID with a human-readable representation. Generate a UUID with a human-readable representation.
+433 -245
View File
@@ -6,7 +6,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-01-26 01:38+0000\n" "POT-Creation-Date: 2026-04-17 21:10+0000\n"
"PO-Revision-Date: 2018-08-05 18:28+0200\n" "PO-Revision-Date: 2018-08-05 18:28+0200\n"
"Last-Translator: Jonas Winkler\n" "Last-Translator: Jonas Winkler\n"
"Language-Team: \n" "Language-Team: \n"
@@ -17,37 +17,45 @@ msgstr ""
"X-Generator: Poedit 2.1.1\n" "X-Generator: Poedit 2.1.1\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: admin.py:43 #: admin.py:30
msgid "Resubmit selected tasks to queue" msgid "Resubmit selected tasks to queue"
msgstr "Ausgewählte Aufgaben erneut ausführen" msgstr "Ausgewählte Aufgaben erneut ausführen"
#: admin.py:107 models.py:293 #: admin.py:64
msgid "Time Taken"
msgstr ""
#: admin.py:95
msgid "Short result"
msgstr ""
#: admin.py:142 models.py:412
#, fuzzy #, fuzzy
#| msgid "Success" #| msgid "Success"
msgid "success" msgid "success"
msgstr "erfolg" msgstr "erfolg"
#: admin.py:119 models.py:295 #: admin.py:154 models.py:414
msgid "last_run" msgid "last_run"
msgstr "" msgstr ""
#: cluster.py:79 #: cluster.py:75
#, python-format #, python-format
msgid "Q Cluster %(name)s starting." msgid "Q Cluster %(name)s starting."
msgstr "Q-Cluster %(name)s wird gestartet." msgstr "Q-Cluster %(name)s wird gestartet."
#: cluster.py:87 #: cluster.py:83
#, fuzzy, python-format #, fuzzy, python-format
#| msgid "Q Cluster-{} stopping." #| msgid "Q Cluster-{} stopping."
msgid "Q Cluster %(name)s stopping." msgid "Q Cluster %(name)s stopping."
msgstr "Q-Cluster {name} wird gestoppt." msgstr "Q-Cluster {name} wird gestoppt."
#: cluster.py:90 #: cluster.py:86
#, python-format #, python-format
msgid "Q Cluster %(name)s has stopped." msgid "Q Cluster %(name)s has stopped."
msgstr "Q-Cluster %(name)s wurde gestoppt." msgstr "Q-Cluster %(name)s wurde gestoppt."
#: cluster.py:97 #: cluster.py:93
#, python-format #, python-format
msgid "%(name)s got signal %(signal)s" msgid "%(name)s got signal %(signal)s"
msgstr "%(name)s erhielt das Signal %(signal)s" msgstr "%(name)s erhielt das Signal %(signal)s"
@@ -62,7 +70,7 @@ msgstr "Monitor %(name)s wurde nach unerwartetem Absturz neu gestartet"
msgid "reincarnated pusher %(name)s after sudden death" msgid "reincarnated pusher %(name)s after sudden death"
msgstr "Pusher %(name)s wurde nach unerwartetem Absturz neu gestartet" msgstr "Pusher %(name)s wurde nach unerwartetem Absturz neu gestartet"
#: cluster.py:250 #: cluster.py:262
#, fuzzy, python-format #, fuzzy, python-format
#| msgid "reincarnated worker %(name)s after timeout" #| msgid "reincarnated worker %(name)s after timeout"
msgid "" msgid ""
@@ -70,123 +78,57 @@ msgid ""
"%(task_name)s" "%(task_name)s"
msgstr "Worker %(name)s wurde nach Zeitüberschreitung neu gestartet" msgstr "Worker %(name)s wurde nach Zeitüberschreitung neu gestartet"
#: cluster.py:255 #: cluster.py:265
#, python-format #, python-format
msgid "reincarnated worker %(name)s after timeout" msgid "reincarnated worker %(name)s after timeout"
msgstr "Worker %(name)s wurde nach Zeitüberschreitung neu gestartet" msgstr "Worker %(name)s wurde nach Zeitüberschreitung neu gestartet"
#: cluster.py:260 #: cluster.py:270
#, python-format #, python-format
msgid "recycled worker %(name)s" msgid "recycled worker %(name)s"
msgstr "Worker %(name)s wurde wiederverwendet" msgstr "Worker %(name)s wurde wiederverwendet"
#: cluster.py:263 #: cluster.py:273
#, python-format #, python-format
msgid "reincarnated worker %(name)s after death" msgid "reincarnated worker %(name)s after death"
msgstr "Worker %(name)s wurde nach unerwartetem Absturz neu gestartet" msgstr "Worker %(name)s wurde nach unerwartetem Absturz neu gestartet"
#: cluster.py:287 #: cluster.py:297
#, python-format #, python-format
msgid "%(name)s guarding cluster %(cluster_name)s" msgid "%(name)s guarding cluster %(cluster_name)s"
msgstr "%(name)s beschützt das Cluster %(cluster_name)s" msgstr "%(name)s beschützt das Cluster %(cluster_name)s"
#: cluster.py:296 #: cluster.py:307
#, python-format #, python-format
msgid "Q Cluster %(cluster_name)s running." msgid "Q Cluster %(cluster_name)s running."
msgstr "Q-Cluster %(cluster_name)s läuft." msgstr "Q-Cluster %(cluster_name)s läuft."
#: cluster.py:332 #: cluster.py:346
#, python-format #, python-format
msgid "%(name)s stopping cluster processes" msgid "%(name)s stopping cluster processes"
msgstr "%(name)s hält Cluster-Prozesse an" msgstr "%(name)s hält Cluster-Prozesse an"
#: cluster.py:357 #: cluster.py:371
#, python-format #, python-format
msgid "%(name)s waiting for the monitor." msgid "%(name)s waiting for the monitor."
msgstr "%(name)s wartet auf den Monitor." msgstr "%(name)s wartet auf den Monitor."
#: cluster.py:383 #: cluster.py:394
#, fuzzy, python-format
#| msgid "%(process_name)s pushing tasks at %(id)s"
msgid "%(name)s pushing tasks at %(id)s"
msgstr "%(process_name)s veröffentlicht Aufagaben auf %(id)s"
#: cluster.py:407
#, python-format
msgid "queueing from %(list_key)s"
msgstr "Einreihen von %(list_key)s"
#: cluster.py:411
#, python-format
msgid "%(name)s stopped pushing tasks"
msgstr "%(name)s veröffentlicht keine Aufgaben mehr"
#: cluster.py:426
#, python-format
msgid "%(name)s monitoring at %(id)s"
msgstr "%(name)s beobachtet auf %(id)s"
#: cluster.py:445
#, python-format
msgid "Processed '%(info_name)s' (%(task_name)s)"
msgstr "[%(task_name)s] - '%(info_name)s' wurde verarbeitet"
#: cluster.py:451
#, python-format
msgid "Failed '%(info_name)s' (%(task_name)s) - %(task_result)s"
msgstr "'%(info_name)s' (%(task_name)s) ist fehlgeschlagen - %(task_result)s"
#: cluster.py:458
#, python-format
msgid "%(name)s stopped monitoring results"
msgstr "%(name)s überwacht keine Ergebnisse mehr"
#: cluster.py:474
#, python-format
msgid "%(proc_name)s ready for work at %(id)s"
msgstr "%(proc_name)s ist bereit für Arbeit auf %(id)s"
#: cluster.py:494
#, fuzzy, python-format
#| msgid "%(proc_name)s processing '%(func_name)s' (%(task_name)s)"
msgid "%(proc_name)s processing %(task_name)s '%(func_name)s'"
msgstr "%(proc_name)s verarbeitet '%(func_name)s' (%(task_name)s)"
#: cluster.py:546
#, python-format
msgid "%(proc_name)s stopped doing work"
msgstr "%(proc_name)s hat die Arbeit beendet"
#: cluster.py:751
#, python-format
msgid "%(process_name)s failed to create a task from schedule [%(schedule)s]"
msgstr ""
"%(process_name)s konnte keine Aufgabe von Zeitplan [%(schedule)s] erstellen"
#: cluster.py:762
#, fuzzy, python-format
#| msgid "%(process_name)s created a task from schedule [%(schedule)s]"
msgid ""
"%(process_name)s created task %(task_name)s from schedule [%(schedule)s]"
msgstr ""
"%(process_name)s hat eine Aufgabe des Zeitplans [%(schedule)s] erstellt"
#: cluster.py:808
msgid "Skipping cpu affinity because psutil was not found." msgid "Skipping cpu affinity because psutil was not found."
msgstr "Cpu-Affinität wird übersprungen, da psutil nicht gefunden wurde." msgstr "Cpu-Affinität wird übersprungen, da psutil nicht gefunden wurde."
#: cluster.py:813 #: cluster.py:399
msgid "Faking cpu affinity because it is not supported on this platform" msgid "Faking cpu affinity because it is not supported on this platform"
msgstr "" msgstr ""
"Vortäuschen von CPU-Affinität, da diese auf dieser Plattform nicht " "Vortäuschen von CPU-Affinität, da diese auf dieser Plattform nicht "
"unterstützt wird" "unterstützt wird"
#: cluster.py:835 #: cluster.py:421
#, python-format #, python-format
msgid "%(pid)s will use cpu %(affinity)s" msgid "%(pid)s will use cpu %(affinity)s"
msgstr "%(pid)s wird CPU %(affinity)s benutzen" msgstr "%(pid)s wird CPU %(affinity)s benutzen"
#: conf.py:90 #: conf.py:122
#, python-format #, python-format
msgid "" msgid ""
"SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', " "SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', "
@@ -196,28 +138,28 @@ msgstr ""
"'group', 'name', 'func' und None. Standard ist None." "'group', 'name', 'func' und None. Standard ist None."
#. Translators: Cluster status descriptions #. Translators: Cluster status descriptions
#: conf.py:207 #: conf.py:239
msgid "Starting" msgid "Starting"
msgstr "Wird gestartet" msgstr "Wird gestartet"
#: conf.py:208 #: conf.py:240
msgid "Working" msgid "Working"
msgstr "Arbeitet" msgstr "Arbeitet"
#: conf.py:209 #: conf.py:241
msgid "Idle" msgid "Idle"
msgstr "Leerlauf" msgstr "Leerlauf"
#: conf.py:210 #: conf.py:242
msgid "Stopped" msgid "Stopped"
msgstr "Gestoppt" msgstr "Gestoppt"
#: conf.py:211 #: conf.py:243
msgid "Stopping" msgid "Stopping"
msgstr "Wird gestoppt" msgstr "Wird gestoppt"
#. Translators: help text for qcluster management command #. Translators: help text for qcluster management command
#: management/commands/qcluster.py:9 #: management/commands/qcluster.py:11
msgid "Starts a Django Q Cluster." msgid "Starts a Django Q Cluster."
msgstr "Startet ein Django-Q-Cluster." msgstr "Startet ein Django-Q-Cluster."
@@ -236,253 +178,479 @@ msgstr "Überwacht die Speichernutzung von Q Cluster"
msgid "Monitors Q Cluster activity" msgid "Monitors Q Cluster activity"
msgstr "Q-Cluster aktiv überwachen" msgstr "Q-Cluster aktiv überwachen"
#: models.py:125 #: models.py:30 models.py:469
msgid "Successful task" msgid "Task id"
msgstr "Erfolgreiche Aufgabe" msgstr ""
#: models.py:126 #: models.py:31
msgid "Successful tasks" msgid "32-character task identifier."
msgstr "Erfolgreiche Aufgaben" msgstr ""
#: models.py:141 #: models.py:36 models.py:235 models.py:470
msgid "Failed task" msgid "Name"
msgstr "Fehlgeschlagene Aufgabe" msgstr ""
#: models.py:142 #: models.py:37
msgid "Failed tasks" msgid "Optional human-readable name for lookup and display."
msgstr "Fehlgeschlagene Aufgaben" msgstr ""
#: models.py:150 models.py:234 #: models.py:41 models.py:240 models.py:468
msgid "Please install croniter to enable cron expressions" msgid "Function"
msgstr "Bitte installieren Sie croniter, um Cron-Ausdrücke zu aktivieren" msgstr ""
#: models.py:170 #: models.py:42
msgid "e.g. 1, 2, 'John'" msgid "Dotted import path to the callable, e.g. myapp.tasks.job."
msgstr "zum Beispiel 1, 2, 'John'" msgstr ""
#: models.py:172 #: models.py:47 models.py:247
msgid "e.g. x=1, y=2, name='John'" msgid "Hook"
msgstr "zum Beispiel x=1, y=2, name='John'" msgstr ""
#: models.py:186 #: models.py:48
msgid "Once" msgid "Optional dotted path to a callback that receives the task result."
msgstr "Einmal" msgstr ""
#: models.py:187 #: models.py:53 models.py:253 models.py:472
msgid "Minutes" msgid "Arguments"
msgstr "Minuten" msgstr ""
#: models.py:188 #: models.py:54
msgid "Hourly" msgid "Pickled positional arguments (tuple)."
msgstr "Stündlich" msgstr ""
#: models.py:189 #: models.py:59 models.py:259 models.py:473
msgid "Daily" msgid "Keyword arguments"
msgstr "Täglich" msgstr ""
#: models.py:190 #: models.py:60
msgid "Weekly" msgid "Pickled keyword arguments (dict)."
msgstr "Wöchentlich" msgstr ""
#: models.py:191 #: models.py:65
msgid "Biweekly" msgid "Result"
msgstr "Zweiwöchentlich" msgstr ""
#: models.py:192 #: models.py:66
msgid "Monthly" msgid "Pickled return value or error payload."
msgstr "Monatlich" msgstr ""
#: models.py:193 #: models.py:72 models.py:471
msgid "Bimonthly" msgid "Group"
msgstr "Zweimonatlich" msgstr ""
#: models.py:194 #: models.py:73
msgid "Quarterly" msgid "Optional group id to aggregate related tasks."
msgstr "Vierteljährlich" msgstr ""
#: models.py:195 #: models.py:80 models.py:328
msgid "Yearly" #, fuzzy
msgstr "Jährlich" #| msgid "Clusters"
msgid "Cluster"
msgstr "Cluster"
#: models.py:196 #: models.py:81
msgid "Cron" msgid "Name of the cluster that executed this task."
msgstr "Cron" msgstr ""
#: models.py:199 #: models.py:85
msgid "Schedule Type" msgid "Started at"
msgstr "Zeitplan-Typ" msgstr ""
#: models.py:202 #: models.py:86
msgid "Number of minutes for the Minutes type" msgid "When the worker started executing the task."
msgstr "Anzahl Minuten für den Typ 'Minuten'" msgstr ""
#: models.py:205 #: models.py:90
msgid "Repeats" #, fuzzy
msgstr "Wiederholungen" #| msgid "Stopped"
msgid "Stopped at"
msgstr "Gestoppt"
#: models.py:205 #: models.py:91
msgid "n = n times, -1 = forever" msgid "When the worker finished (success or failure)."
msgstr "n = n mal, -1 = für immer" msgstr ""
#: models.py:208 #: models.py:96 monitor_terminal.py:180
msgid "Next Run"
msgstr "Nächste Ausführung"
#: models.py:215
msgid "Cron expression"
msgstr "Cron-Ausdruck"
#: models.py:224
msgid "Name of kwarg to pass intended schedule date"
msgstr "Name des zu passierenden Kwargs vorgesehenes Datum"
#: models.py:299
msgid "Scheduled task"
msgstr "Geplante Aufgabe"
#: models.py:300
msgid "Scheduled tasks"
msgstr "Geplante Aufgaben"
#: models.py:326
msgid "Queued task"
msgstr "Eingereihte Aufgabe"
#: models.py:327
msgid "Queued tasks"
msgstr "Eingereihte Aufgaben"
#: monitor.py:64 monitor.py:348
msgid "Host"
msgstr "Host"
#: monitor.py:68 monitor.py:352 monitor.py:459
msgid "Id"
msgstr "Id"
#: monitor.py:72
msgid "State"
msgstr "Status"
#: monitor.py:76
msgid "Pool"
msgstr "Pool"
#: monitor.py:80
msgid "TQ"
msgstr "TQ"
#: monitor.py:84
msgid "RQ"
msgstr "RQ"
#: monitor.py:88
msgid "RC"
msgstr "RC"
#: monitor.py:92
msgid "Up"
msgstr "Up"
#: monitor.py:172 monitor.py:286
msgid "Queued"
msgstr "Eingereiht"
#: monitor.py:180
msgid "Success" msgid "Success"
msgstr "Erfolg" msgstr "Erfolg"
#: monitor.py:190 monitor.py:294 #: models.py:97
msgid "False if the task raised an exception or timed out."
msgstr ""
#: models.py:101
msgid "Attempt count"
msgstr ""
#: models.py:102
msgid "How many times execution was attempted."
msgstr ""
#: models.py:172
msgid "Task"
msgstr ""
#: models.py:173
msgid "Tasks"
msgstr ""
#: models.py:194
msgid "Successful task"
msgstr "Erfolgreiche Aufgabe"
#: models.py:195
msgid "Successful tasks"
msgstr "Erfolgreiche Aufgaben"
#: models.py:210
msgid "Failed task"
msgstr "Fehlgeschlagene Aufgabe"
#: models.py:211
msgid "Failed tasks"
msgstr "Fehlgeschlagene Aufgaben"
#: models.py:219 models.py:347
msgid "Please install croniter to enable cron expressions"
msgstr "Bitte installieren Sie croniter, um Cron-Ausdrücke zu aktivieren"
#: models.py:236
msgid "Optional label to identify this schedule in the admin."
msgstr ""
#: models.py:241
msgid "e.g. module.tasks.function"
msgstr ""
#: models.py:248
msgid "e.g. module.tasks.result_function"
msgstr ""
#: models.py:254
msgid "e.g. 1, 2, 'John'"
msgstr "zum Beispiel 1, 2, 'John'"
#: models.py:260
msgid "e.g. x=1, y=2, name='John'"
msgstr "zum Beispiel x=1, y=2, name='John'"
#: models.py:274
msgid "Once"
msgstr "Einmal"
#: models.py:275 models.py:296
msgid "Minutes"
msgstr "Minuten"
#: models.py:276
msgid "Hourly"
msgstr "Stündlich"
#: models.py:277
msgid "Daily"
msgstr "Täglich"
#: models.py:278
msgid "Weekly"
msgstr "Wöchentlich"
#: models.py:279
msgid "Biweekly"
msgstr "Zweiwöchentlich"
#: models.py:280
msgid "Monthly"
msgstr "Monatlich"
#: models.py:281
msgid "Bimonthly"
msgstr "Zweimonatlich"
#: models.py:282
msgid "Quarterly"
msgstr "Vierteljährlich"
#: models.py:283
msgid "Yearly"
msgstr "Jährlich"
#: models.py:284 models.py:313
msgid "Cron"
msgstr "Cron"
#: models.py:290
msgid "Schedule Type"
msgstr "Zeitplan-Typ"
#: models.py:291
msgid "How often this task should be enqueued."
msgstr ""
#: models.py:297
msgid "Number of minutes for the Minutes type"
msgstr "Anzahl Minuten für den Typ 'Minuten'"
#: models.py:300
msgid "Repeats"
msgstr "Wiederholungen"
#: models.py:300
msgid "n = n times, -1 = forever"
msgstr "n = n mal, -1 = für immer"
#: models.py:303
msgid "Next Run"
msgstr "Nächste Ausführung"
#: models.py:304
msgid "When this schedule runs next (stored in UTC)."
msgstr ""
#: models.py:314
msgid "Cron expression"
msgstr "Cron-Ausdruck"
#: models.py:320
msgid "Last task id"
msgstr ""
#: models.py:321
msgid "Id of the last task spawned from this schedule (read-only)."
msgstr ""
#: models.py:329 models.py:427
msgid "Name of the target cluster"
msgstr ""
#: models.py:336
msgid "Intended date kwarg"
msgstr ""
#: models.py:337
msgid "Name of kwarg to pass intended schedule date"
msgstr "Name des zu passierenden Kwargs vorgesehenes Datum"
#: models.py:418
msgid "Scheduled task"
msgstr "Geplante Aufgabe"
#: models.py:419
msgid "Scheduled tasks"
msgstr "Geplante Aufgaben"
#: models.py:426
#, fuzzy
#| msgid "Clusters"
msgid "Cluster key"
msgstr "Cluster"
#: models.py:430
msgid "Payload"
msgstr ""
#: models.py:431
msgid "Signed serialized task package (do not edit manually)."
msgstr ""
#: models.py:435
msgid "Lock until"
msgstr ""
#: models.py:436
msgid "Prevent any cluster from pulling until"
msgstr ""
#: models.py:474
#, fuzzy
#| msgid "Queued task"
msgid "Queue options"
msgstr "Eingereihte Aufgabe"
#: models.py:478
msgid "Queued task"
msgstr "Eingereihte Aufgabe"
#: models.py:479
msgid "Queued tasks"
msgstr "Eingereihte Aufgaben"
#: monitor.py:41
#, python-format
msgid "%(name)s monitoring at %(id)s"
msgstr "%(name)s beobachtet auf %(id)s"
#: monitor.py:61
#, python-format
msgid "Processed '%(info_name)s' (%(task_name)s)"
msgstr "[%(task_name)s] - '%(info_name)s' wurde verarbeitet"
#: monitor.py:67
#, python-format
msgid "Failed '%(info_name)s' (%(task_name)s) - %(task_result)s"
msgstr "'%(info_name)s' (%(task_name)s) ist fehlgeschlagen - %(task_result)s"
#: monitor.py:74
#, python-format
msgid "%(name)s stopped monitoring results"
msgstr "%(name)s überwacht keine Ergebnisse mehr"
#: monitor_terminal.py:64 monitor_terminal.py:348
msgid "Host"
msgstr "Host"
#: monitor_terminal.py:68 monitor_terminal.py:352 monitor_terminal.py:457
msgid "Id"
msgstr "Id"
#: monitor_terminal.py:72
msgid "State"
msgstr "Status"
#: monitor_terminal.py:76
msgid "Pool"
msgstr "Pool"
#: monitor_terminal.py:80
msgid "TQ"
msgstr "TQ"
#: monitor_terminal.py:84
msgid "RQ"
msgstr "RQ"
#: monitor_terminal.py:88
msgid "RC"
msgstr "RC"
#: monitor_terminal.py:92
msgid "Up"
msgstr "Up"
#: monitor_terminal.py:172 monitor_terminal.py:286
msgid "Queued"
msgstr "Eingereiht"
#: monitor_terminal.py:190 monitor_terminal.py:294
msgid "Failures" msgid "Failures"
msgstr "Fehlschläge" msgstr "Fehlschläge"
#: monitor.py:201 monitor.py:498 #: monitor_terminal.py:201 monitor_terminal.py:496
msgid "[Press q to quit]" msgid "[Press q to quit]"
msgstr "[Drücken Sie q zum Beenden]" msgstr "[Drücken Sie q zum Beenden]"
#: monitor.py:227 #: monitor_terminal.py:227
msgid "day" msgid "day"
msgstr "Tag" msgstr "Tag"
#: monitor.py:248 #: monitor_terminal.py:248
msgid "second" msgid "second"
msgstr "Sekunde" msgstr "Sekunde"
#: monitor.py:251 #: monitor_terminal.py:251
msgid "minute" msgid "minute"
msgstr "Minute" msgstr "Minute"
#: monitor.py:254 #: monitor_terminal.py:254
msgid "hour" msgid "hour"
msgstr "Stunde" msgstr "Stunde"
#: monitor.py:263 #: monitor_terminal.py:263
#, python-format #, python-format
msgid "-- %(prefix)s %(version)s on %(info)s --" msgid "-- %(prefix)s %(version)s on %(info)s --"
msgstr "-- %(prefix)s %(version)s auf %(info)s --" msgstr "-- %(prefix)s %(version)s auf %(info)s --"
#: monitor.py:273 #: monitor_terminal.py:273
msgid "Clusters" msgid "Clusters"
msgstr "Cluster" msgstr "Cluster"
#: monitor.py:277 #: monitor_terminal.py:277
msgid "Workers" msgid "Workers"
msgstr "Arbeiter" msgstr "Arbeiter"
#: monitor.py:281 #: monitor_terminal.py:281
msgid "Restarts" msgid "Restarts"
msgstr "Neustarts" msgstr "Neustarts"
#: monitor.py:290 #: monitor_terminal.py:290
msgid "Successes" msgid "Successes"
msgstr "Erfolge" msgstr "Erfolge"
#: monitor.py:299 #: monitor_terminal.py:299
msgid "Schedules" msgid "Schedules"
msgstr "Zeitpläne" msgstr "Zeitpläne"
#: monitor.py:303 #: monitor_terminal.py:303
#, python-format #, python-format
msgid "Tasks/%(per)s" msgid "Tasks/%(per)s"
msgstr "Aufgaben/%(per)s" msgstr "Aufgaben/%(per)s"
#: monitor.py:307 #: monitor_terminal.py:307
msgid "Avg time" msgid "Avg time"
msgstr "Durchschnittl. Zeit" msgstr "Durchschnittl. Zeit"
#: monitor.py:357 #: monitor_terminal.py:357
msgid "Available (%)" msgid "Available (%)"
msgstr "Verfügbar (%)" msgstr "Verfügbar (%)"
#: monitor.py:363 #: monitor_terminal.py:363
msgid "Available (MB)" msgid "Available (MB)"
msgstr "Verfügbar (MB)" msgstr "Verfügbar (MB)"
#: monitor.py:368 #: monitor_terminal.py:368
msgid "Total (MB)" msgid "Total (MB)"
msgstr "Insgesamt (MB)" msgstr "Insgesamt (MB)"
#: monitor.py:373 #: monitor_terminal.py:373
msgid "Sentinel (MB)" msgid "Sentinel (MB)"
msgstr "Sentinel (MB)" msgstr "Sentinel (MB)"
#: monitor.py:379 #: monitor_terminal.py:379
msgid "Monitor (MB)" msgid "Monitor (MB)"
msgstr "Monitor (MB)" msgstr "Monitor (MB)"
#: monitor.py:385 #: monitor_terminal.py:385
msgid "Workers (MB)" msgid "Workers (MB)"
msgstr "Arbeiter (MB)" msgstr "Arbeiter (MB)"
#: monitor.py:487 #: monitor_terminal.py:485
#, python-format #, python-format
msgid "Available lowest (): %(memory_percent)s ((at)s)" msgid "Available lowest (): %(memory_percent)s ((at)s)"
msgstr "Niedrigste verfügbar (): %(memory_percent)s ((at)s)" msgstr "Niedrigste verfügbar (): %(memory_percent)s ((at)s)"
#: monitor.py:509 #: monitor_terminal.py:507
msgid "No clusters appear to be running." msgid "No clusters appear to be running."
msgstr "Es scheinen keine Cluster zu laufen." msgstr "Es scheinen keine Cluster zu laufen."
#: pusher.py:40
#, python-format
#| msgid "%(process_name)s pushing tasks at %(id)s"
msgid "%(name)s pushing tasks at %(id)s"
msgstr "%(name)s veröffentlicht Aufagaben auf %(id)s"
#: pusher.py:67
#, python-format
msgid "queueing from %(list_key)s"
msgstr "Einreihen von %(list_key)s"
#: pusher.py:71
#, python-format
msgid "%(name)s stopped pushing tasks"
msgstr "%(name)s veröffentlicht keine Aufgaben mehr"
#: scheduler.py:110
#, python-format
msgid "%(process_name)s failed to create a task from schedule [%(schedule)s]"
msgstr ""
"%(process_name)s konnte keine Aufgabe von Zeitplan [%(schedule)s] erstellen"
#: scheduler.py:121
#, fuzzy, python-format
#| msgid "%(process_name)s created a task from schedule [%(schedule)s]"
msgid ""
"%(process_name)s created task %(task_name)s from schedule [%(schedule)s]"
msgstr ""
"%(process_name)s hat eine Aufgabe des Zeitplans [%(schedule)s] erstellt"
#: signals.py:22 #: signals.py:22
#, python-format #, python-format
msgid "malformed return hook '%(hook)s' for [%(name)s]" msgid "malformed return hook '%(hook)s' for [%(name)s]"
@@ -493,6 +661,26 @@ msgstr "Ungültiger Return-Hook '%(hook)s' für [%(name)s]"
msgid "return hook %(hook)s failed on [%(name)s] because %(error)s" msgid "return hook %(hook)s failed on [%(name)s] because %(error)s"
msgstr "Return-Hook %(hook)s für [%(name)s] ist gescheitert: %(error)s" msgstr "Return-Hook %(hook)s für [%(name)s] ist gescheitert: %(error)s"
#: timeout.py:30 timeout.py:43
msgid "SIGALARM is not available on your platform"
msgstr ""
#: worker.py:49
#, python-format
msgid "%(proc_name)s ready for work at %(id)s"
msgstr "%(proc_name)s ist bereit für Arbeit auf %(id)s"
#: worker.py:69
#, fuzzy, python-format
#| msgid "%(proc_name)s processing '%(func_name)s' (%(task_name)s)"
msgid "%(proc_name)s processing %(task_name)s '%(func_name)s'"
msgstr "%(proc_name)s verarbeitet '%(func_name)s' (%(task_name)s)"
#: worker.py:135
#, python-format
msgid "%(proc_name)s stopped doing work"
msgstr "%(proc_name)s hat die Arbeit beendet"
#, python-format #, python-format
#~ msgid "" #~ msgid ""
#~ "Could not process '%(func_name)s'. Check the location of the function and " #~ "Could not process '%(func_name)s'. Check the location of the function and "
+343 -155
View File
@@ -6,7 +6,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-01-26 01:38+0000\n" "POT-Creation-Date: 2026-04-17 21:10+0000\n"
"PO-Revision-Date: 2018-08-05 18:28+0200\n" "PO-Revision-Date: 2018-08-05 18:28+0200\n"
"Last-Translator: Thierry BOULOGNE <contact@tng-concepts.com>\n" "Last-Translator: Thierry BOULOGNE <contact@tng-concepts.com>\n"
"Language-Team: \n" "Language-Team: \n"
@@ -17,36 +17,44 @@ msgstr ""
"X-Generator: Poedit 2.1.1\n" "X-Generator: Poedit 2.1.1\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: admin.py:43 #: admin.py:30
msgid "Resubmit selected tasks to queue" msgid "Resubmit selected tasks to queue"
msgstr "Resoumettre les tâches sélectionnées à la file d'attente" msgstr "Resoumettre les tâches sélectionnées à la file d'attente"
#: admin.py:107 models.py:293 #: admin.py:64
msgid "Time Taken"
msgstr ""
#: admin.py:95
msgid "Short result"
msgstr ""
#: admin.py:142 models.py:412
#, fuzzy #, fuzzy
#| msgid "Success" #| msgid "Success"
msgid "success" msgid "success"
msgstr "succès" msgstr "succès"
#: admin.py:119 models.py:295 #: admin.py:154 models.py:414
msgid "last_run" msgid "last_run"
msgstr "" msgstr ""
#: cluster.py:79 #: cluster.py:75
#, python-format #, python-format
msgid "Q Cluster %(name)s starting." msgid "Q Cluster %(name)s starting."
msgstr "Démarrage de Q Cluster-%(name)s." msgstr "Démarrage de Q Cluster-%(name)s."
#: cluster.py:87 #: cluster.py:83
#, python-format #, python-format
msgid "Q Cluster %(name)s stopping." msgid "Q Cluster %(name)s stopping."
msgstr "Arrêt de Q Cluster-%(name)s." msgstr "Arrêt de Q Cluster-%(name)s."
#: cluster.py:90 #: cluster.py:86
#, python-format #, python-format
msgid "Q Cluster %(name)s has stopped." msgid "Q Cluster %(name)s has stopped."
msgstr "Q Cluster-%(name)s a été arrêté." msgstr "Q Cluster-%(name)s a été arrêté."
#: cluster.py:97 #: cluster.py:93
#, python-format #, python-format
msgid "%(name)s got signal %(signal)s" msgid "%(name)s got signal %(signal)s"
msgstr "%(name)s à reçu le signal %(signal)s" msgstr "%(name)s à reçu le signal %(signal)s"
@@ -61,7 +69,7 @@ msgstr "surveillant %(name)s réincarné après un arrêt intempestif"
msgid "reincarnated pusher %(name)s after sudden death" msgid "reincarnated pusher %(name)s after sudden death"
msgstr "répartiteur %(name)s réincarné après un arrêt intempestif" msgstr "répartiteur %(name)s réincarné après un arrêt intempestif"
#: cluster.py:250 #: cluster.py:262
#, python-format #, python-format
msgid "" msgid ""
"reincarnated worker %(name)s after timeout while processing task " "reincarnated worker %(name)s after timeout while processing task "
@@ -70,122 +78,57 @@ msgstr ""
"processus %(name)s réincarné, délai de traitement dépassé pour la tâche " "processus %(name)s réincarné, délai de traitement dépassé pour la tâche "
"%(task_name)s" "%(task_name)s"
#: cluster.py:255 #: cluster.py:265
#, python-format #, python-format
msgid "reincarnated worker %(name)s after timeout" msgid "reincarnated worker %(name)s after timeout"
msgstr "processus %(name)s réincarné, délai de traitement dépassé" msgstr "processus %(name)s réincarné, délai de traitement dépassé"
#: cluster.py:260 #: cluster.py:270
#, python-format #, python-format
msgid "recycled worker %(name)s" msgid "recycled worker %(name)s"
msgstr "processus recyclé %(name)s" msgstr "processus recyclé %(name)s"
#: cluster.py:263 #: cluster.py:273
#, python-format #, python-format
msgid "reincarnated worker %(name)s after death" msgid "reincarnated worker %(name)s after death"
msgstr "processus réintégré %(name)s après arrêt" msgstr "processus réintégré %(name)s après arrêt"
#: cluster.py:287 #: cluster.py:297
#, python-format #, python-format
msgid "%(name)s guarding cluster %(cluster_name)s" msgid "%(name)s guarding cluster %(cluster_name)s"
msgstr "%(name)s surveillance du cluster à %(cluster_name)s" msgstr "%(name)s surveillance du cluster à %(cluster_name)s"
#: cluster.py:296 #: cluster.py:307
#, python-format #, python-format
msgid "Q Cluster %(cluster_name)s running." msgid "Q Cluster %(cluster_name)s running."
msgstr "Démarrage de Q Cluster-%(cluster_name)s." msgstr "Démarrage de Q Cluster-%(cluster_name)s."
#: cluster.py:332 #: cluster.py:346
#, python-format #, python-format
msgid "%(name)s stopping cluster processes" msgid "%(name)s stopping cluster processes"
msgstr "%(name)s arrêt des processus du cluster" msgstr "%(name)s arrêt des processus du cluster"
#: cluster.py:357 #: cluster.py:371
#, python-format #, python-format
msgid "%(name)s waiting for the monitor." msgid "%(name)s waiting for the monitor."
msgstr "%(name)s en attente du surveillant." msgstr "%(name)s en attente du surveillant."
#: cluster.py:383 #: cluster.py:394
#, python-format
msgid "%(name)s pushing tasks at %(id)s"
msgstr "%(name)s répartit les tâches %(id)s"
#: cluster.py:407
#, python-format
msgid "queueing from %(list_key)s"
msgstr "mise en file d'attente de %(list_key)s"
#: cluster.py:411
#, python-format
msgid "%(name)s stopped pushing tasks"
msgstr "%(name)s a cessé de répartir les tâches"
#: cluster.py:426
#, python-format
msgid "%(name)s monitoring at %(id)s"
msgstr "%(name)s surveille les résultats %(id)s"
#: cluster.py:445
#, python-format
msgid "Processed '%(info_name)s' (%(task_name)s)"
msgstr "traité '%(info_name)s' (%(task_name)s)"
#: cluster.py:451
#, python-format
msgid "Failed '%(info_name)s' (%(task_name)s) - %(task_result)s"
msgstr "Manqué '%(info_name)s' (%(task_name)s) - %(task_result)s"
#: cluster.py:458
#, python-format
msgid "%(name)s stopped monitoring results"
msgstr "%(name)s a cessé de de surveiller les résultats"
#: cluster.py:474
#, python-format
msgid "%(proc_name)s ready for work at %(id)s"
msgstr "%(proc_name)s prêt pour le travail à %(id)s"
#: cluster.py:494
#, fuzzy, python-format
msgid "%(proc_name)s processing %(task_name)s '%(func_name)s'"
msgstr "%(proc_name)s exécute %(task_name)s '%(func_name)s'"
#: cluster.py:546
#, python-format
msgid "%(proc_name)s stopped doing work"
msgstr "%(proc_name)s a cessé de travailler"
#: cluster.py:751
#, python-format
msgid "%(process_name)s failed to create a task from schedule [%(schedule)s]"
msgstr ""
"%(process_name)s Echec de la création d'une tâche à partir de Schedule "
"[%(schedule)s]"
#: cluster.py:762
#, python-format
msgid ""
"%(process_name)s created task %(task_name)s from schedule [%(schedule)s]"
msgstr ""
"%(process_name)s a créé la tâche %(task_name)s à partir de Schedule "
"[%(schedule)s]"
#: cluster.py:808
msgid "Skipping cpu affinity because psutil was not found." msgid "Skipping cpu affinity because psutil was not found."
msgstr "L'affinité cpu ne sera pas définie car psutil n'a pas été trouvé." msgstr "L'affinité cpu ne sera pas définie car psutil n'a pas été trouvé."
#: cluster.py:813 #: cluster.py:399
msgid "Faking cpu affinity because it is not supported on this platform" msgid "Faking cpu affinity because it is not supported on this platform"
msgstr "" msgstr ""
"Simulation de l'affinité cpu parce qu'elle n'est pas supportée sur cette " "Simulation de l'affinité cpu parce qu'elle n'est pas supportée sur cette "
"plateforme." "plateforme."
#: cluster.py:835 #: cluster.py:421
#, python-format #, python-format
msgid "%(pid)s will use cpu %(affinity)s" msgid "%(pid)s will use cpu %(affinity)s"
msgstr "%(pid)s utilisera le CPU %(affinity)s" msgstr "%(pid)s utilisera le CPU %(affinity)s"
#: conf.py:90 #: conf.py:122
#, python-format #, python-format
msgid "" msgid ""
"SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', " "SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', "
@@ -195,28 +138,28 @@ msgstr ""
"'group', 'name', 'func' et None. La valeur par défaut est None." "'group', 'name', 'func' et None. La valeur par défaut est None."
#. Translators: Cluster status descriptions #. Translators: Cluster status descriptions
#: conf.py:207 #: conf.py:239
msgid "Starting" msgid "Starting"
msgstr "Démarrage" msgstr "Démarrage"
#: conf.py:208 #: conf.py:240
msgid "Working" msgid "Working"
msgstr "Actif" msgstr "Actif"
#: conf.py:209 #: conf.py:241
msgid "Idle" msgid "Idle"
msgstr "En attente" msgstr "En attente"
#: conf.py:210 #: conf.py:242
msgid "Stopped" msgid "Stopped"
msgstr "Arrêté" msgstr "Arrêté"
#: conf.py:211 #: conf.py:243
msgid "Stopping" msgid "Stopping"
msgstr "En cours darrêt" msgstr "En cours darrêt"
#. Translators: help text for qcluster management command #. Translators: help text for qcluster management command
#: management/commands/qcluster.py:9 #: management/commands/qcluster.py:11
msgid "Starts a Django Q Cluster." msgid "Starts a Django Q Cluster."
msgstr "Démarre un cluster Django Q." msgstr "Démarre un cluster Django Q."
@@ -237,259 +180,485 @@ msgstr "Surveille l'utilisation mémoire du Q cluster"
msgid "Monitors Q Cluster activity" msgid "Monitors Q Cluster activity"
msgstr "Surveille l'activité de Q cluster" msgstr "Surveille l'activité de Q cluster"
#: models.py:125 #: models.py:30 models.py:469
msgid "Task id"
msgstr ""
#: models.py:31
msgid "32-character task identifier."
msgstr ""
#: models.py:36 models.py:235 models.py:470
msgid "Name"
msgstr ""
#: models.py:37
msgid "Optional human-readable name for lookup and display."
msgstr ""
#: models.py:41 models.py:240 models.py:468
msgid "Function"
msgstr ""
#: models.py:42
msgid "Dotted import path to the callable, e.g. myapp.tasks.job."
msgstr ""
#: models.py:47 models.py:247
msgid "Hook"
msgstr ""
#: models.py:48
msgid "Optional dotted path to a callback that receives the task result."
msgstr ""
#: models.py:53 models.py:253 models.py:472
msgid "Arguments"
msgstr ""
#: models.py:54
msgid "Pickled positional arguments (tuple)."
msgstr ""
#: models.py:59 models.py:259 models.py:473
msgid "Keyword arguments"
msgstr ""
#: models.py:60
msgid "Pickled keyword arguments (dict)."
msgstr ""
#: models.py:65
msgid "Result"
msgstr ""
#: models.py:66
msgid "Pickled return value or error payload."
msgstr ""
#: models.py:72 models.py:471
msgid "Group"
msgstr ""
#: models.py:73
msgid "Optional group id to aggregate related tasks."
msgstr ""
#: models.py:80 models.py:328
#, fuzzy
#| msgid "Clusters"
msgid "Cluster"
msgstr "Grappes"
#: models.py:81
msgid "Name of the cluster that executed this task."
msgstr ""
#: models.py:85
msgid "Started at"
msgstr ""
#: models.py:86
msgid "When the worker started executing the task."
msgstr ""
#: models.py:90
#, fuzzy
#| msgid "Stopped"
msgid "Stopped at"
msgstr "Arrêté"
#: models.py:91
msgid "When the worker finished (success or failure)."
msgstr ""
#: models.py:96 monitor_terminal.py:180
msgid "Success"
msgstr "Succès"
#: models.py:97
msgid "False if the task raised an exception or timed out."
msgstr ""
#: models.py:101
msgid "Attempt count"
msgstr ""
#: models.py:102
msgid "How many times execution was attempted."
msgstr ""
#: models.py:172
msgid "Task"
msgstr ""
#: models.py:173
msgid "Tasks"
msgstr ""
#: models.py:194
msgid "Successful task" msgid "Successful task"
msgstr "Tâche réussie" msgstr "Tâche réussie"
#: models.py:126 #: models.py:195
msgid "Successful tasks" msgid "Successful tasks"
msgstr "Tâches réussies" msgstr "Tâches réussies"
#: models.py:141 #: models.py:210
msgid "Failed task" msgid "Failed task"
msgstr "Tâche échoué" msgstr "Tâche échoué"
#: models.py:142 #: models.py:211
msgid "Failed tasks" msgid "Failed tasks"
msgstr "Tâches échouées" msgstr "Tâches échouées"
#: models.py:150 models.py:234 #: models.py:219 models.py:347
msgid "Please install croniter to enable cron expressions" msgid "Please install croniter to enable cron expressions"
msgstr "Veuillez installer croniter pour activer les expressions cron." msgstr "Veuillez installer croniter pour activer les expressions cron."
#: models.py:170 #: models.py:236
msgid "Optional label to identify this schedule in the admin."
msgstr ""
#: models.py:241
msgid "e.g. module.tasks.function"
msgstr ""
#: models.py:248
msgid "e.g. module.tasks.result_function"
msgstr ""
#: models.py:254
msgid "e.g. 1, 2, 'John'" msgid "e.g. 1, 2, 'John'"
msgstr "ex. 1, 2, Jean" msgstr "ex. 1, 2, Jean"
#: models.py:172 #: models.py:260
msgid "e.g. x=1, y=2, name='John'" msgid "e.g. x=1, y=2, name='John'"
msgstr "p. ex. x = 1, y = 2, Nom = Jean" msgstr "p. ex. x = 1, y = 2, Nom = Jean"
#: models.py:186 #: models.py:274
msgid "Once" msgid "Once"
msgstr "Une fois" msgstr "Une fois"
#: models.py:187 #: models.py:275 models.py:296
msgid "Minutes" msgid "Minutes"
msgstr "Minutes" msgstr "Minutes"
#: models.py:188 #: models.py:276
msgid "Hourly" msgid "Hourly"
msgstr "Toutes les heures" msgstr "Toutes les heures"
#: models.py:189 #: models.py:277
msgid "Daily" msgid "Daily"
msgstr "Quotidien" msgstr "Quotidien"
#: models.py:190 #: models.py:278
msgid "Weekly" msgid "Weekly"
msgstr "Hebdomadaire" msgstr "Hebdomadaire"
#: models.py:191 #: models.py:279
#, fuzzy #, fuzzy
#| msgid "Weekly" #| msgid "Weekly"
msgid "Biweekly" msgid "Biweekly"
msgstr "Bihebdomadaire" msgstr "Bihebdomadaire"
#: models.py:192 #: models.py:280
msgid "Monthly" msgid "Monthly"
msgstr "Mensuel" msgstr "Mensuel"
#: models.py:193 #: models.py:281
#, fuzzy #, fuzzy
#| msgid "Monthly" #| msgid "Monthly"
msgid "Bimonthly" msgid "Bimonthly"
msgstr "Bimestriel" msgstr "Bimestriel"
#: models.py:194 #: models.py:282
msgid "Quarterly" msgid "Quarterly"
msgstr "Trimestriel" msgstr "Trimestriel"
#: models.py:195 #: models.py:283
msgid "Yearly" msgid "Yearly"
msgstr "Annuel" msgstr "Annuel"
#: models.py:196 #: models.py:284 models.py:313
msgid "Cron" msgid "Cron"
msgstr "Cron" msgstr "Cron"
#: models.py:199 #: models.py:290
msgid "Schedule Type" msgid "Schedule Type"
msgstr "Type de plannification" msgstr "Type de plannification"
#: models.py:202 #: models.py:291
msgid "How often this task should be enqueued."
msgstr ""
#: models.py:297
msgid "Number of minutes for the Minutes type" msgid "Number of minutes for the Minutes type"
msgstr "Nombre de minutes pour le type de minutes" msgstr "Nombre de minutes pour le type de minutes"
#: models.py:205 #: models.py:300
msgid "Repeats" msgid "Repeats"
msgstr "Répéter" msgstr "Répéter"
#: models.py:205 #: models.py:300
msgid "n = n times, -1 = forever" msgid "n = n times, -1 = forever"
msgstr "n = n fois,-1 = Toujours" msgstr "n = n fois,-1 = Toujours"
#: models.py:208 #: models.py:303
msgid "Next Run" msgid "Next Run"
msgstr "Prochaine exécution" msgstr "Prochaine exécution"
#: models.py:215 #: models.py:304
msgid "When this schedule runs next (stored in UTC)."
msgstr ""
#: models.py:314
msgid "Cron expression" msgid "Cron expression"
msgstr "Expression Cron" msgstr "Expression Cron"
#: models.py:224 #: models.py:320
msgid "Last task id"
msgstr ""
#: models.py:321
msgid "Id of the last task spawned from this schedule (read-only)."
msgstr ""
#: models.py:329 models.py:427
msgid "Name of the target cluster"
msgstr ""
#: models.py:336
msgid "Intended date kwarg"
msgstr ""
#: models.py:337
msgid "Name of kwarg to pass intended schedule date" msgid "Name of kwarg to pass intended schedule date"
msgstr "Nom du kwarg à passer Date prévue de l'horaire" msgstr "Nom du kwarg à passer Date prévue de l'horaire"
#: models.py:299 #: models.py:418
msgid "Scheduled task" msgid "Scheduled task"
msgstr "Tâche planifiée" msgstr "Tâche planifiée"
#: models.py:300 #: models.py:419
msgid "Scheduled tasks" msgid "Scheduled tasks"
msgstr "Tâches planifiées" msgstr "Tâches planifiées"
#: models.py:326 #: models.py:426
#, fuzzy
#| msgid "Clusters"
msgid "Cluster key"
msgstr "Grappes"
#: models.py:430
msgid "Payload"
msgstr ""
#: models.py:431
msgid "Signed serialized task package (do not edit manually)."
msgstr ""
#: models.py:435
msgid "Lock until"
msgstr ""
#: models.py:436
msgid "Prevent any cluster from pulling until"
msgstr ""
#: models.py:474
#, fuzzy
#| msgid "Queued task"
msgid "Queue options"
msgstr "Tâche en file d'attente"
#: models.py:478
msgid "Queued task" msgid "Queued task"
msgstr "Tâche en file d'attente" msgstr "Tâche en file d'attente"
#: models.py:327 #: models.py:479
msgid "Queued tasks" msgid "Queued tasks"
msgstr "Tâches en file d'attente" msgstr "Tâches en file d'attente"
#: monitor.py:64 monitor.py:348 #: monitor.py:41
#, python-format
msgid "%(name)s monitoring at %(id)s"
msgstr "%(name)s surveille les résultats %(id)s"
#: monitor.py:61
#, python-format
msgid "Processed '%(info_name)s' (%(task_name)s)"
msgstr "traité '%(info_name)s' (%(task_name)s)"
#: monitor.py:67
#, python-format
msgid "Failed '%(info_name)s' (%(task_name)s) - %(task_result)s"
msgstr "Manqué '%(info_name)s' (%(task_name)s) - %(task_result)s"
#: monitor.py:74
#, python-format
msgid "%(name)s stopped monitoring results"
msgstr "%(name)s a cessé de de surveiller les résultats"
#: monitor_terminal.py:64 monitor_terminal.py:348
msgid "Host" msgid "Host"
msgstr "Hôte" msgstr "Hôte"
#: monitor.py:68 monitor.py:352 monitor.py:459 #: monitor_terminal.py:68 monitor_terminal.py:352 monitor_terminal.py:457
msgid "Id" msgid "Id"
msgstr "Id" msgstr "Id"
#: monitor.py:72 #: monitor_terminal.py:72
msgid "State" msgid "State"
msgstr "Statut" msgstr "Statut"
#: monitor.py:76 #: monitor_terminal.py:76
msgid "Pool" msgid "Pool"
msgstr "Piscine" msgstr "Piscine"
#: monitor.py:80 #: monitor_terminal.py:80
msgid "TQ" msgid "TQ"
msgstr "TQ" msgstr "TQ"
#: monitor.py:84 #: monitor_terminal.py:84
msgid "RQ" msgid "RQ"
msgstr "RQ" msgstr "RQ"
#: monitor.py:88 #: monitor_terminal.py:88
msgid "RC" msgid "RC"
msgstr "RC" msgstr "RC"
#: monitor.py:92 #: monitor_terminal.py:92
msgid "Up" msgid "Up"
msgstr "Haut" msgstr "Haut"
#: monitor.py:172 monitor.py:286 #: monitor_terminal.py:172 monitor_terminal.py:286
msgid "Queued" msgid "Queued"
msgstr "En file d'attente" msgstr "En file d'attente"
#: monitor.py:180 #: monitor_terminal.py:190 monitor_terminal.py:294
msgid "Success"
msgstr "Succès"
#: monitor.py:190 monitor.py:294
msgid "Failures" msgid "Failures"
msgstr "Défaillances" msgstr "Défaillances"
#: monitor.py:201 monitor.py:498 #: monitor_terminal.py:201 monitor_terminal.py:496
msgid "[Press q to quit]" msgid "[Press q to quit]"
msgstr "[appuyez sur q pour quitter]" msgstr "[appuyez sur q pour quitter]"
#: monitor.py:227 #: monitor_terminal.py:227
msgid "day" msgid "day"
msgstr "jour" msgstr "jour"
#: monitor.py:248 #: monitor_terminal.py:248
msgid "second" msgid "second"
msgstr "seconde" msgstr "seconde"
#: monitor.py:251 #: monitor_terminal.py:251
msgid "minute" msgid "minute"
msgstr "minute" msgstr "minute"
#: monitor.py:254 #: monitor_terminal.py:254
msgid "hour" msgid "hour"
msgstr "heure" msgstr "heure"
#: monitor.py:263 #: monitor_terminal.py:263
#, python-format #, python-format
msgid "-- %(prefix)s %(version)s on %(info)s --" msgid "-- %(prefix)s %(version)s on %(info)s --"
msgstr "--%(prefix)s %(version)s sur %(info)s --" msgstr "--%(prefix)s %(version)s sur %(info)s --"
#: monitor.py:273 #: monitor_terminal.py:273
msgid "Clusters" msgid "Clusters"
msgstr "Grappes" msgstr "Grappes"
#: monitor.py:277 #: monitor_terminal.py:277
msgid "Workers" msgid "Workers"
msgstr "Processus" msgstr "Processus"
#: monitor.py:281 #: monitor_terminal.py:281
msgid "Restarts" msgid "Restarts"
msgstr "Redémarrages" msgstr "Redémarrages"
#: monitor.py:290 #: monitor_terminal.py:290
msgid "Successes" msgid "Successes"
msgstr "Succès" msgstr "Succès"
#: monitor.py:299 #: monitor_terminal.py:299
msgid "Schedules" msgid "Schedules"
msgstr "Planifications" msgstr "Planifications"
#: monitor.py:303 #: monitor_terminal.py:303
#, python-format #, python-format
msgid "Tasks/%(per)s" msgid "Tasks/%(per)s"
msgstr "Tâches/%(per)s" msgstr "Tâches/%(per)s"
#: monitor.py:307 #: monitor_terminal.py:307
msgid "Avg time" msgid "Avg time"
msgstr "Temps Moyen" msgstr "Temps Moyen"
#: monitor.py:357 #: monitor_terminal.py:357
msgid "Available (%)" msgid "Available (%)"
msgstr "" msgstr ""
#: monitor.py:363 #: monitor_terminal.py:363
msgid "Available (MB)" msgid "Available (MB)"
msgstr "Disponible sur (MB)" msgstr "Disponible sur (MB)"
#: monitor.py:368 #: monitor_terminal.py:368
msgid "Total (MB)" msgid "Total (MB)"
msgstr "Total (MB)" msgstr "Total (MB)"
#: monitor.py:373 #: monitor_terminal.py:373
msgid "Sentinel (MB)" msgid "Sentinel (MB)"
msgstr "Sentinel (MB)" msgstr "Sentinel (MB)"
#: monitor.py:379 #: monitor_terminal.py:379
msgid "Monitor (MB)" msgid "Monitor (MB)"
msgstr "Monitor (MB)" msgstr "Monitor (MB)"
#: monitor.py:385 #: monitor_terminal.py:385
#, fuzzy #, fuzzy
#| msgid "Workers" #| msgid "Workers"
msgid "Workers (MB)" msgid "Workers (MB)"
msgstr "Processus (MB)" msgstr "Processus (MB)"
#: monitor.py:487 #: monitor_terminal.py:485
#, python-format #, python-format
msgid "Available lowest (): %(memory_percent)s ((at)s)" msgid "Available lowest (): %(memory_percent)s ((at)s)"
msgstr "Disponible le plus bas () : %(memory_percent)s ((at)s)" msgstr "Disponible le plus bas () : %(memory_percent)s ((at)s)"
#: monitor.py:509 #: monitor_terminal.py:507
msgid "No clusters appear to be running." msgid "No clusters appear to be running."
msgstr "Aucun cluster ne semble être en cours d'exécution." msgstr "Aucun cluster ne semble être en cours d'exécution."
#: pusher.py:40
#, python-format
msgid "%(name)s pushing tasks at %(id)s"
msgstr "%(name)s répartit les tâches %(id)s"
#: pusher.py:67
#, python-format
msgid "queueing from %(list_key)s"
msgstr "mise en file d'attente de %(list_key)s"
#: pusher.py:71
#, python-format
msgid "%(name)s stopped pushing tasks"
msgstr "%(name)s a cessé de répartir les tâches"
#: scheduler.py:110
#, python-format
msgid "%(process_name)s failed to create a task from schedule [%(schedule)s]"
msgstr ""
"%(process_name)s Echec de la création d'une tâche à partir de Schedule "
"[%(schedule)s]"
#: scheduler.py:121
#, python-format
msgid ""
"%(process_name)s created task %(task_name)s from schedule [%(schedule)s]"
msgstr ""
"%(process_name)s a créé la tâche %(task_name)s à partir de Schedule "
"[%(schedule)s]"
#: signals.py:22 #: signals.py:22
#, python-format #, python-format
msgid "malformed return hook '%(hook)s' for [%(name)s]" msgid "malformed return hook '%(hook)s' for [%(name)s]"
@@ -500,6 +669,25 @@ msgstr "hook de retour '%(hook)s' mal formé pour [%(name)s]"
msgid "return hook %(hook)s failed on [%(name)s] because %(error)s" msgid "return hook %(hook)s failed on [%(name)s] because %(error)s"
msgstr "hook de retour %(hook)s a échoué sur [%(name)s] à cause de %(error)s" msgstr "hook de retour %(hook)s a échoué sur [%(name)s] à cause de %(error)s"
#: timeout.py:30 timeout.py:43
msgid "SIGALARM is not available on your platform"
msgstr ""
#: worker.py:49
#, python-format
msgid "%(proc_name)s ready for work at %(id)s"
msgstr "%(proc_name)s prêt pour le travail à %(id)s"
#: worker.py:69
#, fuzzy, python-format
msgid "%(proc_name)s processing %(task_name)s '%(func_name)s'"
msgstr "%(proc_name)s exécute %(task_name)s '%(func_name)s'"
#: worker.py:135
#, python-format
msgid "%(proc_name)s stopped doing work"
msgstr "%(proc_name)s a cessé de travailler"
#, python-format #, python-format
#~ msgid "" #~ msgid ""
#~ "Could not process '%(func_name)s'. Check the location of the function and " #~ "Could not process '%(func_name)s'. Check the location of the function and "
+676
View File
@@ -0,0 +1,676 @@
# Russian translation for django-q.
# Copyright (C) Django Q authors
# This file is distributed under the same license as the django-q package.
#
msgid ""
msgstr ""
"Project-Id-Version: django-q\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-04-17 21:07+0000\n"
"PO-Revision-Date: 2026-04-04 12:00+0000\n"
"Last-Translator: \n"
"Language-Team: Russian\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || "
"(n%100>=11 && n%100<=14)? 2 : 3);\n"
#: django_q/admin.py:30
msgid "Resubmit selected tasks to queue"
msgstr "Повторно отправить выбранные задачи в очередь"
#: django_q/admin.py:64
msgid "Time Taken"
msgstr "Время выполнения"
#: django_q/admin.py:95
msgid "Short result"
msgstr "Краткий результат"
#: django_q/admin.py:142 django_q/models.py:412
msgid "success"
msgstr "успех"
#: django_q/admin.py:154 django_q/models.py:414
msgid "last_run"
msgstr "последний запуск"
#: django_q/cluster.py:75
#, python-format
msgid "Q Cluster %(name)s starting."
msgstr "Запуск кластера Q %(name)s."
#: django_q/cluster.py:83
#, python-format
msgid "Q Cluster %(name)s stopping."
msgstr "Остановка кластера Q %(name)s."
#: django_q/cluster.py:86
#, python-format
msgid "Q Cluster %(name)s has stopped."
msgstr "Кластер Q %(name)s остановлен."
#: django_q/cluster.py:93
#, python-format
msgid "%(name)s got signal %(signal)s"
msgstr "%(name)s получил сигнал %(signal)s"
#: django_q/cluster.py:224
#, python-format
msgid "reincarnated monitor %(name)s after sudden death"
msgstr "монитор %(name)s перезапущен после аварийного завершения"
#: django_q/cluster.py:230
#, python-format
msgid "reincarnated pusher %(name)s after sudden death"
msgstr "пушер %(name)s перезапущен после аварийного завершения"
#: django_q/cluster.py:262
#, python-format
msgid ""
"reincarnated worker %(name)s after timeout while processing task "
"%(task_name)s"
msgstr ""
"воркер %(name)s перезапущен по таймауту при выполнении задачи %(task_name)s"
#: django_q/cluster.py:265
#, python-format
msgid "reincarnated worker %(name)s after timeout"
msgstr "воркер %(name)s перезапущен по таймауту"
#: django_q/cluster.py:270
#, python-format
msgid "recycled worker %(name)s"
msgstr "воркер %(name)s перезапущен (recycle)"
#: django_q/cluster.py:273
#, python-format
msgid "reincarnated worker %(name)s after death"
msgstr "воркер %(name)s перезапущен после сбоя"
#: django_q/cluster.py:297
#, python-format
msgid "%(name)s guarding cluster %(cluster_name)s"
msgstr "%(name)s обслуживает кластер %(cluster_name)s"
#: django_q/cluster.py:307
#, python-format
msgid "Q Cluster %(cluster_name)s running."
msgstr "Кластер Q %(cluster_name)s работает."
#: django_q/cluster.py:346
#, python-format
msgid "%(name)s stopping cluster processes"
msgstr "%(name)s останавливает процессы кластера"
#: django_q/cluster.py:371
#, python-format
msgid "%(name)s waiting for the monitor."
msgstr "%(name)s ожидает монитор."
#: django_q/cluster.py:394
msgid "Skipping cpu affinity because psutil was not found."
msgstr "Привязка к CPU пропущена: не найден psutil."
#: django_q/cluster.py:399
msgid "Faking cpu affinity because it is not supported on this platform"
msgstr "Имитация привязки к CPU: на этой платформе не поддерживается"
#: django_q/cluster.py:421
#, python-format
msgid "%(pid)s will use cpu %(affinity)s"
msgstr "%(pid)s будет использовать CPU %(affinity)s"
#: django_q/conf.py:122
#, python-format
msgid ""
"SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', "
"'name', 'func' and None. Default is None."
msgstr ""
"SAVE_LIMIT_PER (%(option)s) — недопустимое значение. Допустимо: «group», "
"«name», «func» и None. По умолчанию None."
#. Translators: Cluster status descriptions
#: django_q/conf.py:239
msgid "Starting"
msgstr "Запуск"
#: django_q/conf.py:240
msgid "Working"
msgstr "Работает"
#: django_q/conf.py:241
msgid "Idle"
msgstr "Простой"
#: django_q/conf.py:242
msgid "Stopped"
msgstr "Остановлен"
#: django_q/conf.py:243
msgid "Stopping"
msgstr "Останавливается"
#. Translators: help text for qcluster management command
#: django_q/management/commands/qcluster.py:11
msgid "Starts a Django Q Cluster."
msgstr "Запускает кластер Django Q."
#. Translators: help text for qinfo management command
#: django_q/management/commands/qinfo.py:11
msgid "General information over all clusters."
msgstr "Общая информация по всем кластерам."
#. Translators: help text for qmemory management command
#: django_q/management/commands/qmemory.py:9
msgid "Monitors Q Cluster memory usage"
msgstr "Мониторинг использования памяти кластером Q"
#. Translators: help text for qmonitor management command
#: django_q/management/commands/qmonitor.py:9
msgid "Monitors Q Cluster activity"
msgstr "Мониторинг активности кластера Q"
#: django_q/models.py:30 django_q/models.py:469
msgid "Task id"
msgstr "Идентификатор задачи"
#: django_q/models.py:31
msgid "32-character task identifier."
msgstr "32-символьный идентификатор задачи."
#: django_q/models.py:36 django_q/models.py:235 django_q/models.py:470
msgid "Name"
msgstr "Имя"
#: django_q/models.py:37
msgid "Optional human-readable name for lookup and display."
msgstr "Необязательное имя для поиска и отображения."
#: django_q/models.py:41 django_q/models.py:240 django_q/models.py:468
msgid "Function"
msgstr "Функция"
#: django_q/models.py:42
msgid "Dotted import path to the callable, e.g. myapp.tasks.job."
msgstr "Путь импорта к вызываемому объекту, напр. myapp.tasks.job."
#: django_q/models.py:47 django_q/models.py:247
msgid "Hook"
msgstr "Обработчик"
#: django_q/models.py:48
msgid "Optional dotted path to a callback that receives the task result."
msgstr "Необязательный путь к функции, получающей результат задачи."
#: django_q/models.py:53 django_q/models.py:253 django_q/models.py:472
msgid "Arguments"
msgstr "Аргументы"
#: django_q/models.py:54
msgid "Pickled positional arguments (tuple)."
msgstr "Сериализованные позиционные аргументы (tuple)."
#: django_q/models.py:59 django_q/models.py:259 django_q/models.py:473
msgid "Keyword arguments"
msgstr "Именованные аргументы"
#: django_q/models.py:60
msgid "Pickled keyword arguments (dict)."
msgstr "Сериализованные именованные аргументы (dict)."
#: django_q/models.py:65
msgid "Result"
msgstr "Результат"
#: django_q/models.py:66
msgid "Pickled return value or error payload."
msgstr "Сериализованный результат или данные об ошибке."
#: django_q/models.py:72 django_q/models.py:471
msgid "Group"
msgstr "Группа"
#: django_q/models.py:73
msgid "Optional group id to aggregate related tasks."
msgstr "Необязательный идентификатор группы связанных задач."
#: django_q/models.py:80 django_q/models.py:328
msgid "Cluster"
msgstr "Кластер"
#: django_q/models.py:81
msgid "Name of the cluster that executed this task."
msgstr "Имя кластера, выполнившего эту задачу."
#: django_q/models.py:85
msgid "Started at"
msgstr "Начало выполнения"
#: django_q/models.py:86
msgid "When the worker started executing the task."
msgstr "Когда воркер начал выполнение задачи."
#: django_q/models.py:90
msgid "Stopped at"
msgstr "Окончание выполнения"
#: django_q/models.py:91
msgid "When the worker finished (success or failure)."
msgstr "Когда воркер завершил выполнение (успех или ошибка)."
#: django_q/models.py:96 django_q/monitor_terminal.py:180
msgid "Success"
msgstr "Успех"
#: django_q/models.py:97
msgid "False if the task raised an exception or timed out."
msgstr "Ложь, если задача завершилась исключением или таймаутом."
#: django_q/models.py:101
msgid "Attempt count"
msgstr "Число попыток"
#: django_q/models.py:102
msgid "How many times execution was attempted."
msgstr "Сколько раз выполнялась попытка запуска."
#: django_q/models.py:172
msgid "Task"
msgstr "Задача"
#: django_q/models.py:173
msgid "Tasks"
msgstr "Задачи"
#: django_q/models.py:194
msgid "Successful task"
msgstr "Успешная задача"
#: django_q/models.py:195
msgid "Successful tasks"
msgstr "Успешные задачи"
#: django_q/models.py:210
msgid "Failed task"
msgstr "Неудачная задача"
#: django_q/models.py:211
msgid "Failed tasks"
msgstr "Неудачные задачи"
#: django_q/models.py:219 django_q/models.py:347
msgid "Please install croniter to enable cron expressions"
msgstr "Установите croniter для поддержки cron-выражений"
#: django_q/models.py:236
msgid "Optional label to identify this schedule in the admin."
msgstr "Необязательная подпись для расписания в админке."
#: django_q/models.py:241
msgid "e.g. module.tasks.function"
msgstr "например: module.tasks.function"
#: django_q/models.py:248
msgid "e.g. module.tasks.result_function"
msgstr "например: module.tasks.result_function "
#: django_q/models.py:254
msgid "e.g. 1, 2, 'John'"
msgstr "например: 1, 2, 'Алимхан'"
#: django_q/models.py:260
msgid "e.g. x=1, y=2, name='John'"
msgstr "например: x=1, y=2, name='Алимхан'"
#: django_q/models.py:274
msgid "Once"
msgstr "Один раз"
#: django_q/models.py:275 django_q/models.py:296
msgid "Minutes"
msgstr "Минуты"
#: django_q/models.py:276
msgid "Hourly"
msgstr "Ежечасно"
#: django_q/models.py:277
msgid "Daily"
msgstr "Ежедневно"
#: django_q/models.py:278
msgid "Weekly"
msgstr "Еженедельно"
#: django_q/models.py:279
msgid "Biweekly"
msgstr "Раз в две недели"
#: django_q/models.py:280
msgid "Monthly"
msgstr "Ежемесячно"
#: django_q/models.py:281
msgid "Bimonthly"
msgstr "Раз в два месяца"
#: django_q/models.py:282
msgid "Quarterly"
msgstr "Ежеквартально"
#: django_q/models.py:283
msgid "Yearly"
msgstr "Ежегодно"
#: django_q/models.py:284 django_q/models.py:313
msgid "Cron"
msgstr "Cron"
#: django_q/models.py:290
msgid "Schedule Type"
msgstr "Тип расписания"
#: django_q/models.py:291
msgid "How often this task should be enqueued."
msgstr "Как часто ставить эту задачу в очередь."
#: django_q/models.py:297
msgid "Number of minutes for the Minutes type"
msgstr "Число минут для типа «Минуты»"
#: django_q/models.py:300
msgid "Repeats"
msgstr "Повторы"
#: django_q/models.py:300
msgid "n = n times, -1 = forever"
msgstr "n — число повторов, -1 — бесконечно"
#: django_q/models.py:303
msgid "Next Run"
msgstr "Следующий запуск"
#: django_q/models.py:304
msgid "When this schedule runs next (stored in UTC)."
msgstr "Когда следующий запуск по расписанию (в UTC)."
#: django_q/models.py:314
msgid "Cron expression"
msgstr "Cron-выражение"
#: django_q/models.py:320
msgid "Last task id"
msgstr "ID последней задачи"
#: django_q/models.py:321
msgid "Id of the last task spawned from this schedule (read-only)."
msgstr "Идентификатор последней задачи по этому расписанию (read-only)."
#: django_q/models.py:329 django_q/models.py:427
msgid "Name of the target cluster"
msgstr "Имя целевого кластера"
#: django_q/models.py:336
msgid "Intended date kwarg"
msgstr "Имя аргумента для даты запуска"
#: django_q/models.py:337
msgid "Name of kwarg to pass intended schedule date"
msgstr "Имя kwargs для передачи запланированной даты"
#: django_q/models.py:418
msgid "Scheduled task"
msgstr "Запланированная задача"
#: django_q/models.py:419
msgid "Scheduled tasks"
msgstr "Запланированные задачи"
#: django_q/models.py:426
msgid "Cluster key"
msgstr "Ключ кластера"
#: django_q/models.py:430
msgid "Payload"
msgstr "Данные задачи"
#: django_q/models.py:431
msgid "Signed serialized task package (do not edit manually)."
msgstr "Подписанный сериализованный пакет задачи (не редактировать вручную)."
#: django_q/models.py:435
msgid "Lock until"
msgstr "Блокировка до"
#: django_q/models.py:436
msgid "Prevent any cluster from pulling until"
msgstr "Не забирать задачи кластерами до"
#: django_q/models.py:474
msgid "Queue options"
msgstr "Дополнительные параметры очереди"
#: django_q/models.py:478
msgid "Queued task"
msgstr "Задача в очереди"
#: django_q/models.py:479
msgid "Queued tasks"
msgstr "Задачи в очереди"
#: django_q/monitor.py:41
#, python-format
msgid "%(name)s monitoring at %(id)s"
msgstr "%(name)s мониторинг на %(id)s"
#: django_q/monitor.py:61
#, python-format
msgid "Processed '%(info_name)s' (%(task_name)s)"
msgstr "Обработано «%(info_name)s» (%(task_name)s)"
#: django_q/monitor.py:67
#, python-format
msgid "Failed '%(info_name)s' (%(task_name)s) - %(task_result)s"
msgstr "Ошибка «%(info_name)s» (%(task_name)s) — %(task_result)s"
#: django_q/monitor.py:74
#, python-format
msgid "%(name)s stopped monitoring results"
msgstr "%(name)s прекратил отслеживание результатов"
#: django_q/monitor_terminal.py:64 django_q/monitor_terminal.py:348
msgid "Host"
msgstr "Хост"
#: django_q/monitor_terminal.py:68 django_q/monitor_terminal.py:352
#: django_q/monitor_terminal.py:457
msgid "Id"
msgstr "Id"
#: django_q/monitor_terminal.py:72
msgid "State"
msgstr "Состояние"
#: django_q/monitor_terminal.py:76
msgid "Pool"
msgstr "Пул"
#: django_q/monitor_terminal.py:80
msgid "TQ"
msgstr "TQ"
#: django_q/monitor_terminal.py:84
msgid "RQ"
msgstr "RQ"
#: django_q/monitor_terminal.py:88
msgid "RC"
msgstr "RC"
#: django_q/monitor_terminal.py:92
msgid "Up"
msgstr "Аптайм"
#: django_q/monitor_terminal.py:172 django_q/monitor_terminal.py:286
msgid "Queued"
msgstr "В очереди"
#: django_q/monitor_terminal.py:190 django_q/monitor_terminal.py:294
msgid "Failures"
msgstr "Сбои"
#: django_q/monitor_terminal.py:201 django_q/monitor_terminal.py:496
msgid "[Press q to quit]"
msgstr "[Нажмите q для выхода]"
#: django_q/monitor_terminal.py:227
msgid "day"
msgstr "день"
#: django_q/monitor_terminal.py:248
msgid "second"
msgstr "секунда"
#: django_q/monitor_terminal.py:251
msgid "minute"
msgstr "минута"
#: django_q/monitor_terminal.py:254
msgid "hour"
msgstr "час"
#: django_q/monitor_terminal.py:263
#, python-format
msgid "-- %(prefix)s %(version)s on %(info)s --"
msgstr "-- %(prefix)s %(version)s на %(info)s --"
#: django_q/monitor_terminal.py:273
msgid "Clusters"
msgstr "Кластеры"
#: django_q/monitor_terminal.py:277
msgid "Workers"
msgstr "Воркеры"
#: django_q/monitor_terminal.py:281
msgid "Restarts"
msgstr "Перезапуски"
#: django_q/monitor_terminal.py:290
msgid "Successes"
msgstr "Успехи"
#: django_q/monitor_terminal.py:299
msgid "Schedules"
msgstr "Расписания"
#: django_q/monitor_terminal.py:303
#, python-format
msgid "Tasks/%(per)s"
msgstr "Задач/%(per)s"
#: django_q/monitor_terminal.py:307
msgid "Avg time"
msgstr "Среднее время"
#: django_q/monitor_terminal.py:357
msgid "Available (%)"
msgstr "Доступно (%)"
#: django_q/monitor_terminal.py:363
msgid "Available (MB)"
msgstr "Доступно (МБ)"
#: django_q/monitor_terminal.py:368
msgid "Total (MB)"
msgstr "Всего (МБ)"
#: django_q/monitor_terminal.py:373
msgid "Sentinel (MB)"
msgstr "Sentinel (МБ)"
#: django_q/monitor_terminal.py:379
msgid "Monitor (MB)"
msgstr "Монитор (МБ)"
#: django_q/monitor_terminal.py:385
msgid "Workers (MB)"
msgstr "Воркеры (МБ)"
#: django_q/monitor_terminal.py:485
#, python-format
msgid "Available lowest (): %(memory_percent)s ((at)s)"
msgstr "Минимум доступно (): %(memory_percent)s ((at)s)"
#: django_q/monitor_terminal.py:507
msgid "No clusters appear to be running."
msgstr "Похоже, ни один кластер не запущен."
#: django_q/pusher.py:40
#, python-format
msgid "%(name)s pushing tasks at %(id)s"
msgstr "%(name)s отправляет задачи на %(id)s"
#: django_q/pusher.py:67
#, python-format
msgid "queueing from %(list_key)s"
msgstr "очередь из %(list_key)s"
#: django_q/pusher.py:71
#, python-format
msgid "%(name)s stopped pushing tasks"
msgstr "%(name)s прекратил отправку задач"
#: django_q/scheduler.py:110
#, python-format
msgid "%(process_name)s failed to create a task from schedule [%(schedule)s]"
msgstr ""
"%(process_name)s не удалось создать задачу по расписанию [%(schedule)s]"
#: django_q/scheduler.py:121
#, python-format
msgid ""
"%(process_name)s created task %(task_name)s from schedule [%(schedule)s]"
msgstr ""
"%(process_name)s создал задачу %(task_name)s по расписанию [%(schedule)s]"
#: django_q/signals.py:22
#, python-format
msgid "malformed return hook '%(hook)s' for [%(name)s]"
msgstr "некорректный return hook «%(hook)s» для [%(name)s]"
#: django_q/signals.py:30
#, python-format
msgid "return hook %(hook)s failed on [%(name)s] because %(error)s"
msgstr "return hook %(hook)s для [%(name)s] завершился ошибкой: %(error)s"
#: django_q/timeout.py:30 django_q/timeout.py:43
msgid "SIGALARM is not available on your platform"
msgstr "SIGALRM недоступен на вашей платформе"
#: django_q/worker.py:49
#, python-format
msgid "%(proc_name)s ready for work at %(id)s"
msgstr "%(proc_name)s готов к работе на %(id)s"
#: django_q/worker.py:69
#, python-format
msgid "%(proc_name)s processing %(task_name)s '%(func_name)s'"
msgstr "%(proc_name)s выполняет %(task_name)s «%(func_name)s»"
#: django_q/worker.py:135
#, python-format
msgid "%(proc_name)s stopped doing work"
msgstr "%(proc_name)s прекратил работу"
#, python-format
#~ msgid ""
#~ "Could not process '%(func_name)s'. Check the location of the function and "
#~ "the args/kwargs."
#~ msgstr ""
#~ "Не удалось обработать «%(func_name)s». Проверьте путь к функции и args/"
#~ "kwargs."
+336 -154
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-01-26 01:38+0000\n" "POT-Creation-Date: 2026-04-17 21:10+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Ethem Güner <ethemguener@gmail.com>\n" "Last-Translator: Ethem Güner <ethemguener@gmail.com>\n"
"Language-Team: \n" "Language-Team: \n"
@@ -18,36 +18,44 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: admin.py:43 #: admin.py:30
msgid "Resubmit selected tasks to queue" msgid "Resubmit selected tasks to queue"
msgstr "Seçili işleri kuyruğa tekrar gönder" msgstr "Seçili işleri kuyruğa tekrar gönder"
#: admin.py:107 models.py:293 #: admin.py:64
msgid "Time Taken"
msgstr ""
#: admin.py:95
msgid "Short result"
msgstr ""
#: admin.py:142 models.py:412
#, fuzzy #, fuzzy
#| msgid "Success" #| msgid "Success"
msgid "success" msgid "success"
msgstr "başarılı olanlar" msgstr "başarılı olanlar"
#: admin.py:119 models.py:295 #: admin.py:154 models.py:414
msgid "last_run" msgid "last_run"
msgstr "" msgstr ""
#: cluster.py:79 #: cluster.py:75
#, python-format #, python-format
msgid "Q Cluster %(name)s starting." msgid "Q Cluster %(name)s starting."
msgstr "Q Cluster %(name)s başlatılıyor." msgstr "Q Cluster %(name)s başlatılıyor."
#: cluster.py:87 #: cluster.py:83
#, python-format #, python-format
msgid "Q Cluster %(name)s stopping." msgid "Q Cluster %(name)s stopping."
msgstr "Q Cluster %(name)s durduruluyor." msgstr "Q Cluster %(name)s durduruluyor."
#: cluster.py:90 #: cluster.py:86
#, python-format #, python-format
msgid "Q Cluster %(name)s has stopped." msgid "Q Cluster %(name)s has stopped."
msgstr "Q Cluster %(name)s durduruldu." msgstr "Q Cluster %(name)s durduruldu."
#: cluster.py:97 #: cluster.py:93
#, python-format #, python-format
msgid "%(name)s got signal %(signal)s" msgid "%(name)s got signal %(signal)s"
msgstr "%(name)s, %(signal)s pid'inde izleniyor/monitoring yapılıyor." msgstr "%(name)s, %(signal)s pid'inde izleniyor/monitoring yapılıyor."
@@ -62,7 +70,7 @@ msgstr "Monitor %(name)s ani ölüm sonrası tekrar dirildi"
msgid "reincarnated pusher %(name)s after sudden death" msgid "reincarnated pusher %(name)s after sudden death"
msgstr "Pusher %(name)s ani ölüm sonrası tekrar dirildi" msgstr "Pusher %(name)s ani ölüm sonrası tekrar dirildi"
#: cluster.py:250 #: cluster.py:262
#, fuzzy, python-format #, fuzzy, python-format
#| msgid "reincarnated worker %(name)s after timeout" #| msgid "reincarnated worker %(name)s after timeout"
msgid "" msgid ""
@@ -70,119 +78,55 @@ msgid ""
"%(task_name)s" "%(task_name)s"
msgstr "Worker %(name)s zaman aşımı sonrası tekrar dirildi" msgstr "Worker %(name)s zaman aşımı sonrası tekrar dirildi"
#: cluster.py:255 #: cluster.py:265
#, python-format #, python-format
msgid "reincarnated worker %(name)s after timeout" msgid "reincarnated worker %(name)s after timeout"
msgstr "Worker %(name)s zaman aşımı sonrası tekrar dirildi" msgstr "Worker %(name)s zaman aşımı sonrası tekrar dirildi"
#: cluster.py:260 #: cluster.py:270
#, python-format #, python-format
msgid "recycled worker %(name)s" msgid "recycled worker %(name)s"
msgstr "Worker %(name)s geri döndürüldü" msgstr "Worker %(name)s geri döndürüldü"
#: cluster.py:263 #: cluster.py:273
#, python-format #, python-format
msgid "reincarnated worker %(name)s after death" msgid "reincarnated worker %(name)s after death"
msgstr "Worker %(name)s ani ölüm sonrası tekrar dirildi" msgstr "Worker %(name)s ani ölüm sonrası tekrar dirildi"
#: cluster.py:287 #: cluster.py:297
#, python-format #, python-format
msgid "%(name)s guarding cluster %(cluster_name)s" msgid "%(name)s guarding cluster %(cluster_name)s"
msgstr "%(name)s, %(cluster_name)s cluster'ını koruyor" msgstr "%(name)s, %(cluster_name)s cluster'ını koruyor"
#: cluster.py:296 #: cluster.py:307
#, python-format #, python-format
msgid "Q Cluster %(cluster_name)s running." msgid "Q Cluster %(cluster_name)s running."
msgstr "Q Cluster %(cluster_name)s başlatılıyor." msgstr "Q Cluster %(cluster_name)s başlatılıyor."
#: cluster.py:332 #: cluster.py:346
#, python-format #, python-format
msgid "%(name)s stopping cluster processes" msgid "%(name)s stopping cluster processes"
msgstr "Cluster %(name)s işlemleri durduruluyor." msgstr "Cluster %(name)s işlemleri durduruluyor."
#: cluster.py:357 #: cluster.py:371
#, python-format #, python-format
msgid "%(name)s waiting for the monitor." msgid "%(name)s waiting for the monitor."
msgstr "%(name)s monitor için bekliyor." msgstr "%(name)s monitor için bekliyor."
#: cluster.py:383 #: cluster.py:394
#, fuzzy, python-format
#| msgid "%(process_name)s pushing tasks at %(id)s"
msgid "%(name)s pushing tasks at %(id)s"
msgstr "%(process_name)s, işleri %(id)s pid'ine gönderiyor."
#: cluster.py:407
#, python-format
msgid "queueing from %(list_key)s"
msgstr ""
#: cluster.py:411
#, python-format
msgid "%(name)s stopped pushing tasks"
msgstr "%(name)s işleri göndermeyi durdurdu"
#: cluster.py:426
#, python-format
msgid "%(name)s monitoring at %(id)s"
msgstr "%(name)s, %(id)s pid'inde izleniyor/monitoring yapılıyor."
#: cluster.py:445
#, python-format
msgid "Processed '%(info_name)s' (%(task_name)s)"
msgstr "[%(task_name)s] - '%(info_name)s işlendi."
#: cluster.py:451
#, python-format
msgid "Failed '%(info_name)s' (%(task_name)s) - %(task_result)s"
msgstr "[%(task_name)s] - '%(info_name)s' - %(task_result)s başarısız oldu"
#: cluster.py:458
#, python-format
msgid "%(name)s stopped monitoring results"
msgstr "%(name)s sonuçları göstermeyi bıraktı"
#: cluster.py:474
#, python-format
msgid "%(proc_name)s ready for work at %(id)s"
msgstr "%(proc_name)s, %(id)s pid'inde çalışmaya hazır"
#: cluster.py:494
#, fuzzy, python-format
#| msgid "%(proc_name)s processing '%(func_name)s' (%(task_name)s)"
msgid "%(proc_name)s processing %(task_name)s '%(func_name)s'"
msgstr "%(proc_name)s, '%(func_name)s' [%(task_name)s] işlerini işiyor"
#: cluster.py:546
#, python-format
msgid "%(proc_name)s stopped doing work"
msgstr "%(proc_name)s çalışmayı bıraktı"
#: cluster.py:751
#, python-format
msgid "%(process_name)s failed to create a task from schedule [%(schedule)s]"
msgstr "%(process_name)s programdan bir görev oluşturamadı [%(schedule)s]"
#: cluster.py:762
#, fuzzy, python-format
#| msgid "%(process_name)s created a task from schedule [%(schedule)s]"
msgid ""
"%(process_name)s created task %(task_name)s from schedule [%(schedule)s]"
msgstr "%(process_name)s programdan bir görev oluşturamadı [%(schedule)s]"
#: cluster.py:808
msgid "Skipping cpu affinity because psutil was not found." msgid "Skipping cpu affinity because psutil was not found."
msgstr "Psutil bulunamadığı için cpu benzeşimi atlanıyor." msgstr "Psutil bulunamadığı için cpu benzeşimi atlanıyor."
#: cluster.py:813 #: cluster.py:399
msgid "Faking cpu affinity because it is not supported on this platform" msgid "Faking cpu affinity because it is not supported on this platform"
msgstr "Bu platformda desteklenmediği için sahte cpu benzeşimi" msgstr "Bu platformda desteklenmediği için sahte cpu benzeşimi"
#: cluster.py:835 #: cluster.py:421
#, python-format #, python-format
msgid "%(pid)s will use cpu %(affinity)s" msgid "%(pid)s will use cpu %(affinity)s"
msgstr "%(pid)s cpu %(affinity)s kullanacaktır" msgstr "%(pid)s cpu %(affinity)s kullanacaktır"
#: conf.py:90 #: conf.py:122
#, python-format #, python-format
msgid "" msgid ""
"SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', " "SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', "
@@ -192,28 +136,28 @@ msgstr ""
"'group', 'name', 'func' ve None. Varsayılan değer None'dır." "'group', 'name', 'func' ve None. Varsayılan değer None'dır."
#. Translators: Cluster status descriptions #. Translators: Cluster status descriptions
#: conf.py:207 #: conf.py:239
msgid "Starting" msgid "Starting"
msgstr "Başlıyor" msgstr "Başlıyor"
#: conf.py:208 #: conf.py:240
msgid "Working" msgid "Working"
msgstr "Çalışıyor" msgstr "Çalışıyor"
#: conf.py:209 #: conf.py:241
msgid "Idle" msgid "Idle"
msgstr "Boşta" msgstr "Boşta"
#: conf.py:210 #: conf.py:242
msgid "Stopped" msgid "Stopped"
msgstr "Durdu" msgstr "Durdu"
#: conf.py:211 #: conf.py:243
msgid "Stopping" msgid "Stopping"
msgstr "Durduruluyor" msgstr "Durduruluyor"
#. Translators: help text for qcluster management command #. Translators: help text for qcluster management command
#: management/commands/qcluster.py:9 #: management/commands/qcluster.py:11
msgid "Starts a Django Q Cluster." msgid "Starts a Django Q Cluster."
msgstr "Bir Django Q Cluster çalıştırır." msgstr "Bir Django Q Cluster çalıştırır."
@@ -232,257 +176,475 @@ msgstr "Q Cluster'ın bellek kullanımını izler"
msgid "Monitors Q Cluster activity" msgid "Monitors Q Cluster activity"
msgstr "Q Cluster'ın aktivitelerini izler" msgstr "Q Cluster'ın aktivitelerini izler"
#: models.py:125 #: models.py:30 models.py:469
msgid "Task id"
msgstr ""
#: models.py:31
msgid "32-character task identifier."
msgstr ""
#: models.py:36 models.py:235 models.py:470
msgid "Name"
msgstr ""
#: models.py:37
msgid "Optional human-readable name for lookup and display."
msgstr ""
#: models.py:41 models.py:240 models.py:468
msgid "Function"
msgstr ""
#: models.py:42
msgid "Dotted import path to the callable, e.g. myapp.tasks.job."
msgstr ""
#: models.py:47 models.py:247
msgid "Hook"
msgstr ""
#: models.py:48
msgid "Optional dotted path to a callback that receives the task result."
msgstr ""
#: models.py:53 models.py:253 models.py:472
msgid "Arguments"
msgstr ""
#: models.py:54
msgid "Pickled positional arguments (tuple)."
msgstr ""
#: models.py:59 models.py:259 models.py:473
msgid "Keyword arguments"
msgstr ""
#: models.py:60
msgid "Pickled keyword arguments (dict)."
msgstr ""
#: models.py:65
msgid "Result"
msgstr ""
#: models.py:66
msgid "Pickled return value or error payload."
msgstr ""
#: models.py:72 models.py:471
msgid "Group"
msgstr ""
#: models.py:73
msgid "Optional group id to aggregate related tasks."
msgstr ""
#: models.py:80 models.py:328
msgid "Cluster"
msgstr ""
#: models.py:81
msgid "Name of the cluster that executed this task."
msgstr ""
#: models.py:85
msgid "Started at"
msgstr ""
#: models.py:86
msgid "When the worker started executing the task."
msgstr ""
#: models.py:90
#, fuzzy
#| msgid "Stopped"
msgid "Stopped at"
msgstr "Durdu"
#: models.py:91
msgid "When the worker finished (success or failure)."
msgstr ""
#: models.py:96 monitor_terminal.py:180
msgid "Success"
msgstr "Başarılı olanlar"
#: models.py:97
msgid "False if the task raised an exception or timed out."
msgstr ""
#: models.py:101
msgid "Attempt count"
msgstr ""
#: models.py:102
msgid "How many times execution was attempted."
msgstr ""
#: models.py:172
msgid "Task"
msgstr ""
#: models.py:173
msgid "Tasks"
msgstr ""
#: models.py:194
msgid "Successful task" msgid "Successful task"
msgstr "Başarılı iş" msgstr "Başarılı iş"
#: models.py:126 #: models.py:195
msgid "Successful tasks" msgid "Successful tasks"
msgstr "Başarılı işler" msgstr "Başarılı işler"
#: models.py:141 #: models.py:210
msgid "Failed task" msgid "Failed task"
msgstr "Başarısız iş" msgstr "Başarısız iş"
#: models.py:142 #: models.py:211
msgid "Failed tasks" msgid "Failed tasks"
msgstr "Başarısız işler" msgstr "Başarısız işler"
#: models.py:150 models.py:234 #: models.py:219 models.py:347
msgid "Please install croniter to enable cron expressions" msgid "Please install croniter to enable cron expressions"
msgstr "Cron expressions'ları açmak için croniter yükleyin" msgstr "Cron expressions'ları açmak için croniter yükleyin"
#: models.py:170 #: models.py:236
msgid "Optional label to identify this schedule in the admin."
msgstr ""
#: models.py:241
msgid "e.g. module.tasks.function"
msgstr ""
#: models.py:248
msgid "e.g. module.tasks.result_function"
msgstr ""
#: models.py:254
msgid "e.g. 1, 2, 'John'" msgid "e.g. 1, 2, 'John'"
msgstr "Örneğin: 1, 2, 'Melih'" msgstr "Örneğin: 1, 2, 'Melih'"
#: models.py:172 #: models.py:260
msgid "e.g. x=1, y=2, name='John'" msgid "e.g. x=1, y=2, name='John'"
msgstr "Örneğin: x=1, y=2, name='Melih'" msgstr "Örneğin: x=1, y=2, name='Melih'"
#: models.py:186 #: models.py:274
msgid "Once" msgid "Once"
msgstr "Bir kere" msgstr "Bir kere"
#: models.py:187 #: models.py:275 models.py:296
msgid "Minutes" msgid "Minutes"
msgstr "Dakika" msgstr "Dakika"
#: models.py:188 #: models.py:276
msgid "Hourly" msgid "Hourly"
msgstr "Saatlik" msgstr "Saatlik"
#: models.py:189 #: models.py:277
msgid "Daily" msgid "Daily"
msgstr "Günlük" msgstr "Günlük"
#: models.py:190 #: models.py:278
msgid "Weekly" msgid "Weekly"
msgstr "Haftalık" msgstr "Haftalık"
#: models.py:191 #: models.py:279
#, fuzzy #, fuzzy
#| msgid "Weekly" #| msgid "Weekly"
msgid "Biweekly" msgid "Biweekly"
msgstr "İki haftada bir" msgstr "İki haftada bir"
#: models.py:192 #: models.py:280
msgid "Monthly" msgid "Monthly"
msgstr "Aylık" msgstr "Aylık"
#: models.py:193 #: models.py:281
#, fuzzy #, fuzzy
#| msgid "Monthly" #| msgid "Monthly"
msgid "Bimonthly" msgid "Bimonthly"
msgstr "İki ayda bir" msgstr "İki ayda bir"
#: models.py:194 #: models.py:282
msgid "Quarterly" msgid "Quarterly"
msgstr "Bir Çeyrek (3 Ay)" msgstr "Bir Çeyrek (3 Ay)"
#: models.py:195 #: models.py:283
msgid "Yearly" msgid "Yearly"
msgstr "Yıllık" msgstr "Yıllık"
#: models.py:196 #: models.py:284 models.py:313
msgid "Cron" msgid "Cron"
msgstr "" msgstr ""
#: models.py:199 #: models.py:290
msgid "Schedule Type" msgid "Schedule Type"
msgstr "Zamanlama Tipi" msgstr "Zamanlama Tipi"
#: models.py:202 #: models.py:291
msgid "How often this task should be enqueued."
msgstr ""
#: models.py:297
msgid "Number of minutes for the Minutes type" msgid "Number of minutes for the Minutes type"
msgstr "Dakika tipine göre dakika sayısı" msgstr "Dakika tipine göre dakika sayısı"
#: models.py:205 #: models.py:300
msgid "Repeats" msgid "Repeats"
msgstr "Tekrar eder" msgstr "Tekrar eder"
#: models.py:205 #: models.py:300
msgid "n = n times, -1 = forever" msgid "n = n times, -1 = forever"
msgstr "n = n kere, -1 = sonsuza kadar" msgstr "n = n kere, -1 = sonsuza kadar"
#: models.py:208 #: models.py:303
msgid "Next Run" msgid "Next Run"
msgstr "Bir dahaki çalışma tarihi" msgstr "Bir dahaki çalışma tarihi"
#: models.py:215 #: models.py:304
msgid "When this schedule runs next (stored in UTC)."
msgstr ""
#: models.py:314
msgid "Cron expression" msgid "Cron expression"
msgstr "" msgstr ""
#: models.py:224 #: models.py:320
msgid "Last task id"
msgstr ""
#: models.py:321
msgid "Id of the last task spawned from this schedule (read-only)."
msgstr ""
#: models.py:329 models.py:427
msgid "Name of the target cluster"
msgstr ""
#: models.py:336
msgid "Intended date kwarg"
msgstr ""
#: models.py:337
msgid "Name of kwarg to pass intended schedule date" msgid "Name of kwarg to pass intended schedule date"
msgstr "Geçilecek kwarg'ın adı öngörülen program tarihi" msgstr "Geçilecek kwarg'ın adı öngörülen program tarihi"
#: models.py:299 #: models.py:418
msgid "Scheduled task" msgid "Scheduled task"
msgstr "Zamanlanmış iş" msgstr "Zamanlanmış iş"
#: models.py:300 #: models.py:419
msgid "Scheduled tasks" msgid "Scheduled tasks"
msgstr "Zamanlanmış işler" msgstr "Zamanlanmış işler"
#: models.py:326 #: models.py:426
msgid "Cluster key"
msgstr ""
#: models.py:430
msgid "Payload"
msgstr ""
#: models.py:431
msgid "Signed serialized task package (do not edit manually)."
msgstr ""
#: models.py:435
msgid "Lock until"
msgstr ""
#: models.py:436
msgid "Prevent any cluster from pulling until"
msgstr ""
#: models.py:474
#, fuzzy
#| msgid "Queued task"
msgid "Queue options"
msgstr "Sıraya alınmış iş"
#: models.py:478
msgid "Queued task" msgid "Queued task"
msgstr "Sıraya alınmış iş" msgstr "Sıraya alınmış iş"
#: models.py:327 #: models.py:479
msgid "Queued tasks" msgid "Queued tasks"
msgstr "Sıraya alınmış işler" msgstr "Sıraya alınmış işler"
#: monitor.py:64 monitor.py:348 #: monitor.py:41
#, python-format
msgid "%(name)s monitoring at %(id)s"
msgstr "%(name)s, %(id)s pid'inde izleniyor/monitoring yapılıyor."
#: monitor.py:61
#, python-format
msgid "Processed '%(info_name)s' (%(task_name)s)"
msgstr "[%(task_name)s] - '%(info_name)s işlendi."
#: monitor.py:67
#, python-format
msgid "Failed '%(info_name)s' (%(task_name)s) - %(task_result)s"
msgstr "[%(task_name)s] - '%(info_name)s' - %(task_result)s başarısız oldu"
#: monitor.py:74
#, python-format
msgid "%(name)s stopped monitoring results"
msgstr "%(name)s sonuçları göstermeyi bıraktı"
#: monitor_terminal.py:64 monitor_terminal.py:348
msgid "Host" msgid "Host"
msgstr "" msgstr ""
#: monitor.py:68 monitor.py:352 monitor.py:459 #: monitor_terminal.py:68 monitor_terminal.py:352 monitor_terminal.py:457
msgid "Id" msgid "Id"
msgstr "" msgstr ""
#: monitor.py:72 #: monitor_terminal.py:72
msgid "State" msgid "State"
msgstr "Durum" msgstr "Durum"
#: monitor.py:76 #: monitor_terminal.py:76
msgid "Pool" msgid "Pool"
msgstr "Havuz" msgstr "Havuz"
#: monitor.py:80 #: monitor_terminal.py:80
msgid "TQ" msgid "TQ"
msgstr "" msgstr ""
#: monitor.py:84 #: monitor_terminal.py:84
msgid "RQ" msgid "RQ"
msgstr "" msgstr ""
#: monitor.py:88 #: monitor_terminal.py:88
msgid "RC" msgid "RC"
msgstr "" msgstr ""
#: monitor.py:92 #: monitor_terminal.py:92
msgid "Up" msgid "Up"
msgstr "" msgstr ""
#: monitor.py:172 monitor.py:286 #: monitor_terminal.py:172 monitor_terminal.py:286
msgid "Queued" msgid "Queued"
msgstr "Sıraya alınmış" msgstr "Sıraya alınmış"
#: monitor.py:180 #: monitor_terminal.py:190 monitor_terminal.py:294
msgid "Success"
msgstr "Başarılı olanlar"
#: monitor.py:190 monitor.py:294
msgid "Failures" msgid "Failures"
msgstr "Başarısız olanlar" msgstr "Başarısız olanlar"
#: monitor.py:201 monitor.py:498 #: monitor_terminal.py:201 monitor_terminal.py:496
msgid "[Press q to quit]" msgid "[Press q to quit]"
msgstr "[Çıkmak için q'ya basın]" msgstr "[Çıkmak için q'ya basın]"
#: monitor.py:227 #: monitor_terminal.py:227
msgid "day" msgid "day"
msgstr "gün" msgstr "gün"
#: monitor.py:248 #: monitor_terminal.py:248
msgid "second" msgid "second"
msgstr "saniye" msgstr "saniye"
#: monitor.py:251 #: monitor_terminal.py:251
msgid "minute" msgid "minute"
msgstr "dakika" msgstr "dakika"
#: monitor.py:254 #: monitor_terminal.py:254
msgid "hour" msgid "hour"
msgstr "saat" msgstr "saat"
#: monitor.py:263 #: monitor_terminal.py:263
#, python-format #, python-format
msgid "-- %(prefix)s %(version)s on %(info)s --" msgid "-- %(prefix)s %(version)s on %(info)s --"
msgstr "-- %(prefix)s %(version)s üzerinde %(info)s --" msgstr "-- %(prefix)s %(version)s üzerinde %(info)s --"
#: monitor.py:273 #: monitor_terminal.py:273
msgid "Clusters" msgid "Clusters"
msgstr "" msgstr ""
#: monitor.py:277 #: monitor_terminal.py:277
msgid "Workers" msgid "Workers"
msgstr "" msgstr ""
#: monitor.py:281 #: monitor_terminal.py:281
msgid "Restarts" msgid "Restarts"
msgstr "Yeniden çalıştırmalar" msgstr "Yeniden çalıştırmalar"
#: monitor.py:290 #: monitor_terminal.py:290
msgid "Successes" msgid "Successes"
msgstr "Başarılı olanlar" msgstr "Başarılı olanlar"
#: monitor.py:299 #: monitor_terminal.py:299
msgid "Schedules" msgid "Schedules"
msgstr "Zamanlanmışlar" msgstr "Zamanlanmışlar"
#: monitor.py:303 #: monitor_terminal.py:303
#, python-format #, python-format
msgid "Tasks/%(per)s" msgid "Tasks/%(per)s"
msgstr "İş/%(per)s" msgstr "İş/%(per)s"
#: monitor.py:307 #: monitor_terminal.py:307
msgid "Avg time" msgid "Avg time"
msgstr "Ortalama süre" msgstr "Ortalama süre"
#: monitor.py:357 #: monitor_terminal.py:357
msgid "Available (%)" msgid "Available (%)"
msgstr "Müsait (%) " msgstr "Müsait (%) "
#: monitor.py:363 #: monitor_terminal.py:363
msgid "Available (MB)" msgid "Available (MB)"
msgstr "Müsait (MB)" msgstr "Müsait (MB)"
#: monitor.py:368 #: monitor_terminal.py:368
msgid "Total (MB)" msgid "Total (MB)"
msgstr "Toplam (MB)" msgstr "Toplam (MB)"
#: monitor.py:373 #: monitor_terminal.py:373
msgid "Sentinel (MB)" msgid "Sentinel (MB)"
msgstr "" msgstr ""
#: monitor.py:379 #: monitor_terminal.py:379
msgid "Monitor (MB)" msgid "Monitor (MB)"
msgstr "İzleme (MB)" msgstr "İzleme (MB)"
#: monitor.py:385 #: monitor_terminal.py:385
msgid "Workers (MB)" msgid "Workers (MB)"
msgstr "" msgstr ""
#: monitor.py:487 #: monitor_terminal.py:485
#, python-format #, python-format
msgid "Available lowest (): %(memory_percent)s ((at)s)" msgid "Available lowest (): %(memory_percent)s ((at)s)"
msgstr "Mevcut en düşük (): %(memory_percent)s ((at)s)" msgstr "Mevcut en düşük (): %(memory_percent)s ((at)s)"
#: monitor.py:509 #: monitor_terminal.py:507
msgid "No clusters appear to be running." msgid "No clusters appear to be running."
msgstr "Hiçbir küme çalışıyor görünmüyor." msgstr "Hiçbir küme çalışıyor görünmüyor."
#: pusher.py:40
#, python-format
msgid "%(name)s pushing tasks at %(id)s"
msgstr "%(name)s, işleri %(id)s pid'ine gönderiyor."
#: pusher.py:67
#, python-format
msgid "queueing from %(list_key)s"
msgstr "%(list_key)s kuyruğa alınıyor"
#: pusher.py:71
#, python-format
msgid "%(name)s stopped pushing tasks"
msgstr "%(name)s işleri göndermeyi durdurdu"
#: scheduler.py:110
#, python-format
msgid "%(process_name)s failed to create a task from schedule [%(schedule)s]"
msgstr "%(process_name)s programdan bir görev oluşturamadı [%(schedule)s]"
#: scheduler.py:121
#, python-format
msgid ""
"%(process_name)s created task %(task_name)s from schedule [%(schedule)s]"
msgstr "%(process_name)s programdan %(task_name)s görevini oluşturdu [%(schedule)s]"
#: signals.py:22 #: signals.py:22
#, python-format #, python-format
msgid "malformed return hook '%(hook)s' for [%(name)s]" msgid "malformed return hook '%(hook)s' for [%(name)s]"
@@ -493,6 +655,26 @@ msgstr ""
msgid "return hook %(hook)s failed on [%(name)s] because %(error)s" msgid "return hook %(hook)s failed on [%(name)s] because %(error)s"
msgstr "" msgstr ""
#: timeout.py:30 timeout.py:43
msgid "SIGALARM is not available on your platform"
msgstr ""
#: worker.py:49
#, python-format
msgid "%(proc_name)s ready for work at %(id)s"
msgstr "%(proc_name)s, %(id)s pid'inde çalışmaya hazır"
#: worker.py:69
#, fuzzy, python-format
#| msgid "%(proc_name)s processing '%(func_name)s' (%(task_name)s)"
msgid "%(proc_name)s processing %(task_name)s '%(func_name)s'"
msgstr "%(proc_name)s, '%(func_name)s' [%(task_name)s] işlerini işiyor"
#: worker.py:135
#, python-format
msgid "%(proc_name)s stopped doing work"
msgstr "%(proc_name)s çalışmayı bıraktı"
#, python-format #, python-format
#~ msgid "" #~ msgid ""
#~ "Could not process '%(func_name)s'. Check the location of the function and " #~ "Could not process '%(func_name)s'. Check the location of the function and "
@@ -0,0 +1,682 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
msgid ""
msgstr ""
"Project-Id-Version: django-q\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-04-17 21:10+0000\n"
"PO-Revision-Date: 2026-01-14 16:36+0800\n"
"Last-Translator: Yibo Li <lybcyd@outlook.com>\n"
"Language-Team: Simplified Chinese\n"
"Language: zh_Hans\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: \n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: admin.py:30
msgid "Resubmit selected tasks to queue"
msgstr "将选定的任务重新提交到队列"
#: admin.py:64
msgid "Time Taken"
msgstr ""
#: admin.py:95
msgid "Short result"
msgstr ""
#: admin.py:142 models.py:412
#, fuzzy
#| msgid "Success"
msgid "success"
msgstr "成功"
#: admin.py:154 models.py:414
msgid "last_run"
msgstr "最后运行"
#: cluster.py:75
#, python-format
msgid "Q Cluster %(name)s starting."
msgstr "Q 集群 %(name)s 正在启动。"
#: cluster.py:83
#, fuzzy, python-format
#| msgid "Q Cluster-{} stopping."
msgid "Q Cluster %(name)s stopping."
msgstr "Q 集群 %(name)s 正在停止。"
#: cluster.py:86
#, python-format
msgid "Q Cluster %(name)s has stopped."
msgstr "Q 集群 %(name)s 已停止。"
#: cluster.py:93
#, python-format
msgid "%(name)s got signal %(signal)s"
msgstr "%(name)s 收到信号 %(signal)s"
#: cluster.py:224
#, python-format
msgid "reincarnated monitor %(name)s after sudden death"
msgstr "意外宕机后monitor %(name)s 已重生"
#: cluster.py:230
#, python-format
msgid "reincarnated pusher %(name)s after sudden death"
msgstr "意外宕机后pusher %(name)s 已重生"
#: cluster.py:262
#, fuzzy, python-format
#| msgid "reincarnated worker %(name)s after timeout"
msgid ""
"reincarnated worker %(name)s after timeout while processing task "
"%(task_name)s"
msgstr "处理任务 %(task_name)s 时超时,worker %(name)s 已重生"
#: cluster.py:265
#, python-format
msgid "reincarnated worker %(name)s after timeout"
msgstr "超时后worker %(name)s 已重生"
#: cluster.py:270
#, python-format
msgid "recycled worker %(name)s"
msgstr "worker %(name)s 已回收"
#: cluster.py:273
#, python-format
msgid "reincarnated worker %(name)s after death"
msgstr "意外宕机后worker %(name)s 已重生"
#: cluster.py:297
#, python-format
msgid "%(name)s guarding cluster %(cluster_name)s"
msgstr "%(name)s 正在保护Cluster %(cluster_name)s"
#: cluster.py:307
#, python-format
msgid "Q Cluster %(cluster_name)s running."
msgstr "Q 集群 %(cluster_name)s 正在运行。"
#: cluster.py:346
#, python-format
msgid "%(name)s stopping cluster processes"
msgstr "%(name)s 正在停止集群进程"
#: cluster.py:371
#, python-format
msgid "%(name)s waiting for the monitor."
msgstr "%(name)s 正在等待监视器。"
#: cluster.py:394
msgid "Skipping cpu affinity because psutil was not found."
msgstr "跳过 CPU 亲和性,因为未找到 psutil。"
#: cluster.py:399
msgid "Faking cpu affinity because it is not supported on this platform"
msgstr "伪造 CPU 亲和性,因为此平台不支持此功能"
#: cluster.py:421
#, python-format
msgid "%(pid)s will use cpu %(affinity)s"
msgstr "%(pid)s 将使用 CPU %(affinity)s"
#: conf.py:122
#, python-format
msgid ""
"SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', "
"'name', 'func' and None. Default is None."
msgstr ""
"SAVE_LIMIT_PER (%(option)s) 不是有效的选项。选项包"
"括:'group'、'name'、'func' 和 None。默认值是 None。"
#. Translators: Cluster status descriptions
#: conf.py:239
msgid "Starting"
msgstr "正在启动"
#: conf.py:240
msgid "Working"
msgstr "工作中"
#: conf.py:241
msgid "Idle"
msgstr "空闲"
#: conf.py:242
msgid "Stopped"
msgstr "已停止"
#: conf.py:243
msgid "Stopping"
msgstr "正在停止"
#. Translators: help text for qcluster management command
#: management/commands/qcluster.py:11
msgid "Starts a Django Q Cluster."
msgstr "启动 Django Q 集群。"
#. Translators: help text for qinfo management command
#: management/commands/qinfo.py:11
msgid "General information over all clusters."
msgstr "所有集群的常规信息。"
#. Translators: help text for qmemory management command
#: management/commands/qmemory.py:9
msgid "Monitors Q Cluster memory usage"
msgstr "监视 Q 集群内存使用情况"
#. Translators: help text for qmonitor management command
#: management/commands/qmonitor.py:9
msgid "Monitors Q Cluster activity"
msgstr "监视 Q 集群活动"
#: models.py:30 models.py:469
msgid "Task id"
msgstr ""
#: models.py:31
msgid "32-character task identifier."
msgstr ""
#: models.py:36 models.py:235 models.py:470
msgid "Name"
msgstr ""
#: models.py:37
msgid "Optional human-readable name for lookup and display."
msgstr ""
#: models.py:41 models.py:240 models.py:468
msgid "Function"
msgstr ""
#: models.py:42
msgid "Dotted import path to the callable, e.g. myapp.tasks.job."
msgstr ""
#: models.py:47 models.py:247
msgid "Hook"
msgstr ""
#: models.py:48
msgid "Optional dotted path to a callback that receives the task result."
msgstr ""
#: models.py:53 models.py:253 models.py:472
msgid "Arguments"
msgstr ""
#: models.py:54
msgid "Pickled positional arguments (tuple)."
msgstr ""
#: models.py:59 models.py:259 models.py:473
msgid "Keyword arguments"
msgstr ""
#: models.py:60
msgid "Pickled keyword arguments (dict)."
msgstr ""
#: models.py:65
msgid "Result"
msgstr ""
#: models.py:66
msgid "Pickled return value or error payload."
msgstr ""
#: models.py:72 models.py:471
msgid "Group"
msgstr ""
#: models.py:73
msgid "Optional group id to aggregate related tasks."
msgstr ""
#: models.py:80 models.py:328
#, fuzzy
#| msgid "Clusters"
msgid "Cluster"
msgstr "集群"
#: models.py:81
msgid "Name of the cluster that executed this task."
msgstr ""
#: models.py:85
msgid "Started at"
msgstr ""
#: models.py:86
msgid "When the worker started executing the task."
msgstr ""
#: models.py:90
#, fuzzy
#| msgid "Stopped"
msgid "Stopped at"
msgstr "已停止"
#: models.py:91
msgid "When the worker finished (success or failure)."
msgstr ""
#: models.py:96 monitor_terminal.py:180
msgid "Success"
msgstr "成功"
#: models.py:97
msgid "False if the task raised an exception or timed out."
msgstr ""
#: models.py:101
msgid "Attempt count"
msgstr ""
#: models.py:102
msgid "How many times execution was attempted."
msgstr ""
#: models.py:172
msgid "Task"
msgstr ""
#: models.py:173
msgid "Tasks"
msgstr ""
#: models.py:194
msgid "Successful task"
msgstr "成功的任务"
#: models.py:195
msgid "Successful tasks"
msgstr "成功的任务"
#: models.py:210
msgid "Failed task"
msgstr "失败的任务"
#: models.py:211
msgid "Failed tasks"
msgstr "失败的任务"
#: models.py:219 models.py:347
msgid "Please install croniter to enable cron expressions"
msgstr "请安装 croniter 以启用 cron 表达式"
#: models.py:236
msgid "Optional label to identify this schedule in the admin."
msgstr ""
#: models.py:241
msgid "e.g. module.tasks.function"
msgstr ""
#: models.py:248
msgid "e.g. module.tasks.result_function"
msgstr ""
#: models.py:254
msgid "e.g. 1, 2, 'John'"
msgstr "例如 1, 2, 'John'"
#: models.py:260
msgid "e.g. x=1, y=2, name='John'"
msgstr "例如 x=1, y=2, name='John'"
#: models.py:274
msgid "Once"
msgstr "一次"
#: models.py:275 models.py:296
msgid "Minutes"
msgstr "分钟"
#: models.py:276
msgid "Hourly"
msgstr "每小时"
#: models.py:277
msgid "Daily"
msgstr "每天"
#: models.py:278
msgid "Weekly"
msgstr "每周"
#: models.py:279
msgid "Biweekly"
msgstr "每两周"
#: models.py:280
msgid "Monthly"
msgstr "每月"
#: models.py:281
msgid "Bimonthly"
msgstr "每两个月"
#: models.py:282
msgid "Quarterly"
msgstr "每季度"
#: models.py:283
msgid "Yearly"
msgstr "每年"
#: models.py:284 models.py:313
msgid "Cron"
msgstr "Cron"
#: models.py:290
msgid "Schedule Type"
msgstr "计划类型"
#: models.py:291
msgid "How often this task should be enqueued."
msgstr ""
#: models.py:297
msgid "Number of minutes for the Minutes type"
msgstr "'分钟'类型的分钟数"
#: models.py:300
msgid "Repeats"
msgstr "重复次数"
#: models.py:300
msgid "n = n times, -1 = forever"
msgstr "n = n 次,-1 = 永远"
#: models.py:303
msgid "Next Run"
msgstr "下次运行"
#: models.py:304
msgid "When this schedule runs next (stored in UTC)."
msgstr ""
#: models.py:314
msgid "Cron expression"
msgstr "Cron 表达式"
#: models.py:320
msgid "Last task id"
msgstr ""
#: models.py:321
msgid "Id of the last task spawned from this schedule (read-only)."
msgstr ""
#: models.py:329 models.py:427
msgid "Name of the target cluster"
msgstr ""
#: models.py:336
msgid "Intended date kwarg"
msgstr ""
#: models.py:337
msgid "Name of kwarg to pass intended schedule date"
msgstr "传递预定计划日期的 kwarg 的名称"
#: models.py:418
msgid "Scheduled task"
msgstr "计划任务"
#: models.py:419
msgid "Scheduled tasks"
msgstr "计划任务"
#: models.py:426
#, fuzzy
#| msgid "Clusters"
msgid "Cluster key"
msgstr "集群"
#: models.py:430
msgid "Payload"
msgstr ""
#: models.py:431
msgid "Signed serialized task package (do not edit manually)."
msgstr ""
#: models.py:435
msgid "Lock until"
msgstr ""
#: models.py:436
msgid "Prevent any cluster from pulling until"
msgstr ""
#: models.py:474
#, fuzzy
#| msgid "Queued task"
msgid "Queue options"
msgstr "排队的任务"
#: models.py:478
msgid "Queued task"
msgstr "排队的任务"
#: models.py:479
msgid "Queued tasks"
msgstr "排队的任务"
#: monitor.py:41
#, python-format
msgid "%(name)s monitoring at %(id)s"
msgstr "%(name)s 正在 %(id)s 处监视"
#: monitor.py:61
#, python-format
msgid "Processed '%(info_name)s' (%(task_name)s)"
msgstr "已处理 '%(info_name)s' (%(task_name)s)"
#: monitor.py:67
#, python-format
msgid "Failed '%(info_name)s' (%(task_name)s) - %(task_result)s"
msgstr "'%(info_name)s' (%(task_name)s) 失败 - %(task_result)s"
#: monitor.py:74
#, python-format
msgid "%(name)s stopped monitoring results"
msgstr "%(name)s 已停止监视结果"
#: monitor_terminal.py:64 monitor_terminal.py:348
msgid "Host"
msgstr "主机"
#: monitor_terminal.py:68 monitor_terminal.py:352 monitor_terminal.py:457
msgid "Id"
msgstr "ID"
#: monitor_terminal.py:72
msgid "State"
msgstr "状态"
#: monitor_terminal.py:76
msgid "Pool"
msgstr "连接池"
#: monitor_terminal.py:80
msgid "TQ"
msgstr "TQ"
#: monitor_terminal.py:84
msgid "RQ"
msgstr "RQ"
#: monitor_terminal.py:88
msgid "RC"
msgstr "RC"
#: monitor_terminal.py:92
msgid "Up"
msgstr "运行中"
#: monitor_terminal.py:172 monitor_terminal.py:286
msgid "Queued"
msgstr "已排队"
#: monitor_terminal.py:190 monitor_terminal.py:294
msgid "Failures"
msgstr "失败"
#: monitor_terminal.py:201 monitor_terminal.py:496
msgid "[Press q to quit]"
msgstr "[按 q 键退出]"
#: monitor_terminal.py:227
msgid "day"
msgstr "天"
#: monitor_terminal.py:248
msgid "second"
msgstr "秒"
#: monitor_terminal.py:251
msgid "minute"
msgstr "分钟"
#: monitor_terminal.py:254
msgid "hour"
msgstr "小时"
#: monitor_terminal.py:263
#, python-format
msgid "-- %(prefix)s %(version)s on %(info)s --"
msgstr "-- %(prefix)s %(version)s 在 %(info)s 上 --"
#: monitor_terminal.py:273
msgid "Clusters"
msgstr "集群"
#: monitor_terminal.py:277
msgid "Workers"
msgstr "工作进程"
#: monitor_terminal.py:281
msgid "Restarts"
msgstr "重启次数"
#: monitor_terminal.py:290
msgid "Successes"
msgstr "成功次数"
#: monitor_terminal.py:299
msgid "Schedules"
msgstr "计划"
#: monitor_terminal.py:303
#, python-format
msgid "Tasks/%(per)s"
msgstr "任务/%(per)s"
#: monitor_terminal.py:307
msgid "Avg time"
msgstr "平均时间"
#: monitor_terminal.py:357
msgid "Available (%)"
msgstr "可用 (%)"
#: monitor_terminal.py:363
msgid "Available (MB)"
msgstr "可用 (MB)"
#: monitor_terminal.py:368
msgid "Total (MB)"
msgstr "总计 (MB)"
#: monitor_terminal.py:373
msgid "Sentinel (MB)"
msgstr "哨兵 (MB)"
#: monitor_terminal.py:379
msgid "Monitor (MB)"
msgstr "监视器 (MB)"
#: monitor_terminal.py:385
msgid "Workers (MB)"
msgstr "工作进程 (MB)"
#: monitor_terminal.py:485
#, python-format
msgid "Available lowest (): %(memory_percent)s ((at)s)"
msgstr "最低可用 (): %(memory_percent)s ((at)s)"
#: monitor_terminal.py:507
msgid "No clusters appear to be running."
msgstr "似乎没有集群正在运行。"
#: pusher.py:40
#, python-format
msgid "%(name)s pushing tasks at %(id)s"
msgstr "%(name)s 正在 %(id)s 处推送任务"
#: pusher.py:67
#, python-format
msgid "queueing from %(list_key)s"
msgstr "从 %(list_key)s 排队"
#: pusher.py:71
#, python-format
msgid "%(name)s stopped pushing tasks"
msgstr "%(name)s 已停止推送任务"
#: scheduler.py:110
#, python-format
msgid "%(process_name)s failed to create a task from schedule [%(schedule)s]"
msgstr "%(process_name)s 无法从计划 [%(schedule)s] 创建任务"
#: scheduler.py:121
#, python-format
msgid ""
"%(process_name)s created task %(task_name)s from schedule [%(schedule)s]"
msgstr "%(process_name)s 从计划 [%(schedule)s] 创建了任务 %(task_name)s"
#: signals.py:22
#, python-format
msgid "malformed return hook '%(hook)s' for [%(name)s]"
msgstr "格式错误的返回钩子 '%(hook)s' 用于 [%(name)s]"
#: signals.py:30
#, python-format
msgid "return hook %(hook)s failed on [%(name)s] because %(error)s"
msgstr "返回钩子 %(hook)s 在 [%(name)s] 上失败,原因是 %(error)s"
#: timeout.py:30 timeout.py:43
msgid "SIGALARM is not available on your platform"
msgstr ""
#: worker.py:49
#, python-format
msgid "%(proc_name)s ready for work at %(id)s"
msgstr "%(proc_name)s 已准备好在 %(id)s 处工作"
#: worker.py:69
#, fuzzy, python-format
#| msgid "%(proc_name)s processing '%(func_name)s' (%(task_name)s)"
msgid "%(proc_name)s processing %(task_name)s '%(func_name)s'"
msgstr "%(proc_name)s 正在处理任务 %(task_name)s '%(func_name)s'"
#: worker.py:135
#, python-format
msgid "%(proc_name)s stopped doing work"
msgstr "%(proc_name)s 已停止工作"
#, python-format
#~ msgid ""
#~ "Could not process '%(func_name)s'. Check the location of the function and "
#~ "the args/kwargs."
#~ msgstr "无法处理函数 '%(func_name)s'。检查函数的位置和args/kwargs。"
+3
View File
@@ -1,5 +1,6 @@
import os import os
from django.conf import settings
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
@@ -28,6 +29,8 @@ class Command(BaseCommand):
) )
def handle(self, *args, **options): def handle(self, *args, **options):
# Ensure that the cluster starts only if the SECRET_KEY is set, as it is required for signing.
settings.SECRET_KEY
# Set alternative cluster_name before creating the cluster (cluster_name is broker's queue_name, too) # Set alternative cluster_name before creating the cluster (cluster_name is broker's queue_name, too)
cluster_name = options.get("cluster_name") cluster_name = options.get("cluster_name")
if cluster_name: if cluster_name:
-1
View File
@@ -4,7 +4,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [] dependencies = []
operations = [ operations = [
@@ -2,7 +2,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
("django_q", "0001_initial"), ("django_q", "0001_initial"),
] ]
@@ -2,7 +2,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
("django_q", "0002_auto_20150630_1624"), ("django_q", "0002_auto_20150630_1624"),
] ]
@@ -2,7 +2,6 @@ from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
("django_q", "0003_auto_20150708_1326"), ("django_q", "0003_auto_20150708_1326"),
] ]
@@ -2,7 +2,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
("django_q", "0004_auto_20150710_1043"), ("django_q", "0004_auto_20150710_1043"),
] ]
@@ -2,7 +2,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
("django_q", "0005_auto_20150718_1506"), ("django_q", "0005_auto_20150718_1506"),
] ]
-1
View File
@@ -2,7 +2,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
("django_q", "0006_auto_20150805_1817"), ("django_q", "0006_auto_20150805_1817"),
] ]
@@ -2,7 +2,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
("django_q", "0007_ormq"), ("django_q", "0007_ormq"),
] ]
@@ -2,7 +2,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
("django_q", "0008_auto_20160224_1026"), ("django_q", "0008_auto_20160224_1026"),
] ]
@@ -3,7 +3,6 @@ from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
("django_q", "0009_auto_20171009_0915"), ("django_q", "0009_auto_20171009_0915"),
] ]
@@ -4,7 +4,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
("django_q", "0010_auto_20200610_0856"), ("django_q", "0010_auto_20200610_0856"),
] ]
@@ -6,7 +6,6 @@ import django_q.models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
("django_q", "0011_auto_20200628_1055"), ("django_q", "0011_auto_20200628_1055"),
] ]
@@ -4,7 +4,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
("django_q", "0012_auto_20200702_1608"), ("django_q", "0012_auto_20200702_1608"),
] ]
@@ -4,7 +4,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
("django_q", "0013_task_attempt_count"), ("django_q", "0013_task_attempt_count"),
] ]
@@ -4,7 +4,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
("django_q", "0014_schedule_cluster"), ("django_q", "0014_schedule_cluster"),
] ]
@@ -6,7 +6,6 @@ import django_q.models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
("django_q", "0015_alter_schedule_schedule_type"), ("django_q", "0015_alter_schedule_schedule_type"),
] ]
@@ -4,7 +4,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
("django_q", "0016_schedule_intended_date_kwarg"), ("django_q", "0016_schedule_intended_date_kwarg"),
] ]
@@ -0,0 +1,20 @@
# Generated by Django 4.2.7 on 2024-03-05 17:03
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("django_q", "0017_task_cluster_alter"),
]
operations = [
migrations.AddIndex(
model_name="task",
index=models.Index(
condition=models.Q(("success", True)),
fields=["group", "name", "func"],
name="success_index",
),
),
]
@@ -0,0 +1,325 @@
# Generated by Django 6.0.4 on 2026-04-17 20:55
import django.utils.timezone
import picklefield.fields
from django.db import migrations, models
import django_q.models
class Migration(migrations.Migration):
dependencies = [
("django_q", "0018_task_success_index"),
]
operations = [
migrations.AlterModelOptions(
name="task",
options={
"ordering": ["-stopped"],
"verbose_name": "Task",
"verbose_name_plural": "Tasks",
},
),
migrations.AlterField(
model_name="ormq",
name="key",
field=models.CharField(
help_text="Name of the target cluster",
max_length=100,
verbose_name="Cluster key",
),
),
migrations.AlterField(
model_name="ormq",
name="lock",
field=models.DateTimeField(
help_text="Prevent any cluster from pulling until",
null=True,
verbose_name="Lock until",
),
),
migrations.AlterField(
model_name="ormq",
name="payload",
field=models.TextField(
help_text="Signed serialized task package (do not edit manually).",
verbose_name="Payload",
),
),
migrations.AlterField(
model_name="schedule",
name="args",
field=models.TextField(
blank=True,
help_text="e.g. 1, 2, 'John'",
null=True,
verbose_name="Arguments",
),
),
migrations.AlterField(
model_name="schedule",
name="cluster",
field=models.CharField(
blank=True,
default=None,
help_text="Name of the target cluster",
max_length=100,
null=True,
verbose_name="Cluster",
),
),
migrations.AlterField(
model_name="schedule",
name="cron",
field=models.CharField(
blank=True,
help_text="Cron expression",
max_length=100,
null=True,
validators=[django_q.models.validate_cron],
verbose_name="Cron",
),
),
migrations.AlterField(
model_name="schedule",
name="func",
field=models.CharField(
help_text="e.g. module.tasks.function",
max_length=256,
verbose_name="Function",
),
),
migrations.AlterField(
model_name="schedule",
name="hook",
field=models.CharField(
blank=True,
help_text="e.g. module.tasks.result_function",
max_length=256,
null=True,
verbose_name="Hook",
),
),
migrations.AlterField(
model_name="schedule",
name="intended_date_kwarg",
field=models.CharField(
blank=True,
help_text="Name of kwarg to pass intended schedule date",
max_length=100,
null=True,
validators=[django_q.models.validate_kwarg],
verbose_name="Intended date kwarg",
),
),
migrations.AlterField(
model_name="schedule",
name="kwargs",
field=models.TextField(
blank=True,
help_text="e.g. x=1, y=2, name='John'",
null=True,
verbose_name="Keyword arguments",
),
),
migrations.AlterField(
model_name="schedule",
name="minutes",
field=models.PositiveSmallIntegerField(
blank=True,
help_text="Number of minutes for the Minutes type",
null=True,
verbose_name="Minutes",
),
),
migrations.AlterField(
model_name="schedule",
name="name",
field=models.CharField(
blank=True,
help_text="Optional label to identify this schedule in the admin.",
max_length=100,
null=True,
verbose_name="Name",
),
),
migrations.AlterField(
model_name="schedule",
name="next_run",
field=models.DateTimeField(
default=django.utils.timezone.now,
help_text="When this schedule runs next (stored in UTC).",
null=True,
verbose_name="Next Run",
),
),
migrations.AlterField(
model_name="schedule",
name="schedule_type",
field=models.CharField(
choices=[
("O", "Once"),
("I", "Minutes"),
("H", "Hourly"),
("D", "Daily"),
("W", "Weekly"),
("BW", "Biweekly"),
("M", "Monthly"),
("BM", "Bimonthly"),
("Q", "Quarterly"),
("Y", "Yearly"),
("C", "Cron"),
],
default="O",
help_text="How often this task should be enqueued.",
max_length=2,
verbose_name="Schedule Type",
),
),
migrations.AlterField(
model_name="schedule",
name="task",
field=models.CharField(
editable=False,
help_text="Id of the last task spawned from this schedule (read-only).",
max_length=100,
null=True,
verbose_name="Last task id",
),
),
migrations.AlterField(
model_name="task",
name="args",
field=picklefield.fields.PickledObjectField(
editable=False,
help_text="Pickled positional arguments (tuple).",
null=True,
protocol=-1,
verbose_name="Arguments",
),
),
migrations.AlterField(
model_name="task",
name="attempt_count",
field=models.IntegerField(
default=0,
help_text="How many times execution was attempted.",
verbose_name="Attempt count",
),
),
migrations.AlterField(
model_name="task",
name="cluster",
field=models.CharField(
blank=True,
default=None,
help_text="Name of the cluster that executed this task.",
max_length=100,
null=True,
verbose_name="Cluster",
),
),
migrations.AlterField(
model_name="task",
name="func",
field=models.CharField(
help_text="Dotted import path to the callable, e.g. myapp.tasks.job.",
max_length=256,
verbose_name="Function",
),
),
migrations.AlterField(
model_name="task",
name="group",
field=models.CharField(
editable=False,
help_text="Optional group id to aggregate related tasks.",
max_length=100,
null=True,
verbose_name="Group",
),
),
migrations.AlterField(
model_name="task",
name="hook",
field=models.CharField(
help_text="Optional dotted path to a callback that receives the task result.",
max_length=256,
null=True,
verbose_name="Hook",
),
),
migrations.AlterField(
model_name="task",
name="id",
field=models.CharField(
editable=False,
help_text="32-character task identifier.",
max_length=32,
primary_key=True,
serialize=False,
verbose_name="Task id",
),
),
migrations.AlterField(
model_name="task",
name="kwargs",
field=picklefield.fields.PickledObjectField(
editable=False,
help_text="Pickled keyword arguments (dict).",
null=True,
protocol=-1,
verbose_name="Keyword arguments",
),
),
migrations.AlterField(
model_name="task",
name="name",
field=models.CharField(
editable=False,
help_text="Optional human-readable name for lookup and display.",
max_length=100,
verbose_name="Name",
),
),
migrations.AlterField(
model_name="task",
name="result",
field=picklefield.fields.PickledObjectField(
editable=False,
help_text="Pickled return value or error payload.",
null=True,
protocol=-1,
verbose_name="Result",
),
),
migrations.AlterField(
model_name="task",
name="started",
field=models.DateTimeField(
editable=False,
help_text="When the worker started executing the task.",
verbose_name="Started at",
),
),
migrations.AlterField(
model_name="task",
name="stopped",
field=models.DateTimeField(
editable=False,
help_text="When the worker finished (success or failure).",
verbose_name="Stopped at",
),
),
migrations.AlterField(
model_name="task",
name="success",
field=models.BooleanField(
default=True,
editable=False,
help_text="False if the task raised an exception or timed out.",
verbose_name="Success",
),
),
]
+166 -44
View File
@@ -2,23 +2,20 @@ from datetime import datetime, timedelta
from keyword import iskeyword from keyword import iskeyword
# Django # Django
from django import get_version
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import models from django.db import models
from django.template.defaultfilters import truncatechars from django.db.models import Q
from django.urls import reverse from django.urls import reverse
from django.utils import timezone from django.utils import timezone
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.html import format_html from django.utils.html import format_html
from django.utils.timezone import is_aware
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
# External # External
from picklefield import PickledObjectField from picklefield import PickledObjectField
from picklefield.fields import dbsafe_decode
# Local # Local
from django_q.conf import Conf, croniter from django_q.conf import croniter
from django_q.signing import SignedPackage from django_q.signing import SignedPackage
from django_q.utils import add_months, add_years, localtime from django_q.utils import add_months, add_years, localtime
@@ -26,19 +23,86 @@ from .utils import get_func_repr
class Task(models.Model): class Task(models.Model):
id = models.CharField(max_length=32, primary_key=True, editable=False) id = models.CharField(
name = models.CharField(max_length=100, editable=False) max_length=32,
func = models.CharField(max_length=256) primary_key=True,
hook = models.CharField(max_length=256, null=True) editable=False,
args = PickledObjectField(null=True, protocol=-1) verbose_name=_("Task id"),
kwargs = PickledObjectField(null=True, protocol=-1) help_text=_("32-character task identifier."),
result = PickledObjectField(null=True, protocol=-1) )
group = models.CharField(max_length=100, editable=False, null=True) name = models.CharField(
cluster = models.CharField(max_length=100, default=None, null=True, blank=True) max_length=100,
started = models.DateTimeField(editable=False) editable=False,
stopped = models.DateTimeField(editable=False) verbose_name=_("Name"),
success = models.BooleanField(default=True, editable=False) help_text=_("Optional human-readable name for lookup and display."),
attempt_count = models.IntegerField(default=0) )
func = models.CharField(
max_length=256,
verbose_name=_("Function"),
help_text=_("Dotted import path to the callable, e.g. myapp.tasks.job."),
)
hook = models.CharField(
max_length=256,
null=True,
verbose_name=_("Hook"),
help_text=_(
"Optional dotted path to a callback that receives the task result."
),
)
args = PickledObjectField(
null=True,
protocol=-1,
verbose_name=_("Arguments"),
help_text=_("Pickled positional arguments (tuple)."),
)
kwargs = PickledObjectField(
null=True,
protocol=-1,
verbose_name=_("Keyword arguments"),
help_text=_("Pickled keyword arguments (dict)."),
)
result = PickledObjectField(
null=True,
protocol=-1,
verbose_name=_("Result"),
help_text=_("Pickled return value or error payload."),
)
group = models.CharField(
max_length=100,
editable=False,
null=True,
verbose_name=_("Group"),
help_text=_("Optional group id to aggregate related tasks."),
)
cluster = models.CharField(
max_length=100,
default=None,
null=True,
blank=True,
verbose_name=_("Cluster"),
help_text=_("Name of the cluster that executed this task."),
)
started = models.DateTimeField(
editable=False,
verbose_name=_("Started at"),
help_text=_("When the worker started executing the task."),
)
stopped = models.DateTimeField(
editable=False,
verbose_name=_("Stopped at"),
help_text=_("When the worker finished (success or failure)."),
)
success = models.BooleanField(
default=True,
editable=False,
verbose_name=_("Success"),
help_text=_("False if the task raised an exception or timed out."),
)
attempt_count = models.IntegerField(
default=0,
verbose_name=_("Attempt count"),
help_text=_("How many times execution was attempted."),
)
@staticmethod @staticmethod
def get_result(task_id): def get_result(task_id):
@@ -59,7 +123,7 @@ class Task(models.Model):
.exclude(success=False) .exclude(success=False)
.values_list("result", flat=True) .values_list("result", flat=True)
) )
return decode_results(values) return values
def group_result(self, failures=False): def group_result(self, failures=False):
if self.group: if self.group:
@@ -102,16 +166,21 @@ class Task(models.Model):
def time_taken(self): def time_taken(self):
return (self.stopped - self.started).total_seconds() return (self.stopped - self.started).total_seconds()
@property
def short_result(self):
return truncatechars(self.result, 100)
def __str__(self): def __str__(self):
return f"{self.name or self.id}" return f"{self.name or self.id}"
class Meta: class Meta:
app_label = "django_q" app_label = "django_q"
verbose_name = _("Task")
verbose_name_plural = _("Tasks")
ordering = ["-stopped"] ordering = ["-stopped"]
indexes = [
models.Index(
name="success_index",
fields=["group", "name", "func"],
condition=Q(success=True),
),
]
class SuccessManager(models.Manager): class SuccessManager(models.Manager):
@@ -161,17 +230,36 @@ def validate_kwarg(value):
class Schedule(models.Model): class Schedule(models.Model):
name = models.CharField(max_length=100, null=True, blank=True) name = models.CharField(
func = models.CharField(max_length=256, help_text="e.g. module.tasks.function") max_length=100,
null=True,
blank=True,
verbose_name=_("Name"),
help_text=_("Optional label to identify this schedule in the admin."),
)
func = models.CharField(
max_length=256,
verbose_name=_("Function"),
help_text=_("e.g. module.tasks.function"),
)
hook = models.CharField( hook = models.CharField(
max_length=256, max_length=256,
null=True, null=True,
blank=True, blank=True,
help_text="e.g. module.tasks.result_function", verbose_name=_("Hook"),
help_text=_("e.g. module.tasks.result_function"),
)
args = models.TextField(
null=True,
blank=True,
verbose_name=_("Arguments"),
help_text=_("e.g. 1, 2, 'John'"),
) )
args = models.TextField(null=True, blank=True, help_text=_("e.g. 1, 2, 'John'"))
kwargs = models.TextField( kwargs = models.TextField(
null=True, blank=True, help_text=_("e.g. x=1, y=2, name='John'") null=True,
blank=True,
verbose_name=_("Keyword arguments"),
help_text=_("e.g. x=1, y=2, name='John'"),
) )
ONCE = "O" ONCE = "O"
MINUTES = "I" MINUTES = "I"
@@ -198,30 +286,48 @@ class Schedule(models.Model):
(CRON, _("Cron")), (CRON, _("Cron")),
) )
schedule_type = models.CharField( schedule_type = models.CharField(
max_length=2, choices=TYPE, default=TYPE[0][0], verbose_name=_("Schedule Type") max_length=2,
choices=TYPE,
default=TYPE[0][0],
verbose_name=_("Schedule Type"),
help_text=_("How often this task should be enqueued."),
) )
minutes = models.PositiveSmallIntegerField( minutes = models.PositiveSmallIntegerField(
null=True, blank=True, help_text=_("Number of minutes for the Minutes type") null=True,
blank=True,
verbose_name=_("Minutes"),
help_text=_("Number of minutes for the Minutes type"),
) )
repeats = models.IntegerField( repeats = models.IntegerField(
default=-1, verbose_name=_("Repeats"), help_text=_("n = n times, -1 = forever") default=-1, verbose_name=_("Repeats"), help_text=_("n = n times, -1 = forever")
) )
next_run = models.DateTimeField( next_run = models.DateTimeField(
verbose_name=_("Next Run"), default=timezone.now, null=True verbose_name=_("Next Run"),
help_text=_("When this schedule runs next (stored in UTC)."),
default=timezone.now,
null=True,
) )
cron = models.CharField( cron = models.CharField(
max_length=100, max_length=100,
null=True, null=True,
blank=True, blank=True,
validators=[validate_cron], validators=[validate_cron],
verbose_name=_("Cron"),
help_text=_("Cron expression"), help_text=_("Cron expression"),
) )
task = models.CharField(max_length=100, null=True, editable=False) task = models.CharField(
max_length=100,
null=True,
editable=False,
verbose_name=_("Last task id"),
help_text=_("Id of the last task spawned from this schedule (read-only)."),
)
cluster = models.CharField( cluster = models.CharField(
max_length=100, max_length=100,
default=None, default=None,
null=True, null=True,
blank=True, blank=True,
verbose_name=_("Cluster"),
help_text=_("Name of the target cluster"), help_text=_("Name of the target cluster"),
) )
intended_date_kwarg = models.CharField( intended_date_kwarg = models.CharField(
@@ -229,6 +335,7 @@ class Schedule(models.Model):
null=True, null=True,
blank=True, blank=True,
validators=[validate_kwarg], validators=[validate_kwarg],
verbose_name=_("Intended date kwarg"),
help_text=_("Name of kwarg to pass intended schedule date"), help_text=_("Name of kwarg to pass intended schedule date"),
) )
@@ -291,12 +398,18 @@ class Schedule(models.Model):
url = reverse("admin:django_q_success_change", args=(task.id,)) url = reverse("admin:django_q_success_change", args=(task.id,))
else: else:
url = reverse("admin:django_q_failure_change", args=(task.id,)) url = reverse("admin:django_q_failure_change", args=(task.id,))
return format_html(f'<a href="{url}">[{task.name}]</a>') return format_html('<a href="{}">[{}]</a>', url, task.name)
return None return None
def __str__(self): def __str__(self):
return self.func return self.func
def save(self, *args, **kwargs):
if self.pk is None and self.schedule_type == self.CRON:
self.next_run = self.calculate_next_run()
return super().save(*args, **kwargs)
success.boolean = True success.boolean = True
success.short_description = _("success") success.short_description = _("success")
last_run.allow_tags = True last_run.allow_tags = True
@@ -310,10 +423,19 @@ class Schedule(models.Model):
class OrmQ(models.Model): class OrmQ(models.Model):
key = models.CharField(max_length=100, help_text=_("Name of the target cluster")) key = models.CharField(
payload = models.TextField() max_length=100,
verbose_name=_("Cluster key"),
help_text=_("Name of the target cluster"),
)
payload = models.TextField(
verbose_name=_("Payload"),
help_text=_("Signed serialized task package (do not edit manually)."),
)
lock = models.DateTimeField( lock = models.DateTimeField(
null=True, help_text=_("Prevent any cluster from pulling until") null=True,
verbose_name=_("Lock until"),
help_text=_("Prevent any cluster from pulling until"),
) )
@cached_property @cached_property
@@ -345,15 +467,15 @@ class OrmQ(models.Model):
exclude = {"id", "name", "group", "func", "args", "kwargs"} exclude = {"id", "name", "group", "func", "args", "kwargs"}
return {k: v for k, v in self.task.items() if k not in exclude} return {k: v for k, v in self.task.items() if k not in exclude}
func.short_description = _("Function")
task_id.short_description = _("Task id")
name.short_description = _("Name")
group.short_description = _("Group")
args.short_description = _("Arguments")
kwargs.short_description = _("Keyword arguments")
q_options.short_description = _("Queue options")
class Meta: class Meta:
app_label = "django_q" app_label = "django_q"
verbose_name = _("Queued task") verbose_name = _("Queued task")
verbose_name_plural = _("Queued tasks") verbose_name_plural = _("Queued tasks")
# Backwards compatibility for Django 1.7
def decode_results(values):
if get_version().split(".")[1] == "7":
# decode values in 1.7
return [dbsafe_decode(v) for v in values]
return values
+30 -24
View File
@@ -2,8 +2,8 @@ from multiprocessing.process import current_process
from multiprocessing.queues import Queue from multiprocessing.queues import Queue
from django import core, db from django import core, db
from django.utils.translation import gettext_lazy as _
from django.apps.registry import apps from django.apps.registry import apps
from django.utils.translation import gettext_lazy as _
try: try:
apps.check_apps_ready() apps.check_apps_ready()
@@ -93,7 +93,8 @@ def save_task(task, broker: Broker):
broker=broker, broker=broker,
) )
# SAVE LIMIT > 0: Prune database, SAVE_LIMIT 0: No pruning # SAVE LIMIT > 0: Prune database, SAVE_LIMIT 0: No pruning
close_old_django_connections() if not task.get("sync", False):
close_old_django_connections()
try: try:
filters = {} filters = {}
@@ -107,35 +108,32 @@ def save_task(task, broker: Broker):
value = get_func_repr(value) value = get_func_repr(value)
filters[Conf.SAVE_LIMIT_PER] = value filters[Conf.SAVE_LIMIT_PER] = value
with db.transaction.atomic(using=db.router.db_for_write(Success)): # check if we should clean the success tasks
last = Success.objects.filter(**filters).select_for_update().last() if Conf.SAVE_LIMIT > 0:
if ( with db.transaction.atomic(using=db.router.db_for_write(Success)):
task["success"] success_tasks_qs = Success.objects.filter(**filters)
and 0 < Conf.SAVE_LIMIT <= Success.objects.filter(**filters).count() success_tasks_pks = [
): success_task.pk
last.delete() for success_task in success_tasks_qs.select_for_update()
]
if task["success"] and len(success_tasks_pks) >= Conf.SAVE_LIMIT:
success_tasks_qs.last().delete()
# check if this task has previous results # check if this task has previous results
try: try:
existing_task = Task.objects.get(id=task["id"], name=task["name"]) task_obj = Task.objects.get(id=task["id"], name=task["name"])
# only update the result if it hasn't succeeded yet # only update the result if it hasn't succeeded yet
if not existing_task.success: if not task_obj.success:
existing_task.stopped = task["stopped"] task_obj.stopped = task["stopped"]
existing_task.result = task["result"] task_obj.result = task["result"]
existing_task.success = task["success"] task_obj.success = task["success"]
existing_task.attempt_count = existing_task.attempt_count + 1 task_obj.attempt_count = task_obj.attempt_count + 1
existing_task.save() task_obj.save()
if (
Conf.MAX_ATTEMPTS > 0
and existing_task.attempt_count >= Conf.MAX_ATTEMPTS
):
broker.acknowledge(task["ack_id"])
except Task.DoesNotExist: except Task.DoesNotExist:
# convert func to string # convert func to string
func = get_func_repr(task["func"]) func = get_func_repr(task["func"])
Task.objects.create( task_obj = Task.objects.create(
id=task["id"], id=task["id"],
name=task["name"], name=task["name"],
func=func, func=func,
@@ -150,12 +148,20 @@ def save_task(task, broker: Broker):
success=task["success"], success=task["success"],
attempt_count=1, attempt_count=1,
) )
if (
Conf.MAX_ATTEMPTS > 0
and task_obj.attempt_count >= Conf.MAX_ATTEMPTS
and task.get("ack_id")
):
broker.acknowledge(task["ack_id"])
except Exception: except Exception:
logger.exception("Could not save task result") logger.exception("Could not save task result")
def save_cached(task, broker: Broker): def save_cached(task, broker: Broker):
task_key = f'{broker.list_key}:{task["id"]}' task_key = f"{broker.list_key}:{task['id']}"
timeout = task["cached"] timeout = task["cached"]
if timeout is True: if timeout is True:
timeout = None timeout = None
+23 -15
View File
@@ -97,7 +97,9 @@ def monitor(run_once=False, broker=None):
for stat in stats: for stat in stats:
status = stat.status status = stat.status
# color status # color status
if stat.status == Conf.WORKING: if stat.status == Conf.STARTING:
status = term.yellow(str(Conf.STARTING))
elif stat.status == Conf.WORKING:
status = term.green(str(Conf.WORKING)) status = term.green(str(Conf.WORKING))
elif stat.status == Conf.STOPPING: elif stat.status == Conf.STOPPING:
status = term.yellow(str(Conf.STOPPING)) status = term.yellow(str(Conf.STOPPING))
@@ -105,6 +107,8 @@ def monitor(run_once=False, broker=None):
status = term.red(str(Conf.STOPPED)) status = term.red(str(Conf.STOPPED))
elif stat.status == Conf.IDLE: elif stat.status == Conf.IDLE:
status = str(Conf.IDLE) status = str(Conf.IDLE)
else:
status = _("Unknown")
# color q's # color q's
tasks = str(stat.task_q_size) tasks = str(stat.task_q_size)
if stat.task_q_size > 0: if stat.task_q_size > 0:
@@ -114,10 +118,14 @@ def monitor(run_once=False, broker=None):
results = stat.done_q_size results = stat.done_q_size
if results > 0: if results > 0:
results = term.cyan(str(results)) results = term.cyan(str(results))
else:
results = str(results)
# color workers # color workers
workers = len(stat.workers) workers = len(stat.workers)
if workers < Conf.WORKERS: if workers < Conf.WORKERS:
workers = term.yellow(str(workers)) workers = term.yellow(str(workers))
else:
workers = str(workers)
# format uptime # format uptime
uptime = (timezone.now() - stat.tob).total_seconds() uptime = (timezone.now() - stat.tob).total_seconds()
hours, remainder = divmod(uptime, 3600) hours, remainder = divmod(uptime, 3600)
@@ -150,7 +158,7 @@ def monitor(run_once=False, broker=None):
) )
print( print(
term.move(i, 6 * col_width) term.move(i, 6 * col_width)
+ term.center(stat.reincarnations, width=col_width - 1) + term.center(str(stat.reincarnations), width=col_width - 1)
) )
print( print(
term.move(i, 7 * col_width) term.move(i, 7 * col_width)
@@ -173,7 +181,7 @@ def monitor(run_once=False, broker=None):
) )
print( print(
term.move(i, 3 * col_width) term.move(i, 3 * col_width)
+ term.white_on_cyan(term.center(queue_size, width=col_width)) + term.white_on_cyan(term.center(str(queue_size), width=col_width))
) )
print( print(
term.move(i, 4 * col_width) term.move(i, 4 * col_width)
@@ -182,7 +190,7 @@ def monitor(run_once=False, broker=None):
print( print(
term.move(i, 5 * col_width) term.move(i, 5 * col_width)
+ term.white_on_cyan( + term.white_on_cyan(
term.center(models.Success.objects.count(), width=col_width) term.center(str(models.Success.objects.count()), width=col_width)
) )
) )
print( print(
@@ -192,7 +200,7 @@ def monitor(run_once=False, broker=None):
print( print(
term.move(i, 7 * col_width) term.move(i, 7 * col_width)
+ term.white_on_cyan( + term.white_on_cyan(
term.center(models.Failure.objects.count(), width=col_width) term.center(str(models.Failure.objects.count()), width=col_width)
) )
) )
# for testing # for testing
@@ -397,9 +405,7 @@ def memory(run_once=False, workers=False, broker=None):
2, 2,
) )
# memory available (MB) # memory available (MB)
memory_available = round( memory_available = round(psutil.virtual_memory().available / 1024**2, 2)
psutil.virtual_memory().available / 1024**2, 2
)
if memory_available_percentage < MEMORY_AVAILABLE_LOWEST_PERCENTAGE: if memory_available_percentage < MEMORY_AVAILABLE_LOWEST_PERCENTAGE:
MEMORY_AVAILABLE_LOWEST_PERCENTAGE = memory_available_percentage MEMORY_AVAILABLE_LOWEST_PERCENTAGE = memory_available_percentage
MEMORY_AVAILABLE_LOWEST_PERCENTAGE_AT = timezone.now() MEMORY_AVAILABLE_LOWEST_PERCENTAGE_AT = timezone.now()
@@ -413,27 +419,29 @@ def memory(run_once=False, workers=False, broker=None):
) )
print( print(
term.move(row, 2 * col_width) term.move(row, 2 * col_width)
+ term.center(memory_available_percentage, width=col_width - 1) + term.center(str(memory_available_percentage), width=col_width - 1)
) )
print( print(
term.move(row, 3 * col_width) term.move(row, 3 * col_width)
+ term.center(memory_available, width=col_width - 1) + term.center(str(memory_available), width=col_width - 1)
) )
print( print(
term.move(row, 4 * col_width) term.move(row, 4 * col_width)
+ term.center( + term.center(
round(psutil.virtual_memory().total / 1024**2, 2), str(round(psutil.virtual_memory().total / 1024**2, 2)),
width=col_width - 1, width=col_width - 1,
) )
) )
print( print(
term.move(row, 5 * col_width) term.move(row, 5 * col_width)
+ term.center(get_process_mb(stat.sentinel), width=col_width - 1) + term.center(
str(get_process_mb(stat.sentinel)), width=col_width - 1
)
) )
print( print(
term.move(row, 6 * col_width) term.move(row, 6 * col_width)
+ term.center( + term.center(
get_process_mb(getattr(stat, "monitor", None)), str(get_process_mb(getattr(stat, "monitor", None))),
width=col_width - 1, width=col_width - 1,
) )
) )
@@ -446,7 +454,7 @@ def memory(run_once=False, workers=False, broker=None):
print( print(
term.move(row, 7 * col_width) term.move(row, 7 * col_width)
+ term.center( + term.center(
workers_mb or "NO_PROCESSES_FOUND", width=col_width - 1 str(workers_mb or "NO_PROCESSES_FOUND"), width=col_width - 1
) )
) )
row += 1 row += 1
@@ -478,7 +486,7 @@ def memory(run_once=False, workers=False, broker=None):
mb_used = get_process_mb(worker_pid) mb_used = get_process_mb(worker_pid)
print( print(
term.move(row, (idx + 1) * col_width) term.move(row, (idx + 1) * col_width)
+ term.center(mb_used, width=col_width - 1) + term.center(str(mb_used), width=col_width - 1)
) )
row += 1 row += 1
row += 1 row += 1
+4 -4
View File
@@ -4,8 +4,8 @@ from multiprocessing.queues import Queue
from time import sleep from time import sleep
from django import core from django import core
from django.utils.translation import gettext_lazy as _
from django.apps.registry import apps from django.apps.registry import apps
from django.utils.translation import gettext_lazy as _
try: try:
apps.check_apps_ready() apps.check_apps_ready()
@@ -58,9 +58,9 @@ def pusher(task_queue: Queue, event: Event, broker: Broker = None):
logger.exception("Failed to push task to queue") logger.exception("Failed to push task to queue")
broker.fail(ack_id) broker.fail(ack_id)
continue continue
task[ task["cluster"] = (
"cluster" Conf.CLUSTER_NAME
] = Conf.CLUSTER_NAME # save actual cluster name to orm task table ) # save actual cluster name to orm task table
task["ack_id"] = ack_id task["ack_id"] = ack_id
task_queue.put(task) task_queue.put(task)
logger.debug( logger.debug(
+1
View File
@@ -2,6 +2,7 @@
The code is derived from The code is derived from
https://github.com/althonos/pronto/commit/3384010dfb4fc7c66a219f59276adef3288a886b https://github.com/althonos/pronto/commit/3384010dfb4fc7c66a219f59276adef3288a886b
""" """
import multiprocessing import multiprocessing
import multiprocessing.queues import multiprocessing.queues
import sys import sys
+3 -4
View File
@@ -2,11 +2,10 @@ import ast
from multiprocessing.process import current_process from multiprocessing.process import current_process
from django import core, db from django import core, db
from django.apps.registry import apps
from django.utils import timezone from django.utils import timezone
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.apps.registry import apps
try: try:
apps.check_apps_ready() apps.check_apps_ready()
except core.exceptions.AppRegistryNotReady: except core.exceptions.AppRegistryNotReady:
@@ -66,7 +65,7 @@ def scheduler(broker: Broker = None):
if s.args: if s.args:
args = ast.literal_eval(s.args) args = ast.literal_eval(s.args)
# single value won't eval to tuple, so: # single value won't eval to tuple, so:
if type(args) != tuple: if type(args) is not tuple:
args = (args,) args = (args,)
q_options = kwargs.get("q_options", {}) q_options = kwargs.get("q_options", {})
if s.intended_date_kwarg: if s.intended_date_kwarg:
@@ -86,7 +85,7 @@ def scheduler(broker: Broker = None):
# Little Fix for already broken numbers # Little Fix for already broken numbers
if s.repeats < -1: if s.repeats < -1:
s.repeats = -1 s.repeats = -1
# Check if the value is not zero # Check if the value is not zero
if s.repeats > 0: if s.repeats > 0:
s.repeats -= 1 s.repeats -= 1
+3
View File
@@ -43,3 +43,6 @@ pre_execute = Signal()
# args: task # args: task
post_execute = Signal() post_execute = Signal()
# args: func, task
post_execute_in_worker = Signal()
+1
View File
@@ -1,4 +1,5 @@
"""Package signing.""" """Package signing."""
import pickle import pickle
from django_q import core_signing as signing from django_q import core_signing as signing
+7 -6
View File
@@ -1,4 +1,5 @@
"""Provides task functionality.""" """Provides task functionality."""
# Standard # Standard
from multiprocessing import Value from multiprocessing import Value
from time import sleep, time from time import sleep, time
@@ -460,7 +461,9 @@ def async_iter(func, args_iter, **kwargs):
# save the original arguments # save the original arguments
broker = options["broker"] broker = options["broker"]
broker.cache.set( broker.cache.set(
f"{broker.list_key}:{iter_group}:args", SignedPackage.dumps(args_iter) f"{broker.list_key}:{iter_group}:args",
SignedPackage.dumps(args_iter),
timeout=None,
) )
for args in args_iter: for args in args_iter:
if not isinstance(args, tuple): if not isinstance(args, tuple):
@@ -569,7 +572,9 @@ class Chain:
A sequential chain of tasks A sequential chain of tasks
""" """
def __init__(self, chain=None, group=None, cached=Conf.CACHED, sync=Conf.SYNC, broker=None): def __init__(
self, chain=None, group=None, cached=Conf.CACHED, sync=Conf.SYNC, broker=None
):
self.chain = chain or [] self.chain = chain or []
self.group = group or "" self.group = group or ""
self.broker = broker or get_broker() self.broker = broker or get_broker()
@@ -729,17 +734,14 @@ class AsyncTask:
return self.id return self.id
def result(self, wait=0): def result(self, wait=0):
if self.started: if self.started:
return result(self.id, wait=wait, cached=self.cached) return result(self.id, wait=wait, cached=self.cached)
def fetch(self, wait=0): def fetch(self, wait=0):
if self.started: if self.started:
return fetch(self.id, wait=wait, cached=self.cached) return fetch(self.id, wait=wait, cached=self.cached)
def result_group(self, failures=False, wait=0, count=None): def result_group(self, failures=False, wait=0, count=None):
if self.started and self.group: if self.started and self.group:
return result_group( return result_group(
self.group, self.group,
@@ -750,7 +752,6 @@ class AsyncTask:
) )
def fetch_group(self, failures=True, wait=0, count=None): def fetch_group(self, failures=True, wait=0, count=None):
if self.started and self.group: if self.started and self.group:
return fetch_group( return fetch_group(
self.group, self.group,
+1 -1
View File
@@ -116,7 +116,7 @@ CACHES = {
"LOCATION": f"redis://{REDIS_HOST}:6379/0", "LOCATION": f"redis://{REDIS_HOST}:6379/0",
"OPTIONS": { "OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient", "CLIENT_CLASS": "django_redis.client.DefaultClient",
"PARSER_CLASS": "redis.connection.HiredisParser", "PARSER_CLASS": "redis.connection.DefaultParser",
}, },
} }
} }
+61 -11
View File
@@ -35,6 +35,57 @@ def test_broker(monkeypatch):
assert broker.get_stats("test:*") is None assert broker.get_stats("test:*") is None
def test_broker_set_stat_prunes_stale_master_list():
# regression: set_stat should prune stale master-list entries on register
broker = Broker()
a_key = f"{Conf.Q_STAT}:A"
b_key = f"{Conf.Q_STAT}:B"
broker.cache.delete(Conf.Q_STAT)
broker.set_stat(a_key, "state_a", 3)
assert a_key in broker.cache.get(Conf.Q_STAT)
# Drop A's per-stat value to simulate a dead cluster whose TTL expired,
# leaving the master-list entry as a stale reference.
broker.cache.delete(a_key)
assert broker.get_stat(a_key) is None
assert a_key in broker.cache.get(Conf.Q_STAT)
# Registering B should prune stale A from the master list.
broker.set_stat(b_key, "state_b", 3)
key_list = broker.cache.get(Conf.Q_STAT)
assert a_key not in key_list
assert b_key in key_list
assert broker.get_stat(b_key) == "state_b"
def test_broker_set_stat_skips_master_list_write_on_repeat(monkeypatch):
# set_stat should only write the master list when membership changes
broker = Broker()
a_key = f"{Conf.Q_STAT}:A"
broker.cache.delete(Conf.Q_STAT)
writes = []
orig_set = broker.cache.set
def counting_set(key, value, timeout=None, **kw):
if key == Conf.Q_STAT:
writes.append(key)
return orig_set(key, value, timeout, **kw)
monkeypatch.setattr(broker.cache, "set", counting_set)
# First call adds a new entry, one master-list write expected
broker.set_stat(a_key, "state_a", 3)
assert len(writes) == 1
# Subsequent calls for the same key must not rewrite the master list
broker.set_stat(a_key, "state_a", 3)
broker.set_stat(a_key, "state_a", 3)
broker.set_stat(a_key, "state_a", 3)
assert len(writes) == 1
def test_redis(monkeypatch): def test_redis(monkeypatch):
monkeypatch.setattr(Conf, "DJANGO_REDIS", None) monkeypatch.setattr(Conf, "DJANGO_REDIS", None)
broker = get_broker() broker = get_broker()
@@ -51,7 +102,7 @@ def test_redis(monkeypatch):
def test_custom(monkeypatch): def test_custom(monkeypatch):
monkeypatch.setattr(Conf, "BROKER_CLASS", "brokers.redis_broker.Redis") monkeypatch.setattr(Conf, "BROKER_CLASS", "django_q.brokers.redis_broker.Redis")
broker = get_broker() broker = get_broker()
assert broker.ping() is True assert broker.ping() is True
assert broker.info() is not None assert broker.info() is not None
@@ -121,10 +172,7 @@ def test_ironmq(monkeypatch):
broker.delete_queue() broker.delete_queue()
@pytest.mark.skipif( def test_sqs(monkeypatch):
not os.getenv("AWS_ACCESS_KEY_ID"), reason="requires AWS credentials"
)
def canceled_sqs(monkeypatch):
monkeypatch.setattr( monkeypatch.setattr(
Conf, Conf,
"SQS", "SQS",
@@ -132,11 +180,14 @@ def canceled_sqs(monkeypatch):
"aws_region": os.getenv("AWS_REGION"), "aws_region": os.getenv("AWS_REGION"),
"aws_access_key_id": os.getenv("AWS_ACCESS_KEY_ID"), "aws_access_key_id": os.getenv("AWS_ACCESS_KEY_ID"),
"aws_secret_access_key": os.getenv("AWS_SECRET_ACCESS_KEY"), "aws_secret_access_key": os.getenv("AWS_SECRET_ACCESS_KEY"),
"receive_message_wait_time_seconds": 20, "receive_message_wait_time_seconds": 5,
}, },
) )
# check broker # check broker
broker = get_broker(list_key=uuid()[0]) broker = get_broker(list_key="testing")
broker.purge_queue()
assert "receive_message_wait_time_seconds" in Conf.SQS
assert "aws_region" in Conf.SQS
assert broker.ping() is True assert broker.ping() is True
assert broker.info() is not None assert broker.info() is not None
assert broker.queue_size() == 0 assert broker.queue_size() == 0
@@ -171,9 +222,10 @@ def canceled_sqs(monkeypatch):
assert broker.dequeue() is None assert broker.dequeue() is None
# fail # fail
broker.enqueue("test") broker.enqueue("test")
task = None
while task is None: while task is None:
task = broker.dequeue()[0] task = broker.dequeue()
broker.fail(task[0]) broker.fail(task[0][0])
# bulk test # bulk test
for _ in range(10): for _ in range(10):
broker.enqueue("test") broker.enqueue("test")
@@ -182,8 +234,6 @@ def canceled_sqs(monkeypatch):
for task in tasks: for task in tasks:
assert task is not None assert task is not None
broker.acknowledge(task[0]) broker.acknowledge(task[0])
# duplicate acknowledge
broker.acknowledge(task[0])
assert broker.lock_size() == 0 assert broker.lock_size() == 0
# delete queue # delete queue
broker.enqueue("test") broker.enqueue("test")
+23
View File
@@ -1,3 +1,5 @@
import time
from copy import deepcopy
from multiprocessing import Event, Value from multiprocessing import Event, Value
import pytest import pytest
@@ -128,6 +130,27 @@ def test_iter(broker):
assert len(i.result()) == 5 assert len(i.result()) == 5
def _sleeping_func(_):
time.sleep(1)
@pytest.mark.django_db
def test_iter_default_cache_timeout(broker, settings):
"""
Test async_iter when it completes after the default Django
cache timeout expires.
"""
cache_settings = deepcopy(settings.CACHES)
cache_settings["default"]["TIMEOUT"] = 1
settings.CACHES = cache_settings
broker.purge_queue()
broker.cache.clear()
it = [i for i in range(2)]
t = async_iter(_sleeping_func, it, sync=True)
result_t = result(t)
assert result_t is not None
@pytest.mark.django_db @pytest.mark.django_db
def test_chain(broker): def test_chain(broker):
broker.purge_queue() broker.purge_queue()
+199 -5
View File
@@ -1,4 +1,6 @@
import multiprocessing
import os import os
import signal
import sys import sys
import threading import threading
import uuid as uuidlib import uuid as uuidlib
@@ -12,14 +14,19 @@ import pytest
from django.utils import timezone from django.utils import timezone
from django_q.brokers import Broker, get_broker from django_q.brokers import Broker, get_broker
from django_q.cluster import Cluster, Sentinel from django_q.cluster import Cluster, Sentinel, get_mp_context
from django_q.conf import Conf from django_q.conf import Conf
from django_q.humanhash import DEFAULT_WORDLIST, uuid from django_q.humanhash import DEFAULT_WORDLIST, uuid
from django_q.models import Success, Task from django_q.models import Success, Task
from django_q.monitor import monitor, save_task from django_q.monitor import monitor, save_task
from django_q.pusher import pusher from django_q.pusher import pusher
from django_q.queues import Queue from django_q.queues import Queue
from django_q.signals import post_execute, pre_enqueue, pre_execute from django_q.signals import (
post_execute,
post_execute_in_worker,
pre_enqueue,
pre_execute,
)
from django_q.status import Stat from django_q.status import Stat
from django_q.tasks import ( from django_q.tasks import (
async_task, async_task,
@@ -53,6 +60,53 @@ def broker(monkeypatch):
return get_broker() return get_broker()
def test_get_mp_context_prefers_fork_when_available(monkeypatch):
monkeypatch.setattr(
multiprocessing,
"get_all_start_methods",
lambda: ["fork", "spawn", "forkserver"],
)
calls = []
class DummyContext:
def get_start_method(self):
return "fork"
def fake_get_context(method=None):
calls.append(method)
return DummyContext()
monkeypatch.setattr(multiprocessing, "get_context", fake_get_context)
assert get_mp_context().get_start_method() == "fork"
assert calls == ["fork"]
def test_get_mp_context_falls_back_to_platform_default_without_fork(monkeypatch):
"""
Regression test: get_mp_context() used to hardcode the unix-only "fork"
context, which raises ValueError on platforms (e.g. Windows) that don't
support it. It should instead defer to the platform's default context
whenever "fork" isn't available.
"""
monkeypatch.setattr(multiprocessing, "get_all_start_methods", lambda: ["spawn"])
calls = []
real_get_context = multiprocessing.get_context
def fake_get_context(method=None):
calls.append(method)
return real_get_context(method)
monkeypatch.setattr(multiprocessing, "get_context", fake_get_context)
get_mp_context()
# Must ask for the platform default (no explicit method), should never be equal to "fork"
assert calls == [None]
def test_redis_connection(broker): def test_redis_connection(broker):
assert broker.ping() is True assert broker.ping() is True
@@ -93,6 +147,116 @@ def test_cluster_initial(broker):
broker.delete_queue() broker.delete_queue()
class TestEarlyClusterStop:
sentinel_event = Event()
test_event = Event()
@staticmethod
def _fake_ping_for_test_cluster_early_stop():
"""
Fake broker ping() method for test_cluster_early_stop()
This is called in the sentinel process's start() method and overriding it allows
us to synchronize the sentinel process with the main process to provide a
deterministic ordering of operations for the test.
This is implemented as a static method so the patched broker remains pickleable
for passing to the sentinel process, in case anyone ever runs the test on
platforms like MacOS that use spawn Process start method.
"""
# let the main process know the sentinel is waiting
TestEarlyClusterStop.sentinel_event.set()
# wait for the main process to let the sentinel proceed. The timeout prevents
# the test from hanging if the main process terminates unexpectedly before
# setting the event.
assert TestEarlyClusterStop.test_event.wait(10)
@pytest.mark.django_db
def test_cluster_early_stop(self, broker, monkeypatch):
"""
Test stopping the cluster before the sentinel has set the cluster's start_event
"""
def raise_sigterm():
# wait for the sentinel to be blocked in fake_ping(). Periodically check
# that the sentinel is alive in case the sentinel dies unexpectedly before
# setting the sentinel_event -- prevents the test from hanging if sentinel
# dies unexpectedly.
while True:
if self.sentinel_event.wait(0.5):
break
if not c.sentinel.is_alive():
break
# stop the cluster via SIGTERM
os.kill(os.getpid(), signal.SIGTERM)
# unblock the sentinel
self.test_event.set()
monkeypatch.setattr(
broker,
"ping",
self._fake_ping_for_test_cluster_early_stop,
)
broker.list_key = "initial_test:q"
broker.delete_queue()
c = Cluster(broker=broker)
assert c.sentinel is None
assert c.stat.status == Conf.STOPPED
# Use a timer to stop the cluster while it is still starting up. The timer function
# is guaranteed to run before c.start() returns, as start() must wait for the
# sentinel to set the cluster's start_event, and the sentinel will block on
# test_event before setting start_event.
threading.Timer(0.5, raise_sigterm).start()
c.start()
stat = c.stat
assert stat.status == Conf.STOPPED
assert c.sentinel.is_alive() is False
assert c.has_stopped
broker.delete_queue()
@pytest.mark.django_db
def test_cluster_stop_responsive(broker, monkeypatch):
"""
Ensure that stopping the cluster is responsive and does not wait for a full
GUARD_CYCLE.
"""
timeout_seconds = 5
def timeout(signal, frame):
assert 0, f"cluster did not stop after {timeout_seconds}s"
broker.list_key = "initial_test:q"
broker.delete_queue()
# set a long GUARD_CYCLE -- greater than timeout_seconds
monkeypatch.setattr(Conf, "GUARD_CYCLE", timeout_seconds * 2)
c = Cluster(broker=broker)
assert c.sentinel is None
assert c.stat.status == Conf.STOPPED
assert c.start() > 0
assert c.sentinel.is_alive() is True
assert c.is_running
assert c.is_stopping is False
assert c.is_starting is False
sleep(0.5)
stat = c.stat
assert stat.status == Conf.IDLE
prev_handler = signal.signal(signal.SIGALRM, timeout)
try:
signal.alarm(timeout_seconds)
assert c.stop() is True
finally:
signal.alarm(0) # cancel the alarm
signal.signal(signal.SIGALRM, prev_handler)
assert c.sentinel.is_alive() is False
assert c.has_stopped
assert c.stop() is False
broker.delete_queue()
@pytest.mark.django_db @pytest.mark.django_db
def test_sentinel(): def test_sentinel():
start_event = Event() start_event = Event()
@@ -399,7 +563,7 @@ def test_timeout_task_finishes(broker, cluster_config_timeout, async_task_kwargs
@pytest.mark.django_db @pytest.mark.django_db
def test_recycle(broker, monkeypatch): def test_recycle(broker, monkeypatch, django_assert_num_queries):
# set up the Sentinel # set up the Sentinel
broker.list_key = "test_recycle_test:q" broker.list_key = "test_recycle_test:q"
async_task("django_q.tests.tasks.multiply", 2, 2, broker=broker) async_task("django_q.tests.tasks.multiply", 2, 2, broker=broker)
@@ -432,7 +596,8 @@ def test_recycle(broker, monkeypatch):
monkeypatch.setattr(Conf, "SAVE_LIMIT", 1) monkeypatch.setattr(Conf, "SAVE_LIMIT", 1)
result_queue.put("STOP") result_queue.put("STOP")
# run monitor # run monitor
monitor(result_queue) with django_assert_num_queries(12):
monitor(result_queue)
assert Success.objects.count() == Conf.SAVE_LIMIT assert Success.objects.count() == Conf.SAVE_LIMIT
broker.delete_queue() broker.delete_queue()
@@ -487,7 +652,7 @@ def test_max_rss(broker, monkeypatch):
stop_event = Event() stop_event = Event()
cluster_id = uuidlib.uuid4() cluster_id = uuidlib.uuid4()
# override settings # override settings
monkeypatch.setattr(Conf, "MAX_RSS", 40000) monkeypatch.setattr(Conf, "MAX_RSS", 20000)
monkeypatch.setattr(Conf, "WORKERS", 1) monkeypatch.setattr(Conf, "WORKERS", 1)
# set a timer to stop the Sentinel # set a timer to stop the Sentinel
threading.Timer(3, stop_event.set).start() threading.Timer(3, stop_event.set).start()
@@ -759,6 +924,35 @@ class TestSignals:
assert self.task.get("result") == -1 assert self.task.get("result") == -1
post_execute.disconnect(handler) post_execute.disconnect(handler)
@pytest.mark.django_db
def test_post_execute_in_worker_signal(self, broker):
broker.list_key = "post_execute_in_worker_test:q"
broker.delete_queue()
self.signal_was_called: bool = False
self.task: Optional[dict] = None
self.func = None
def handler(sender, task, **kwargs):
self.signal_was_called = True
self.task = task
post_execute_in_worker.connect(handler)
task_id = async_task("math.copysign", 1, -1, broker=broker)
task_queue = Queue()
result_queue = Queue()
event = Event()
event.set()
pusher(task_queue, event, broker=broker)
task_queue.put("STOP")
worker(task_queue, result_queue, Value("f", -1))
result_queue.put("STOP")
monitor(result_queue, broker)
broker.delete_queue()
assert self.signal_was_called is True
assert self.task.get("id") == task_id
assert self.task.get("result") == -1
post_execute_in_worker.disconnect(handler)
@pytest.mark.django_db @pytest.mark.django_db
def assert_result(task): def assert_result(task):
+41
View File
@@ -473,6 +473,47 @@ def test_scheduler_atomic_must_specify_the_database_based_on_router_redirection(
mocked_db.atomic.assert_called_with(using="default") mocked_db.atomic.assert_called_with(using="default")
@pytest.mark.django_db
def test_schedule_save_sets_next_run_for_cron():
"""Ensure Schedule.save() sets next_run correctly for CRON schedules."""
cron_expression = "0 12 * * *" # Executes dialy at 12pm
schedule = Schedule(
func="math.sqrt",
schedule_type=Schedule.CRON,
cron=cron_expression,
)
assert schedule.next_run is not None
assert schedule.pk is None
initial_next_run = schedule.next_run
schedule.save()
# After save, next_run must be recalculated based on the CRON expression
assert schedule.next_run > initial_next_run
@pytest.mark.django_db
def test_schedule_save_direct_db(broker):
"""Ensure Schedule.save() updates next_run correctly when created directly in DB."""
cron_expression = "0 12 * * *" # Executes dialy at 12pm
# Creating schedule directly in database
schedule = Schedule.objects.create(
func="math.sqrt",
schedule_type=Schedule.CRON,
cron=cron_expression,
)
# Next run must be defined after execution time
assert schedule.next_run is not None
assert schedule.next_run > timezone.now()
scheduler(broker)
assert broker.queue_size() == 0
def test_localtime(): def test_localtime():
assert not is_naive(localtime()) assert not is_naive(localtime())
+43
View File
@@ -0,0 +1,43 @@
import signal
from django.utils.translation import gettext_lazy as _
from django_q.conf import logger
from .exceptions import TimeoutException
class TimeoutHandler:
def __init__(self, timeout: int):
self._timeout = timeout
def raise_timeout_exception(self, signum, frame):
raise TimeoutException(
f"Task exceeded maximum timeout value ({self._timeout} seconds)"
)
def __enter__(self):
# if the timeout is -1, then there is no timeout and the task will always keep running until it's done or manually killed
if self._timeout == -1:
return
try:
signal.signal(signal.SIGALRM, self.raise_timeout_exception)
signal.alarm(self._timeout)
except (
ValueError,
AttributeError,
): # AttributeError or ValueError might be raised for Windows users
logger.debug(_("SIGALARM is not available on your platform"))
def __exit__(self, exc_type, exc_value, traceback):
if self._timeout == -1:
return
"""When getting out of the timeout, reset the alarm, so it won't trigger"""
try:
signal.alarm(0)
signal.signal(signal.SIGALRM, signal.SIG_DFL)
except (
ValueError,
AttributeError,
): # AttributeError or ValueError might be raised for Windows users
logger.debug(_("SIGALARM is not available on your platform"))
+1 -3
View File
@@ -50,9 +50,7 @@ def get_func_repr(func):
if inspect.isfunction(func): if inspect.isfunction(func):
return f"{func.__module__}.{func.__name__}" return f"{func.__module__}.{func.__name__}"
elif inspect.ismethod(func) and hasattr(func.__self__, "__name__"): elif inspect.ismethod(func) and hasattr(func.__self__, "__name__"):
return ( return f"{func.__self__.__module__}.{func.__self__.__name__}.{func.__name__}"
f"{func.__self__.__module__}." f"{func.__self__.__name__}.{func.__name__}"
)
else: else:
return str(func) if func else None return str(func) if func else None
+22 -5
View File
@@ -5,9 +5,9 @@ from multiprocessing.process import current_process
from multiprocessing.queues import Queue from multiprocessing.queues import Queue
from django import core from django import core
from django.apps.registry import apps
from django.utils import timezone from django.utils import timezone
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.apps.registry import apps
try: try:
apps.check_apps_ready() apps.check_apps_ready()
@@ -17,7 +17,9 @@ except core.exceptions.AppRegistryNotReady:
django.setup() django.setup()
from django_q.conf import Conf, error_reporter, logger, resource, setproctitle from django_q.conf import Conf, error_reporter, logger, resource, setproctitle
from django_q.signals import post_spawn, pre_execute from django_q.exceptions import TimeoutException
from django_q.signals import post_execute_in_worker, post_spawn, pre_execute
from django_q.timeout import TimeoutHandler
from django_q.utils import close_old_django_connections, get_func_repr from django_q.utils import close_old_django_connections, get_func_repr
try: try:
@@ -83,31 +85,46 @@ def worker(
if not callable(f): if not callable(f):
# locate() returns None if f cannot be loaded # locate() returns None if f cannot be loaded
f = pydoc.locate(f) f = pydoc.locate(f)
close_old_django_connections() if not task.get("sync", False):
close_old_django_connections()
timer_value = task.pop("timeout", timeout) timer_value = task.pop("timeout", timeout)
# signal execution # signal execution
pre_execute.send(sender="django_q", func=f, task=task) pre_execute.send(sender="django_q", func=f, task=task)
# execute the payload # execute the payload
timer.value = timer_value # Busy timer.value = timer_value # Busy
if timer.value != -1:
timer.value += 3 # Add buffer so that guard doesn't kill the process on timeout before it gets processed
timeout_error = False
try: try:
if f is None: if f is None:
# raise a meaningfull error if task["func"] is not a valid function # raise a meaningfull error if task["func"] is not a valid function
raise ValueError(f"Function {task['func']} is not defined") raise ValueError(f"Function {task['func']} is not defined")
res = f(*task["args"], **task["kwargs"]) with TimeoutHandler(timer_value):
res = f(*task["args"], **task["kwargs"])
result = (res, True) result = (res, True)
except Exception as e: except (Exception, TimeoutException) as e:
if isinstance(e, TimeoutException):
timeout_error = True
result = (f"{e} : {traceback.format_exc()}", False) result = (f"{e} : {traceback.format_exc()}", False)
if error_reporter: if error_reporter:
error_reporter.report() error_reporter.report()
if task.get("sync", False): if task.get("sync", False):
post_execute_in_worker.send(sender="django_q", func=f, task=task)
raise raise
with timer.get_lock(): with timer.get_lock():
# Process result # Process result
task["result"] = result[0] task["result"] = result[0]
task["success"] = result[1] task["success"] = result[1]
task["stopped"] = timezone.now() task["stopped"] = timezone.now()
post_execute_in_worker.send(sender="django_q", func=f, task=task)
result_queue.put(task) result_queue.put(task)
if timeout_error:
# force destroy process due to timeout
timer.value = 0
break
timer.value = -1 # Idle timer.value = -1 # Idle
if setproctitle: if setproctitle:
setproctitle.setproctitle(f"qcluster {proc_name} idle") setproctitle.setproctitle(f"qcluster {proc_name} idle")
+2 -2
View File
@@ -73,9 +73,9 @@ author = "Ilan Steemers, Stan Triepels"
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = "1.6" version = "1.11"
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = "1.6.2" release = "1.11.1"
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.
+2
View File
@@ -79,6 +79,8 @@ timeout
The number of seconds a worker is allowed to spend on a task before it's terminated. Defaults to ``None``, meaning it will never time out. The number of seconds a worker is allowed to spend on a task before it's terminated. Defaults to ``None``, meaning it will never time out.
Set this to something that makes sense for your project. Can be overridden for individual tasks. Set this to something that makes sense for your project. Can be overridden for individual tasks.
Note: for systems that don't have `SIGALRM` available (e.g. Windows), it will not raise an error properly. It will kill the task, but it will keep retrying until it finishes within the given time.
See :ref:`retry` for details how to set values for timeout and retry. See :ref:`retry` for details how to set values for timeout and retry.
.. _time_zone: .. _time_zone:
-1
View File
@@ -1,4 +1,3 @@
version: "3.0"
services: services:
docs: docs:
container_name: djangoq2-docs container_name: djangoq2-docs
+1 -1
View File
@@ -27,7 +27,7 @@ Features
- Rollbar and Sentry support - Rollbar and Sentry support
Django Q2 is tested with: Python 3.8, 3.9, 3.10, 3.11 and 3.12. Works with Django 3.2.x, 4.1.x, 4.2.x and 5.0.x Django Q2 is tested with: python 3.10, 3.11, 3.12, 3.13 and 3.14. Works with Django 5.2, 6.0 and 6.1
Currently available in English, German and French. Currently available in English, German and French.
+12 -2
View File
@@ -32,8 +32,14 @@ executed by a worker. This signal provides two arguments:
After executing a task After executing a task
"""""""""""""""""""""" """"""""""""""""""""""
The ``django_q.signals.post_execute`` signal is emitted after a task is - The ``django_q.signals.post_execute_in_worker`` signal is emitted after a task
executed by a worker and processed by the monitor. It included the ``task`` dictionary with the result. is executed by a worker and processed by the **worker**. It included the ``task``
dictionary with the result. Note that this signal is **emitted from, and handled
by, the worker process itself**, not the monitor, unlike the ``post_execute``
signal below.
- The ``django_q.signals.post_execute`` signal is emitted after a task is
executed by a worker and processed by the **monitor**. It included the ``task``
dictionary with the result.
Subscribing to a signal Subscribing to a signal
@@ -56,6 +62,10 @@ signal::
@receiver(post_execute) @receiver(post_execute)
def my_post_execute_callback(sender, task, **kwargs): def my_post_execute_callback(sender, task, **kwargs):
print(f"Task {task['name']} was executed with result {task['result']}") print(f"Task {task['name']} was executed with result {task['result']}")
@receiver(post_execute_in_worker)
def my_post_execute_in_worker_callback(sender, func, task, **kwargs):
print(f"Task {task['name']} was executed with result {task['result']}")
@receiver(post_spawn) @receiver(post_spawn)
def my_post_spawn_callback(sender, proc_name, **kwargs): def my_post_spawn_callback(sender, proc_name, **kwargs):
View File
+16
View File
@@ -0,0 +1,16 @@
"""
ASGI config for exampleproject project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "exampleproject.settings")
application = get_asgi_application()
+134
View File
@@ -0,0 +1,134 @@
"""
Django settings for exampleproject project.
Generated by 'django-admin startproject' using Django 5.1.1.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.1/ref/settings/
"""
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "django-insecure-)oouh93bjg+c=b!l5-*w)7et1l+!3nmp223rr^1r4v#jn&ow3f"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ["*"]
# Application definition
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"django_q",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = "exampleproject.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
WSGI_APPLICATION = "exampleproject.wsgi.application"
# Database
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
# Password validation
# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
# Internationalization
# https://docs.djangoproject.com/en/5.1/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.1/howto/static-files/
STATIC_URL = "static/"
# Default primary key field type
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
Q_CLUSTER = {
"name": "DjangORM",
"workers": 4,
"timeout": 90,
"retry": 120,
"queue_limit": 50,
"bulk": 10,
"orm": "default",
}
+27
View File
@@ -0,0 +1,27 @@
"""
URL configuration for exampleproject project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/5.1/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from exampleproject import views
urlpatterns = [
path("admin/", admin.site.urls),
path("new_task/", views.add_task, name="add_task"),
path("result/<slug:task_id>/", views.get_result, name="get_result"),
]
+31
View File
@@ -0,0 +1,31 @@
import time
from django.http import HttpResponse
from django.urls import reverse
from django_q import tasks
# internal function to be called with django_q
def new_task(run_for_minutes):
print("Task started")
time.sleep(run_for_minutes)
print("Task done")
return True
def add_task(request):
task_id = tasks.async_task(new_task, 5)
result_url = reverse("get_result", args=[task_id])
return HttpResponse(
f"Added async task with <a href='{result_url}'>Go to results</a>"
)
def get_result(request, task_id):
task = tasks.fetch(task_id)
if not task:
msg = "Task running... please refresh after some time"
else:
msg = f"Async task result: {task.result}"
return HttpResponse(msg)
+16
View File
@@ -0,0 +1,16 @@
"""
WSGI config for exampleproject project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "exampleproject.settings")
application = get_wsgi_application()
Generated
-1749
View File
File diff suppressed because it is too large Load Diff
+69 -70
View File
@@ -1,87 +1,86 @@
[build-system] [build-system]
requires = ["poetry-core>=1.0.0"] requires = ["uv_build>=0.10.7,<=0.12.1"]
build-backend = "poetry.core.masonry.api" build-backend = "uv_build"
[tool.poetry] [project]
name = "django-q2" name = "django-q2"
version = "1.6.2" version = "1.11.1"
packages = [ packages = [
{ include = "django_q" }, { include = "django_q" },
] ]
description = "A multiprocessing distributed task queue for Django" description = "A multiprocessing distributed task queue for Django"
authors = ["Stan Triepels <django-q2@stantriepels.com>", "Ilan Steemers <koed00@gmail.com>"] authors = [
maintainers = ["Stan Triepels <django-q2@stantriepels.com>"] { name = "Stan Triepels", email = "django-q2@stantriepels.com" },
{ name = "Ilan Steemers", email = "koed00@gmail.com" },
]
requires-python = ">=3.10,<4"
readme = "README.rst"
license = "MIT" license = "MIT"
readme = 'README.rst' maintainers = [{ name = "Stan Triepels", email = "django-q2@stantriepels.com" }]
keywords = [
repository = "https://github.com/GDay/django-q2" "django",
homepage = "https://django-q2.readthedocs.org" "distributed",
documentation = "https://django-q2.readthedocs.org" "multiprocessing",
"queue",
keywords = ["django", "distributed", "multiprocessing", "queue", "scheduler"] "scheduler",
]
classifiers = [ classifiers = [
'Development Status :: 5 - Production/Stable', "Development Status :: 5 - Production/Stable",
'Environment :: Web Environment', "Environment :: Web Environment",
'Framework :: Django', "Framework :: Django",
'Intended Audience :: Developers', "Intended Audience :: Developers",
'License :: OSI Approved :: MIT License', "Operating System :: POSIX",
'Operating System :: POSIX', "Operating System :: MacOS",
'Operating System :: MacOS', "Programming Language :: Python",
'Programming Language :: Python', "Programming Language :: Python :: 3",
'Programming Language :: Python :: 3', "Programming Language :: Python :: 3.10",
'Programming Language :: Python :: 3.8', "Programming Language :: Python :: 3.11",
'Programming Language :: Python :: 3.9', "Programming Language :: Python :: 3.12",
'Programming Language :: Python :: 3.10', "Programming Language :: Python :: 3.13",
'Programming Language :: Python :: 3.11', "Programming Language :: Python :: 3.14",
'Programming Language :: Python :: 3.12', "Topic :: Internet :: WWW/HTTP",
'Topic :: Internet :: WWW/HTTP', "Topic :: System :: Distributed Computing",
'Topic :: System :: Distributed Computing', "Topic :: Software Development :: Libraries :: Python Modules",
'Topic :: Software Development :: Libraries :: Python Modules', "Programming Language :: Python :: 3.14",
]
dependencies = [
"django>=5.2",
"django-picklefield>=3.1,<4",
"importlib-metadata>=3.6 ; python_full_version < '3.10'",
] ]
include = ['CHANGELOG.md']
[tool.poetry.plugins] # Optional super table [project.optional-dependencies]
testing = [
"django-redis",
"croniter",
"hiredis",
"psutil",
"iron-mq",
"boto3",
"pymongo",
"blessed",
"redis",
"setproctitle",
"pytest",
"pytest-django",
"pytest-cov",
"ruff",
]
croniter = ["croniter"]
[tool.poetry.plugins."djangoq.errorreporters"] [project.urls]
"rollbar" = "django_q_rollbar:Rollbar" Homepage = "https://django-q2.readthedocs.org"
"sentry" = "django_q_sentry:Sentry" Repository = "https://github.com/GDay/django-q2"
Documentation = "https://django-q2.readthedocs.org"
[project.entry-points."djangoq.errorreporters"]
rollbar = "django_q_rollbar:Rollbar"
sentry = "django_q_sentry:Sentry"
[tool.poetry.dependencies] [tool.uv.build-backend]
python = ">=3.8,<4" module-name = ["django_q"]
django = { version = ">=3.2, <6", allow-prereleases = true} module-root = ""
django-picklefield = "^3.1" source-include = ["CHANGELOG.md"]
blessed = { version = "^1.19.1", optional = true }
hiredis = { version = "^2.0.0", optional = true }
psutil = { version = "^5.9.2", optional = true }
django-redis = { version = "^5.2.0", optional = true }
iron-mq = { version = "^0.9", optional = true }
boto3 = { version = "^1.24.92", optional = true }
pymongo = { version = "^4.2.0", optional = true }
croniter = { version = "^2.0.1", optional = true }
django-q-rollbar = {version = ">=0.1", optional = true}
django-q-sentry = {version = ">=0.1", optional = true}
redis = {version = "^4.3.4", optional = true}
setproctitle = {version = "^1.3.2", optional = true}
importlib-metadata = {version = ">=3.6", python = "<3.10"}
[tool.poetry.dev-dependencies]
pytest = "^7.1.3"
pytest-django = "^4.5.2"
Sphinx = "^4.0.2"
pytest-cov = "^4.0.0"
black = "^22.10.0"
isort = {extras = ["requirements_deprecated_finder"], version = "^5.10.1"}
[tool.poetry.extras]
requires = ["poetry_core"]
build-backend = ["poetry.core.masonry.api"]
testing = ["django-redis", "croniter", "hiredis", "psutil", "iron-mq", "boto3", "pymongo", "blessed", "redis", "setproctitle"]
rollbar = ["django-q-rollbar"]
sentry = ["django-q-sentry"]
[tool.isort] [tool.isort]
profile = "black" profile = "black"
+41 -40
View File
@@ -1,40 +1,41 @@
ansicon==1.89.0; platform_system == "Windows" and python_version >= "2.7" \ asgiref==3.8.1 ; python_version >= "3.8" and python_version < "4" \
--hash=sha256:f1def52d17f65c2c9682cf8370c03f541f410c1752d6a14029f97318e4b9dfec \ --hash=sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47 \
--hash=sha256:e4d039def5768a47e4afec8e89e83ec3ae5a26bf00ad851f914d1240b444d2b1 --hash=sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590
arrow==1.1.1; python_version >= "3.6" \ backports-zoneinfo==0.2.1 ; python_version >= "3.8" and python_version < "3.9" \
--hash=sha256:77a60a4db5766d900a2085ce9074c5c7b8e2c99afeaa98ad627637ff6f292510 \ --hash=sha256:17746bd546106fa389c51dbea67c8b7c8f0d14b5526a579ca6ccf5ed72c526cf \
--hash=sha256:dee7602f6c60e3ec510095b5e301441bc56288cb8f51def14dcb3079f623823a --hash=sha256:1b13e654a55cd45672cb54ed12148cd33628f672548f373963b0bff67b217328 \
asgiref==3.3.4; python_version >= "3.6" \ --hash=sha256:1c5742112073a563c81f786e77514969acb58649bcdf6cdf0b4ed31a348d4546 \
--hash=sha256:92906c611ce6c967347bbfea733f13d6313901d54dcca88195eaeb52b2a8e8ee \ --hash=sha256:4a0f800587060bf8880f954dbef70de6c11bbe59c673c3d818921f042f9954a6 \
--hash=sha256:d1216dfbdfb63826470995d31caed36225dcaf34f182e0fa257a4dd9e86f1b78 --hash=sha256:5c144945a7752ca544b4b78c8c41544cdfaf9786f25fe5ffb10e838e19a27570 \
blessed==1.18.1; python_version >= "2.7" \ --hash=sha256:7b0a64cda4145548fed9efc10322770f929b944ce5cee6c0dfe0c87bf4c0c8c9 \
--hash=sha256:dd7c0d33db9a2e7f597b446996484d0ed46e1586239db064fb5025008937dcae \ --hash=sha256:8439c030a11780786a2002261569bdf362264f605dfa4d65090b64b05c9f79a7 \
--hash=sha256:8b09936def6bc06583db99b65636b980075733e13550cb6af262ce724a55da23 --hash=sha256:8961c0f32cd0336fb8e8ead11a1f8cd99ec07145ec2931122faaac1c8f7fd987 \
django-picklefield==3.0.1; python_version >= "3" \ --hash=sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722 \
--hash=sha256:15ccba592ca953b9edf9532e64640329cd47b136b7f8f10f2939caa5f9ce4287 \ --hash=sha256:a76b38c52400b762e48131494ba26be363491ac4f9a04c1b7e92483d169f6582 \
--hash=sha256:3c702a54fde2d322fe5b2f39b8f78d9f655b8f77944ab26f703be6c0ed335a35 --hash=sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc \
django==3.2.4; python_version >= "3.6" \ --hash=sha256:e55b384612d93be96506932a786bbcde5a2db7a9e6a4bb4bffe8b733f5b9036b \
--hash=sha256:ea735cbbbb3b2fba6d4da4784a0043d84c67c92f1fdf15ad6db69900e792c10f \ --hash=sha256:e81b76cace8eda1fca50e345242ba977f9be6ae3945af8d46326d776b4cf78d1 \
--hash=sha256:66c9d8db8cc6fe938a28b7887c1596e42d522e27618562517cc8929eb7e7f296 --hash=sha256:e8236383a20872c0cdf5a62b554b27538db7fa1bbec52429d8d106effbaeca08 \
jinxed==1.1.0; platform_system == "Windows" and python_version >= "2.7" \ --hash=sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac \
--hash=sha256:6a61ccf963c16aa885304f27e6e5693783676897cea0c7f223270c8b8e78baf8 \ --hash=sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2
--hash=sha256:d8f1731f134e9e6b04d95095845ae6c10eb15cb223a5f0cabdea87d4a279c305 django-picklefield==3.2 ; python_version >= "3.8" and python_version < "4" \
python-dateutil==2.8.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6" \ --hash=sha256:aa463f5d79d497dbe789f14b45180f00a51d0d670067d0729f352a3941cdfa4d \
--hash=sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c \ --hash=sha256:e9a73539d110f69825d9320db18bcb82e5189ff48dbed41821c026a20497764c
--hash=sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a django==4.2.11 ; python_version >= "3.8" and python_version < "4" \
pytz==2021.1; python_version >= "3.6" \ --hash=sha256:6e6ff3db2d8dd0c986b4eec8554c8e4f919b5c1ff62a5b4390c17aff2ed6e5c4 \
--hash=sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798 \ --hash=sha256:ddc24a0a8280a0430baa37aff11f28574720af05888c62b7cfe71d219f4599d3
--hash=sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da importlib-metadata==7.1.0 ; python_version >= "3.8" and python_version < "3.10" \
six==1.16.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6" \ --hash=sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570 \
--hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 \ --hash=sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2
--hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 sqlparse==0.5.0 ; python_version >= "3.8" and python_version < "4" \
sqlparse==0.4.1; python_version >= "3.6" \ --hash=sha256:714d0a4932c059d16189f58ef5411ec2287a4360f17cdd0edd2d09d4c5087c93 \
--hash=sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0 \ --hash=sha256:c204494cd97479d0e39f28c93d46c0b2d5959c7b9ab904762ea6c7af211c8663
--hash=sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8 typing-extensions==4.11.0 ; python_version >= "3.8" and python_version < "3.11" \
typing-extensions==3.10.0.0; python_version < "3.8" and python_version >= "3.6" \ --hash=sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0 \
--hash=sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497 \ --hash=sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a
--hash=sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84 \ tzdata==2024.1 ; python_version >= "3.8" and python_version < "4" and sys_platform == "win32" \
--hash=sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342 --hash=sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd \
wcwidth==0.2.5; python_version >= "2.7" \ --hash=sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252
--hash=sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784 \ zipp==3.18.1 ; python_version >= "3.8" and python_version < "3.10" \
--hash=sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83 --hash=sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b \
--hash=sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715
+1
View File
@@ -0,0 +1 @@
lint.extend-select = ["I"]
+24 -2
View File
@@ -1,5 +1,3 @@
version: '3'
services: services:
redis: redis:
image: redis:latest image: redis:latest
@@ -15,15 +13,39 @@ services:
networks: networks:
- main - main
aws:
container_name: aws
image: ministackorg/ministack:1.4.16
ports:
- "127.0.0.1:4566:4566"
environment:
MINISTACK_HOST: aws
SERVICES: sqs
volumes:
- ./containers/ministack:/docker-entrypoint-initaws.d
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:4566/_ministack/ready"]
interval: 2s
retries: 15
networks:
- main
django-q2: django-q2:
build: build:
dockerfile: ./Dockerfile.dev dockerfile: ./Dockerfile.dev
context: . context: .
environment:
AWS_ENDPOINT_URL: http://aws:4566
AWS_REGION: ${AWS_REGION:-us-east-1}
AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID:-test}
AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY:-test}
AWS_DEFAULT_REGION: ${AWS_DEFAULT_REGION:-us-east-1}
volumes: volumes:
- .:/app - .:/app
depends_on: depends_on:
- redis - redis
- mongo - mongo
- aws
networks: networks:
- main - main
Generated
+993
View File
@@ -0,0 +1,993 @@
version = 1
revision = 3
requires-python = ">=3.10, <4"
resolution-markers = [
"python_full_version >= '3.12'",
"python_full_version < '3.12'",
]
[[package]]
name = "ansicon"
version = "1.89.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/b6/e2/1c866404ddbd280efedff4a9f15abfe943cb83cde6e895022370f3a61f85/ansicon-1.89.0.tar.gz", hash = "sha256:e4d039def5768a47e4afec8e89e83ec3ae5a26bf00ad851f914d1240b444d2b1", size = 67312, upload-time = "2019-04-29T20:23:57.314Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/75/f9/f1c10e223c7b56a38109a3f2eb4e7fe9a757ea3ed3a166754fb30f65e466/ansicon-1.89.0-py2.py3-none-any.whl", hash = "sha256:f1def52d17f65c2c9682cf8370c03f541f410c1752d6a14029f97318e4b9dfec", size = 63675, upload-time = "2019-04-29T20:23:53.83Z" },
]
[[package]]
name = "asgiref"
version = "3.11.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/63/40/f03da1264ae8f7cfdbf9146542e5e7e8100a4c66ab48e791df9a03d3f6c0/asgiref-3.11.1.tar.gz", hash = "sha256:5f184dc43b7e763efe848065441eac62229c9f7b0475f41f80e207a114eda4ce", size = 38550, upload-time = "2026-02-03T13:30:14.33Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/5c/0a/a72d10ed65068e115044937873362e6e32fab1b7dce0046aeb224682c989/asgiref-3.11.1-py3-none-any.whl", hash = "sha256:e8667a091e69529631969fd45dc268fa79b99c92c5fcdda727757e52146ec133", size = 24345, upload-time = "2026-02-03T13:30:13.039Z" },
]
[[package]]
name = "async-timeout"
version = "5.0.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" },
]
[[package]]
name = "blessed"
version = "1.30.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "jinxed", marker = "sys_platform == 'win32'" },
{ name = "wcwidth" },
]
sdist = { url = "https://files.pythonhosted.org/packages/dd/19/e926a0dbbf93c7aeb15d4dfff0d0e3de02653b3ba540b687307d0819c1ff/blessed-1.30.0.tar.gz", hash = "sha256:4d547019d7b40fc5420ea2ba2bc180fdccc31d6715298e2b49ffa7b020d44667", size = 13948932, upload-time = "2026-02-06T19:40:23.541Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/64/b0/8d87c7c8015ce8d4b2c5ee7a82a1d955f10138322c4f0cb387d7d2c1b2e7/blessed-1.30.0-py3-none-any.whl", hash = "sha256:4061a9f10dd22798716c2548ba36385af6a29d856c897f367c6ccc927e0b3a5a", size = 98399, upload-time = "2026-02-06T19:40:20.815Z" },
]
[[package]]
name = "boto3"
version = "1.42.59"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "botocore" },
{ name = "jmespath" },
{ name = "s3transfer" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b0/4e/499cb52aaee9468c346bcc1158965e24e72b4e2a20052725b680e0ac949b/boto3-1.42.59.tar.gz", hash = "sha256:6c4a14a4eb37b58a9048901bdeefbe1c529638b73e8f55413319a25f010ca211", size = 112725, upload-time = "2026-02-27T20:25:33.228Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/17/c0/22d868b9408dc5a33935a72896ec8d638b2766c459668d1b37c3e5ac2066/boto3-1.42.59-py3-none-any.whl", hash = "sha256:7a66e3e8e2087ea4403e135e9de592e6d63fc9a91080d8dac415bb74df873a72", size = 140557, upload-time = "2026-02-27T20:25:31.774Z" },
]
[[package]]
name = "botocore"
version = "1.42.59"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "jmespath" },
{ name = "python-dateutil" },
{ name = "urllib3" },
]
sdist = { url = "https://files.pythonhosted.org/packages/45/ae/50fb33bdf1911c216d50f98d989dd032a506f054cf829ebd737c6fa7e3e6/botocore-1.42.59.tar.gz", hash = "sha256:5314f19e1da8fc0ebc41bdb8bbe17c9a7397d87f4d887076ac8bdef972a34138", size = 14950271, upload-time = "2026-02-27T20:25:20.614Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/59/df/9d52819e0d804ead073d53ab1823bc0f0cb172a250fba31107b0b43fbb04/botocore-1.42.59-py3-none-any.whl", hash = "sha256:d2f2ff7ecc31e86ef46b5daee112cfbca052c13801285fb23af909f7bff5b657", size = 14619293, upload-time = "2026-02-27T20:25:17.455Z" },
]
[[package]]
name = "certifi"
version = "2026.2.25"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7", size = 155029, upload-time = "2026-02-25T02:54:17.342Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" },
]
[[package]]
name = "charset-normalizer"
version = "3.4.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1f/b8/6d51fc1d52cbd52cd4ccedd5b5b2f0f6a11bbf6765c782298b0f3e808541/charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d", size = 209709, upload-time = "2025-10-14T04:40:11.385Z" },
{ url = "https://files.pythonhosted.org/packages/5c/af/1f9d7f7faafe2ddfb6f72a2e07a548a629c61ad510fe60f9630309908fef/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8", size = 148814, upload-time = "2025-10-14T04:40:13.135Z" },
{ url = "https://files.pythonhosted.org/packages/79/3d/f2e3ac2bbc056ca0c204298ea4e3d9db9b4afe437812638759db2c976b5f/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad", size = 144467, upload-time = "2025-10-14T04:40:14.728Z" },
{ url = "https://files.pythonhosted.org/packages/ec/85/1bf997003815e60d57de7bd972c57dc6950446a3e4ccac43bc3070721856/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8", size = 162280, upload-time = "2025-10-14T04:40:16.14Z" },
{ url = "https://files.pythonhosted.org/packages/3e/8e/6aa1952f56b192f54921c436b87f2aaf7c7a7c3d0d1a765547d64fd83c13/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d", size = 159454, upload-time = "2025-10-14T04:40:17.567Z" },
{ url = "https://files.pythonhosted.org/packages/36/3b/60cbd1f8e93aa25d1c669c649b7a655b0b5fb4c571858910ea9332678558/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313", size = 153609, upload-time = "2025-10-14T04:40:19.08Z" },
{ url = "https://files.pythonhosted.org/packages/64/91/6a13396948b8fd3c4b4fd5bc74d045f5637d78c9675585e8e9fbe5636554/charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e", size = 151849, upload-time = "2025-10-14T04:40:20.607Z" },
{ url = "https://files.pythonhosted.org/packages/b7/7a/59482e28b9981d105691e968c544cc0df3b7d6133152fb3dcdc8f135da7a/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93", size = 151586, upload-time = "2025-10-14T04:40:21.719Z" },
{ url = "https://files.pythonhosted.org/packages/92/59/f64ef6a1c4bdd2baf892b04cd78792ed8684fbc48d4c2afe467d96b4df57/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0", size = 145290, upload-time = "2025-10-14T04:40:23.069Z" },
{ url = "https://files.pythonhosted.org/packages/6b/63/3bf9f279ddfa641ffa1962b0db6a57a9c294361cc2f5fcac997049a00e9c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84", size = 163663, upload-time = "2025-10-14T04:40:24.17Z" },
{ url = "https://files.pythonhosted.org/packages/ed/09/c9e38fc8fa9e0849b172b581fd9803bdf6e694041127933934184e19f8c3/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e", size = 151964, upload-time = "2025-10-14T04:40:25.368Z" },
{ url = "https://files.pythonhosted.org/packages/d2/d1/d28b747e512d0da79d8b6a1ac18b7ab2ecfd81b2944c4c710e166d8dd09c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db", size = 161064, upload-time = "2025-10-14T04:40:26.806Z" },
{ url = "https://files.pythonhosted.org/packages/bb/9a/31d62b611d901c3b9e5500c36aab0ff5eb442043fb3a1c254200d3d397d9/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6", size = 155015, upload-time = "2025-10-14T04:40:28.284Z" },
{ url = "https://files.pythonhosted.org/packages/1f/f3/107e008fa2bff0c8b9319584174418e5e5285fef32f79d8ee6a430d0039c/charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f", size = 99792, upload-time = "2025-10-14T04:40:29.613Z" },
{ url = "https://files.pythonhosted.org/packages/eb/66/e396e8a408843337d7315bab30dbf106c38966f1819f123257f5520f8a96/charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d", size = 107198, upload-time = "2025-10-14T04:40:30.644Z" },
{ url = "https://files.pythonhosted.org/packages/b5/58/01b4f815bf0312704c267f2ccb6e5d42bcc7752340cd487bc9f8c3710597/charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69", size = 100262, upload-time = "2025-10-14T04:40:32.108Z" },
{ url = "https://files.pythonhosted.org/packages/ed/27/c6491ff4954e58a10f69ad90aca8a1b6fe9c5d3c6f380907af3c37435b59/charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8", size = 206988, upload-time = "2025-10-14T04:40:33.79Z" },
{ url = "https://files.pythonhosted.org/packages/94/59/2e87300fe67ab820b5428580a53cad894272dbb97f38a7a814a2a1ac1011/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0", size = 147324, upload-time = "2025-10-14T04:40:34.961Z" },
{ url = "https://files.pythonhosted.org/packages/07/fb/0cf61dc84b2b088391830f6274cb57c82e4da8bbc2efeac8c025edb88772/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3", size = 142742, upload-time = "2025-10-14T04:40:36.105Z" },
{ url = "https://files.pythonhosted.org/packages/62/8b/171935adf2312cd745d290ed93cf16cf0dfe320863ab7cbeeae1dcd6535f/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc", size = 160863, upload-time = "2025-10-14T04:40:37.188Z" },
{ url = "https://files.pythonhosted.org/packages/09/73/ad875b192bda14f2173bfc1bc9a55e009808484a4b256748d931b6948442/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897", size = 157837, upload-time = "2025-10-14T04:40:38.435Z" },
{ url = "https://files.pythonhosted.org/packages/6d/fc/de9cce525b2c5b94b47c70a4b4fb19f871b24995c728e957ee68ab1671ea/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381", size = 151550, upload-time = "2025-10-14T04:40:40.053Z" },
{ url = "https://files.pythonhosted.org/packages/55/c2/43edd615fdfba8c6f2dfbd459b25a6b3b551f24ea21981e23fb768503ce1/charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815", size = 149162, upload-time = "2025-10-14T04:40:41.163Z" },
{ url = "https://files.pythonhosted.org/packages/03/86/bde4ad8b4d0e9429a4e82c1e8f5c659993a9a863ad62c7df05cf7b678d75/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0", size = 150019, upload-time = "2025-10-14T04:40:42.276Z" },
{ url = "https://files.pythonhosted.org/packages/1f/86/a151eb2af293a7e7bac3a739b81072585ce36ccfb4493039f49f1d3cae8c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161", size = 143310, upload-time = "2025-10-14T04:40:43.439Z" },
{ url = "https://files.pythonhosted.org/packages/b5/fe/43dae6144a7e07b87478fdfc4dbe9efd5defb0e7ec29f5f58a55aeef7bf7/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4", size = 162022, upload-time = "2025-10-14T04:40:44.547Z" },
{ url = "https://files.pythonhosted.org/packages/80/e6/7aab83774f5d2bca81f42ac58d04caf44f0cc2b65fc6db2b3b2e8a05f3b3/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89", size = 149383, upload-time = "2025-10-14T04:40:46.018Z" },
{ url = "https://files.pythonhosted.org/packages/4f/e8/b289173b4edae05c0dde07f69f8db476a0b511eac556dfe0d6bda3c43384/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569", size = 159098, upload-time = "2025-10-14T04:40:47.081Z" },
{ url = "https://files.pythonhosted.org/packages/d8/df/fe699727754cae3f8478493c7f45f777b17c3ef0600e28abfec8619eb49c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224", size = 152991, upload-time = "2025-10-14T04:40:48.246Z" },
{ url = "https://files.pythonhosted.org/packages/1a/86/584869fe4ddb6ffa3bd9f491b87a01568797fb9bd8933f557dba9771beaf/charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a", size = 99456, upload-time = "2025-10-14T04:40:49.376Z" },
{ url = "https://files.pythonhosted.org/packages/65/f6/62fdd5feb60530f50f7e38b4f6a1d5203f4d16ff4f9f0952962c044e919a/charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016", size = 106978, upload-time = "2025-10-14T04:40:50.844Z" },
{ url = "https://files.pythonhosted.org/packages/7a/9d/0710916e6c82948b3be62d9d398cb4fcf4e97b56d6a6aeccd66c4b2f2bd5/charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1", size = 99969, upload-time = "2025-10-14T04:40:52.272Z" },
{ url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" },
{ url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" },
{ url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" },
{ url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" },
{ url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" },
{ url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" },
{ url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" },
{ url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" },
{ url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" },
{ url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" },
{ url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" },
{ url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" },
{ url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" },
{ url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" },
{ url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" },
{ url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" },
{ url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" },
{ url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" },
{ url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" },
{ url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" },
{ url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" },
{ url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" },
{ url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" },
{ url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" },
{ url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" },
{ url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" },
{ url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" },
{ url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" },
{ url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" },
{ url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" },
{ url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" },
{ url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" },
{ url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" },
{ url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" },
{ url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" },
{ url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" },
{ url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" },
{ url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" },
{ url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" },
{ url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" },
{ url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" },
{ url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" },
{ url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" },
{ url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" },
{ url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" },
{ url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" },
{ url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" },
{ url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" },
{ url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" },
]
[[package]]
name = "colorama"
version = "0.4.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
]
[[package]]
name = "coverage"
version = "7.13.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/24/56/95b7e30fa389756cb56630faa728da46a27b8c6eb46f9d557c68fff12b65/coverage-7.13.4.tar.gz", hash = "sha256:e5c8f6ed1e61a8b2dcdf31eb0b9bbf0130750ca79c1c49eb898e2ad86f5ccc91", size = 827239, upload-time = "2026-02-09T12:59:03.86Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/44/d4/7827d9ffa34d5d4d752eec907022aa417120936282fc488306f5da08c292/coverage-7.13.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0fc31c787a84f8cd6027eba44010517020e0d18487064cd3d8968941856d1415", size = 219152, upload-time = "2026-02-09T12:56:11.974Z" },
{ url = "https://files.pythonhosted.org/packages/35/b0/d69df26607c64043292644dbb9dc54b0856fabaa2cbb1eeee3331cc9e280/coverage-7.13.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a32ebc02a1805adf637fc8dec324b5cdacd2e493515424f70ee33799573d661b", size = 219667, upload-time = "2026-02-09T12:56:13.33Z" },
{ url = "https://files.pythonhosted.org/packages/82/a4/c1523f7c9e47b2271dbf8c2a097e7a1f89ef0d66f5840bb59b7e8814157b/coverage-7.13.4-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e24f9156097ff9dc286f2f913df3a7f63c0e333dcafa3c196f2c18b4175ca09a", size = 246425, upload-time = "2026-02-09T12:56:14.552Z" },
{ url = "https://files.pythonhosted.org/packages/f8/02/aa7ec01d1a5023c4b680ab7257f9bfde9defe8fdddfe40be096ac19e8177/coverage-7.13.4-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8041b6c5bfdc03257666e9881d33b1abc88daccaf73f7b6340fb7946655cd10f", size = 248229, upload-time = "2026-02-09T12:56:16.31Z" },
{ url = "https://files.pythonhosted.org/packages/35/98/85aba0aed5126d896162087ef3f0e789a225697245256fc6181b95f47207/coverage-7.13.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a09cfa6a5862bc2fc6ca7c3def5b2926194a56b8ab78ffcf617d28911123012", size = 250106, upload-time = "2026-02-09T12:56:18.024Z" },
{ url = "https://files.pythonhosted.org/packages/96/72/1db59bd67494bc162e3e4cd5fbc7edba2c7026b22f7c8ef1496d58c2b94c/coverage-7.13.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:296f8b0af861d3970c2a4d8c91d48eb4dd4771bcef9baedec6a9b515d7de3def", size = 252021, upload-time = "2026-02-09T12:56:19.272Z" },
{ url = "https://files.pythonhosted.org/packages/9d/97/72899c59c7066961de6e3daa142d459d47d104956db43e057e034f015c8a/coverage-7.13.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e101609bcbbfb04605ea1027b10dc3735c094d12d40826a60f897b98b1c30256", size = 247114, upload-time = "2026-02-09T12:56:21.051Z" },
{ url = "https://files.pythonhosted.org/packages/39/1f/f1885573b5970235e908da4389176936c8933e86cb316b9620aab1585fa2/coverage-7.13.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aa3feb8db2e87ff5e6d00d7e1480ae241876286691265657b500886c98f38bda", size = 248143, upload-time = "2026-02-09T12:56:22.585Z" },
{ url = "https://files.pythonhosted.org/packages/a8/cf/e80390c5b7480b722fa3e994f8202807799b85bc562aa4f1dde209fbb7be/coverage-7.13.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4fc7fa81bbaf5a02801b65346c8b3e657f1d93763e58c0abdf7c992addd81a92", size = 246152, upload-time = "2026-02-09T12:56:23.748Z" },
{ url = "https://files.pythonhosted.org/packages/44/bf/f89a8350d85572f95412debb0fb9bb4795b1d5b5232bd652923c759e787b/coverage-7.13.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:33901f604424145c6e9c2398684b92e176c0b12df77d52db81c20abd48c3794c", size = 249959, upload-time = "2026-02-09T12:56:25.209Z" },
{ url = "https://files.pythonhosted.org/packages/f7/6e/612a02aece8178c818df273e8d1642190c4875402ca2ba74514394b27aba/coverage-7.13.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:bb28c0f2cf2782508a40cec377935829d5fcc3ad9a3681375af4e84eb34b6b58", size = 246416, upload-time = "2026-02-09T12:56:26.475Z" },
{ url = "https://files.pythonhosted.org/packages/cb/98/b5afc39af67c2fa6786b03c3a7091fc300947387ce8914b096db8a73d67a/coverage-7.13.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9d107aff57a83222ddbd8d9ee705ede2af2cc926608b57abed8ef96b50b7e8f9", size = 247025, upload-time = "2026-02-09T12:56:27.727Z" },
{ url = "https://files.pythonhosted.org/packages/51/30/2bba8ef0682d5bd210c38fe497e12a06c9f8d663f7025e9f5c2c31ce847d/coverage-7.13.4-cp310-cp310-win32.whl", hash = "sha256:a6f94a7d00eb18f1b6d403c91a88fd58cfc92d4b16080dfdb774afc8294469bf", size = 221758, upload-time = "2026-02-09T12:56:29.051Z" },
{ url = "https://files.pythonhosted.org/packages/78/13/331f94934cf6c092b8ea59ff868eb587bc8fe0893f02c55bc6c0183a192e/coverage-7.13.4-cp310-cp310-win_amd64.whl", hash = "sha256:2cb0f1e000ebc419632bbe04366a8990b6e32c4e0b51543a6484ffe15eaeda95", size = 222693, upload-time = "2026-02-09T12:56:30.366Z" },
{ url = "https://files.pythonhosted.org/packages/b4/ad/b59e5b451cf7172b8d1043dc0fa718f23aab379bc1521ee13d4bd9bfa960/coverage-7.13.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d490ba50c3f35dd7c17953c68f3270e7ccd1c6642e2d2afe2d8e720b98f5a053", size = 219278, upload-time = "2026-02-09T12:56:31.673Z" },
{ url = "https://files.pythonhosted.org/packages/f1/17/0cb7ca3de72e5f4ef2ec2fa0089beafbcaaaead1844e8b8a63d35173d77d/coverage-7.13.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:19bc3c88078789f8ef36acb014d7241961dbf883fd2533d18cb1e7a5b4e28b11", size = 219783, upload-time = "2026-02-09T12:56:33.104Z" },
{ url = "https://files.pythonhosted.org/packages/ab/63/325d8e5b11e0eaf6d0f6a44fad444ae58820929a9b0de943fa377fe73e85/coverage-7.13.4-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3998e5a32e62fdf410c0dbd3115df86297995d6e3429af80b8798aad894ca7aa", size = 250200, upload-time = "2026-02-09T12:56:34.474Z" },
{ url = "https://files.pythonhosted.org/packages/76/53/c16972708cbb79f2942922571a687c52bd109a7bd51175aeb7558dff2236/coverage-7.13.4-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8e264226ec98e01a8e1054314af91ee6cde0eacac4f465cc93b03dbe0bce2fd7", size = 252114, upload-time = "2026-02-09T12:56:35.749Z" },
{ url = "https://files.pythonhosted.org/packages/eb/c2/7ab36d8b8cc412bec9ea2d07c83c48930eb4ba649634ba00cb7e4e0f9017/coverage-7.13.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a3aa4e7b9e416774b21797365b358a6e827ffadaaca81b69ee02946852449f00", size = 254220, upload-time = "2026-02-09T12:56:37.796Z" },
{ url = "https://files.pythonhosted.org/packages/d6/4d/cf52c9a3322c89a0e6febdfbc83bb45c0ed3c64ad14081b9503adee702e7/coverage-7.13.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:71ca20079dd8f27fcf808817e281e90220475cd75115162218d0e27549f95fef", size = 256164, upload-time = "2026-02-09T12:56:39.016Z" },
{ url = "https://files.pythonhosted.org/packages/78/e9/eb1dd17bd6de8289df3580e967e78294f352a5df8a57ff4671ee5fc3dcd0/coverage-7.13.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e2f25215f1a359ab17320b47bcdaca3e6e6356652e8256f2441e4ef972052903", size = 250325, upload-time = "2026-02-09T12:56:40.668Z" },
{ url = "https://files.pythonhosted.org/packages/71/07/8c1542aa873728f72267c07278c5cc0ec91356daf974df21335ccdb46368/coverage-7.13.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d65b2d373032411e86960604dc4edac91fdfb5dca539461cf2cbe78327d1e64f", size = 251913, upload-time = "2026-02-09T12:56:41.97Z" },
{ url = "https://files.pythonhosted.org/packages/74/d7/c62e2c5e4483a748e27868e4c32ad3daa9bdddbba58e1bc7a15e252baa74/coverage-7.13.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94eb63f9b363180aff17de3e7c8760c3ba94664ea2695c52f10111244d16a299", size = 249974, upload-time = "2026-02-09T12:56:43.323Z" },
{ url = "https://files.pythonhosted.org/packages/98/9f/4c5c015a6e98ced54efd0f5cf8d31b88e5504ecb6857585fc0161bb1e600/coverage-7.13.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e856bf6616714c3a9fbc270ab54103f4e685ba236fa98c054e8f87f266c93505", size = 253741, upload-time = "2026-02-09T12:56:45.155Z" },
{ url = "https://files.pythonhosted.org/packages/bd/59/0f4eef89b9f0fcd9633b5d350016f54126ab49426a70ff4c4e87446cabdc/coverage-7.13.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:65dfcbe305c3dfe658492df2d85259e0d79ead4177f9ae724b6fb245198f55d6", size = 249695, upload-time = "2026-02-09T12:56:46.636Z" },
{ url = "https://files.pythonhosted.org/packages/b5/2c/b7476f938deb07166f3eb281a385c262675d688ff4659ad56c6c6b8e2e70/coverage-7.13.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b507778ae8a4c915436ed5c2e05b4a6cecfa70f734e19c22a005152a11c7b6a9", size = 250599, upload-time = "2026-02-09T12:56:48.13Z" },
{ url = "https://files.pythonhosted.org/packages/b8/34/c3420709d9846ee3785b9f2831b4d94f276f38884032dca1457fa83f7476/coverage-7.13.4-cp311-cp311-win32.whl", hash = "sha256:784fc3cf8be001197b652d51d3fd259b1e2262888693a4636e18879f613a62a9", size = 221780, upload-time = "2026-02-09T12:56:50.479Z" },
{ url = "https://files.pythonhosted.org/packages/61/08/3d9c8613079d2b11c185b865de9a4c1a68850cfda2b357fae365cf609f29/coverage-7.13.4-cp311-cp311-win_amd64.whl", hash = "sha256:2421d591f8ca05b308cf0092807308b2facbefe54af7c02ac22548b88b95c98f", size = 222715, upload-time = "2026-02-09T12:56:51.815Z" },
{ url = "https://files.pythonhosted.org/packages/18/1a/54c3c80b2f056164cc0a6cdcb040733760c7c4be9d780fe655f356f433e4/coverage-7.13.4-cp311-cp311-win_arm64.whl", hash = "sha256:79e73a76b854d9c6088fe5d8b2ebe745f8681c55f7397c3c0a016192d681045f", size = 221385, upload-time = "2026-02-09T12:56:53.194Z" },
{ url = "https://files.pythonhosted.org/packages/d1/81/4ce2fdd909c5a0ed1f6dedb88aa57ab79b6d1fbd9b588c1ac7ef45659566/coverage-7.13.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:02231499b08dabbe2b96612993e5fc34217cdae907a51b906ac7fca8027a4459", size = 219449, upload-time = "2026-02-09T12:56:54.889Z" },
{ url = "https://files.pythonhosted.org/packages/5d/96/5238b1efc5922ddbdc9b0db9243152c09777804fb7c02ad1741eb18a11c0/coverage-7.13.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40aa8808140e55dc022b15d8aa7f651b6b3d68b365ea0398f1441e0b04d859c3", size = 219810, upload-time = "2026-02-09T12:56:56.33Z" },
{ url = "https://files.pythonhosted.org/packages/78/72/2f372b726d433c9c35e56377cf1d513b4c16fe51841060d826b95caacec1/coverage-7.13.4-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5b856a8ccf749480024ff3bd7310adaef57bf31fd17e1bfc404b7940b6986634", size = 251308, upload-time = "2026-02-09T12:56:57.858Z" },
{ url = "https://files.pythonhosted.org/packages/5d/a0/2ea570925524ef4e00bb6c82649f5682a77fac5ab910a65c9284de422600/coverage-7.13.4-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2c048ea43875fbf8b45d476ad79f179809c590ec7b79e2035c662e7afa3192e3", size = 254052, upload-time = "2026-02-09T12:56:59.754Z" },
{ url = "https://files.pythonhosted.org/packages/e8/ac/45dc2e19a1939098d783c846e130b8f862fbb50d09e0af663988f2f21973/coverage-7.13.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b7b38448866e83176e28086674fe7368ab8590e4610fb662b44e345b86d63ffa", size = 255165, upload-time = "2026-02-09T12:57:01.287Z" },
{ url = "https://files.pythonhosted.org/packages/2d/4d/26d236ff35abc3b5e63540d3386e4c3b192168c1d96da5cb2f43c640970f/coverage-7.13.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:de6defc1c9badbf8b9e67ae90fd00519186d6ab64e5cc5f3d21359c2a9b2c1d3", size = 257432, upload-time = "2026-02-09T12:57:02.637Z" },
{ url = "https://files.pythonhosted.org/packages/ec/55/14a966c757d1348b2e19caf699415a2a4c4f7feaa4bbc6326a51f5c7dd1b/coverage-7.13.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7eda778067ad7ffccd23ecffce537dface96212576a07924cbf0d8799d2ded5a", size = 251716, upload-time = "2026-02-09T12:57:04.056Z" },
{ url = "https://files.pythonhosted.org/packages/77/33/50116647905837c66d28b2af1321b845d5f5d19be9655cb84d4a0ea806b4/coverage-7.13.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e87f6c587c3f34356c3759f0420693e35e7eb0e2e41e4c011cb6ec6ecbbf1db7", size = 253089, upload-time = "2026-02-09T12:57:05.503Z" },
{ url = "https://files.pythonhosted.org/packages/c2/b4/8efb11a46e3665d92635a56e4f2d4529de6d33f2cb38afd47d779d15fc99/coverage-7.13.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8248977c2e33aecb2ced42fef99f2d319e9904a36e55a8a68b69207fb7e43edc", size = 251232, upload-time = "2026-02-09T12:57:06.879Z" },
{ url = "https://files.pythonhosted.org/packages/51/24/8cd73dd399b812cc76bb0ac260e671c4163093441847ffe058ac9fda1e32/coverage-7.13.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:25381386e80ae727608e662474db537d4df1ecd42379b5ba33c84633a2b36d47", size = 255299, upload-time = "2026-02-09T12:57:08.245Z" },
{ url = "https://files.pythonhosted.org/packages/03/94/0a4b12f1d0e029ce1ccc1c800944a9984cbe7d678e470bb6d3c6bc38a0da/coverage-7.13.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:ee756f00726693e5ba94d6df2bdfd64d4852d23b09bb0bc700e3b30e6f333985", size = 250796, upload-time = "2026-02-09T12:57:10.142Z" },
{ url = "https://files.pythonhosted.org/packages/73/44/6002fbf88f6698ca034360ce474c406be6d5a985b3fdb3401128031eef6b/coverage-7.13.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fdfc1e28e7c7cdce44985b3043bc13bbd9c747520f94a4d7164af8260b3d91f0", size = 252673, upload-time = "2026-02-09T12:57:12.197Z" },
{ url = "https://files.pythonhosted.org/packages/de/c6/a0279f7c00e786be75a749a5674e6fa267bcbd8209cd10c9a450c655dfa7/coverage-7.13.4-cp312-cp312-win32.whl", hash = "sha256:01d4cbc3c283a17fc1e42d614a119f7f438eabb593391283adca8dc86eff1246", size = 221990, upload-time = "2026-02-09T12:57:14.085Z" },
{ url = "https://files.pythonhosted.org/packages/77/4e/c0a25a425fcf5557d9abd18419c95b63922e897bc86c1f327f155ef234a9/coverage-7.13.4-cp312-cp312-win_amd64.whl", hash = "sha256:9401ebc7ef522f01d01d45532c68c5ac40fb27113019b6b7d8b208f6e9baa126", size = 222800, upload-time = "2026-02-09T12:57:15.944Z" },
{ url = "https://files.pythonhosted.org/packages/47/ac/92da44ad9a6f4e3a7debd178949d6f3769bedca33830ce9b1dcdab589a37/coverage-7.13.4-cp312-cp312-win_arm64.whl", hash = "sha256:b1ec7b6b6e93255f952e27ab58fbc68dcc468844b16ecbee881aeb29b6ab4d8d", size = 221415, upload-time = "2026-02-09T12:57:17.497Z" },
{ url = "https://files.pythonhosted.org/packages/db/23/aad45061a31677d68e47499197a131eea55da4875d16c1f42021ab963503/coverage-7.13.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b66a2da594b6068b48b2692f043f35d4d3693fb639d5ea8b39533c2ad9ac3ab9", size = 219474, upload-time = "2026-02-09T12:57:19.332Z" },
{ url = "https://files.pythonhosted.org/packages/a5/70/9b8b67a0945f3dfec1fd896c5cefb7c19d5a3a6d74630b99a895170999ae/coverage-7.13.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3599eb3992d814d23b35c536c28df1a882caa950f8f507cef23d1cbf334995ac", size = 219844, upload-time = "2026-02-09T12:57:20.66Z" },
{ url = "https://files.pythonhosted.org/packages/97/fd/7e859f8fab324cef6c4ad7cff156ca7c489fef9179d5749b0c8d321281c2/coverage-7.13.4-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:93550784d9281e374fb5a12bf1324cc8a963fd63b2d2f223503ef0fd4aa339ea", size = 250832, upload-time = "2026-02-09T12:57:22.007Z" },
{ url = "https://files.pythonhosted.org/packages/e4/dc/b2442d10020c2f52617828862d8b6ee337859cd8f3a1f13d607dddda9cf7/coverage-7.13.4-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b720ce6a88a2755f7c697c23268ddc47a571b88052e6b155224347389fdf6a3b", size = 253434, upload-time = "2026-02-09T12:57:23.339Z" },
{ url = "https://files.pythonhosted.org/packages/5a/88/6728a7ad17428b18d836540630487231f5470fb82454871149502f5e5aa2/coverage-7.13.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7b322db1284a2ed3aa28ffd8ebe3db91c929b7a333c0820abec3d838ef5b3525", size = 254676, upload-time = "2026-02-09T12:57:24.774Z" },
{ url = "https://files.pythonhosted.org/packages/7c/bc/21244b1b8cedf0dff0a2b53b208015fe798d5f2a8d5348dbfece04224fff/coverage-7.13.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f4594c67d8a7c89cf922d9df0438c7c7bb022ad506eddb0fdb2863359ff78242", size = 256807, upload-time = "2026-02-09T12:57:26.125Z" },
{ url = "https://files.pythonhosted.org/packages/97/a0/ddba7ed3251cff51006737a727d84e05b61517d1784a9988a846ba508877/coverage-7.13.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:53d133df809c743eb8bce33b24bcababb371f4441340578cd406e084d94a6148", size = 251058, upload-time = "2026-02-09T12:57:27.614Z" },
{ url = "https://files.pythonhosted.org/packages/9b/55/e289addf7ff54d3a540526f33751951bf0878f3809b47f6dfb3def69c6f7/coverage-7.13.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:76451d1978b95ba6507a039090ba076105c87cc76fc3efd5d35d72093964d49a", size = 252805, upload-time = "2026-02-09T12:57:29.066Z" },
{ url = "https://files.pythonhosted.org/packages/13/4e/cc276b1fa4a59be56d96f1dabddbdc30f4ba22e3b1cd42504c37b3313255/coverage-7.13.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7f57b33491e281e962021de110b451ab8a24182589be17e12a22c79047935e23", size = 250766, upload-time = "2026-02-09T12:57:30.522Z" },
{ url = "https://files.pythonhosted.org/packages/94/44/1093b8f93018f8b41a8cf29636c9292502f05e4a113d4d107d14a3acd044/coverage-7.13.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1731dc33dc276dafc410a885cbf5992f1ff171393e48a21453b78727d090de80", size = 254923, upload-time = "2026-02-09T12:57:31.946Z" },
{ url = "https://files.pythonhosted.org/packages/8b/55/ea2796da2d42257f37dbea1aab239ba9263b31bd91d5527cdd6db5efe174/coverage-7.13.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:bd60d4fe2f6fa7dff9223ca1bbc9f05d2b6697bc5961072e5d3b952d46e1b1ea", size = 250591, upload-time = "2026-02-09T12:57:33.842Z" },
{ url = "https://files.pythonhosted.org/packages/d4/fa/7c4bb72aacf8af5020675aa633e59c1fbe296d22aed191b6a5b711eb2bc7/coverage-7.13.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9181a3ccead280b828fae232df12b16652702b49d41e99d657f46cc7b1f6ec7a", size = 252364, upload-time = "2026-02-09T12:57:35.743Z" },
{ url = "https://files.pythonhosted.org/packages/5c/38/a8d2ec0146479c20bbaa7181b5b455a0c41101eed57f10dd19a78ab44c80/coverage-7.13.4-cp313-cp313-win32.whl", hash = "sha256:f53d492307962561ac7de4cd1de3e363589b000ab69617c6156a16ba7237998d", size = 222010, upload-time = "2026-02-09T12:57:37.25Z" },
{ url = "https://files.pythonhosted.org/packages/e2/0c/dbfafbe90a185943dcfbc766fe0e1909f658811492d79b741523a414a6cc/coverage-7.13.4-cp313-cp313-win_amd64.whl", hash = "sha256:e6f70dec1cc557e52df5306d051ef56003f74d56e9c4dd7ddb07e07ef32a84dd", size = 222818, upload-time = "2026-02-09T12:57:38.734Z" },
{ url = "https://files.pythonhosted.org/packages/04/d1/934918a138c932c90d78301f45f677fb05c39a3112b96fd2c8e60503cdc7/coverage-7.13.4-cp313-cp313-win_arm64.whl", hash = "sha256:fb07dc5da7e849e2ad31a5d74e9bece81f30ecf5a42909d0a695f8bd1874d6af", size = 221438, upload-time = "2026-02-09T12:57:40.223Z" },
{ url = "https://files.pythonhosted.org/packages/52/57/ee93ced533bcb3e6df961c0c6e42da2fc6addae53fb95b94a89b1e33ebd7/coverage-7.13.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:40d74da8e6c4b9ac18b15331c4b5ebc35a17069410cad462ad4f40dcd2d50c0d", size = 220165, upload-time = "2026-02-09T12:57:41.639Z" },
{ url = "https://files.pythonhosted.org/packages/c5/e0/969fc285a6fbdda49d91af278488d904dcd7651b2693872f0ff94e40e84a/coverage-7.13.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4223b4230a376138939a9173f1bdd6521994f2aff8047fae100d6d94d50c5a12", size = 220516, upload-time = "2026-02-09T12:57:44.215Z" },
{ url = "https://files.pythonhosted.org/packages/b1/b8/9531944e16267e2735a30a9641ff49671f07e8138ecf1ca13db9fd2560c7/coverage-7.13.4-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1d4be36a5114c499f9f1f9195e95ebf979460dbe2d88e6816ea202010ba1c34b", size = 261804, upload-time = "2026-02-09T12:57:45.989Z" },
{ url = "https://files.pythonhosted.org/packages/8a/f3/e63df6d500314a2a60390d1989240d5f27318a7a68fa30ad3806e2a9323e/coverage-7.13.4-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:200dea7d1e8095cc6e98cdabe3fd1d21ab17d3cee6dab00cadbb2fe35d9c15b9", size = 263885, upload-time = "2026-02-09T12:57:47.42Z" },
{ url = "https://files.pythonhosted.org/packages/f3/67/7654810de580e14b37670b60a09c599fa348e48312db5b216d730857ffe6/coverage-7.13.4-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8eb931ee8e6d8243e253e5ed7336deea6904369d2fd8ae6e43f68abbf167092", size = 266308, upload-time = "2026-02-09T12:57:49.345Z" },
{ url = "https://files.pythonhosted.org/packages/37/6f/39d41eca0eab3cc82115953ad41c4e77935286c930e8fad15eaed1389d83/coverage-7.13.4-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:75eab1ebe4f2f64d9509b984f9314d4aa788540368218b858dad56dc8f3e5eb9", size = 267452, upload-time = "2026-02-09T12:57:50.811Z" },
{ url = "https://files.pythonhosted.org/packages/50/6d/39c0fbb8fc5cd4d2090811e553c2108cf5112e882f82505ee7495349a6bf/coverage-7.13.4-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c35eb28c1d085eb7d8c9b3296567a1bebe03ce72962e932431b9a61f28facf26", size = 261057, upload-time = "2026-02-09T12:57:52.447Z" },
{ url = "https://files.pythonhosted.org/packages/a4/a2/60010c669df5fa603bb5a97fb75407e191a846510da70ac657eb696b7fce/coverage-7.13.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb88b316ec33760714a4720feb2816a3a59180fd58c1985012054fa7aebee4c2", size = 263875, upload-time = "2026-02-09T12:57:53.938Z" },
{ url = "https://files.pythonhosted.org/packages/3e/d9/63b22a6bdbd17f1f96e9ed58604c2a6b0e72a9133e37d663bef185877cf6/coverage-7.13.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7d41eead3cc673cbd38a4417deb7fd0b4ca26954ff7dc6078e33f6ff97bed940", size = 261500, upload-time = "2026-02-09T12:57:56.012Z" },
{ url = "https://files.pythonhosted.org/packages/70/bf/69f86ba1ad85bc3ad240e4c0e57a2e620fbc0e1645a47b5c62f0e941ad7f/coverage-7.13.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:fb26a934946a6afe0e326aebe0730cdff393a8bc0bbb65a2f41e30feddca399c", size = 265212, upload-time = "2026-02-09T12:57:57.5Z" },
{ url = "https://files.pythonhosted.org/packages/ae/f2/5f65a278a8c2148731831574c73e42f57204243d33bedaaf18fa79c5958f/coverage-7.13.4-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:dae88bc0fc77edaa65c14be099bd57ee140cf507e6bfdeea7938457ab387efb0", size = 260398, upload-time = "2026-02-09T12:57:59.027Z" },
{ url = "https://files.pythonhosted.org/packages/ef/80/6e8280a350ee9fea92f14b8357448a242dcaa243cb2c72ab0ca591f66c8c/coverage-7.13.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:845f352911777a8e722bfce168958214951e07e47e5d5d9744109fa5fe77f79b", size = 262584, upload-time = "2026-02-09T12:58:01.129Z" },
{ url = "https://files.pythonhosted.org/packages/22/63/01ff182fc95f260b539590fb12c11ad3e21332c15f9799cb5e2386f71d9f/coverage-7.13.4-cp313-cp313t-win32.whl", hash = "sha256:2fa8d5f8de70688a28240de9e139fa16b153cc3cbb01c5f16d88d6505ebdadf9", size = 222688, upload-time = "2026-02-09T12:58:02.736Z" },
{ url = "https://files.pythonhosted.org/packages/a9/43/89de4ef5d3cd53b886afa114065f7e9d3707bdb3e5efae13535b46ae483d/coverage-7.13.4-cp313-cp313t-win_amd64.whl", hash = "sha256:9351229c8c8407645840edcc277f4a2d44814d1bc34a2128c11c2a031d45a5dd", size = 223746, upload-time = "2026-02-09T12:58:05.362Z" },
{ url = "https://files.pythonhosted.org/packages/35/39/7cf0aa9a10d470a5309b38b289b9bb07ddeac5d61af9b664fe9775a4cb3e/coverage-7.13.4-cp313-cp313t-win_arm64.whl", hash = "sha256:30b8d0512f2dc8c8747557e8fb459d6176a2c9e5731e2b74d311c03b78451997", size = 222003, upload-time = "2026-02-09T12:58:06.952Z" },
{ url = "https://files.pythonhosted.org/packages/92/11/a9cf762bb83386467737d32187756a42094927150c3e107df4cb078e8590/coverage-7.13.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:300deaee342f90696ed186e3a00c71b5b3d27bffe9e827677954f4ee56969601", size = 219522, upload-time = "2026-02-09T12:58:08.623Z" },
{ url = "https://files.pythonhosted.org/packages/d3/28/56e6d892b7b052236d67c95f1936b6a7cf7c3e2634bf27610b8cbd7f9c60/coverage-7.13.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:29e3220258d682b6226a9b0925bc563ed9a1ebcff3cad30f043eceea7eaf2689", size = 219855, upload-time = "2026-02-09T12:58:10.176Z" },
{ url = "https://files.pythonhosted.org/packages/e5/69/233459ee9eb0c0d10fcc2fe425a029b3fa5ce0f040c966ebce851d030c70/coverage-7.13.4-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:391ee8f19bef69210978363ca930f7328081c6a0152f1166c91f0b5fdd2a773c", size = 250887, upload-time = "2026-02-09T12:58:12.503Z" },
{ url = "https://files.pythonhosted.org/packages/06/90/2cdab0974b9b5bbc1623f7876b73603aecac11b8d95b85b5b86b32de5eab/coverage-7.13.4-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0dd7ab8278f0d58a0128ba2fca25824321f05d059c1441800e934ff2efa52129", size = 253396, upload-time = "2026-02-09T12:58:14.615Z" },
{ url = "https://files.pythonhosted.org/packages/ac/15/ea4da0f85bf7d7b27635039e649e99deb8173fe551096ea15017f7053537/coverage-7.13.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78cdf0d578b15148b009ccf18c686aa4f719d887e76e6b40c38ffb61d264a552", size = 254745, upload-time = "2026-02-09T12:58:16.162Z" },
{ url = "https://files.pythonhosted.org/packages/99/11/bb356e86920c655ca4d61daee4e2bbc7258f0a37de0be32d233b561134ff/coverage-7.13.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:48685fee12c2eb3b27c62f2658e7ea21e9c3239cba5a8a242801a0a3f6a8c62a", size = 257055, upload-time = "2026-02-09T12:58:17.892Z" },
{ url = "https://files.pythonhosted.org/packages/c9/0f/9ae1f8cb17029e09da06ca4e28c9e1d5c1c0a511c7074592e37e0836c915/coverage-7.13.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4e83efc079eb39480e6346a15a1bcb3e9b04759c5202d157e1dd4303cd619356", size = 250911, upload-time = "2026-02-09T12:58:19.495Z" },
{ url = "https://files.pythonhosted.org/packages/89/3a/adfb68558fa815cbc29747b553bc833d2150228f251b127f1ce97e48547c/coverage-7.13.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ecae9737b72408d6a950f7e525f30aca12d4bd8dd95e37342e5beb3a2a8c4f71", size = 252754, upload-time = "2026-02-09T12:58:21.064Z" },
{ url = "https://files.pythonhosted.org/packages/32/b1/540d0c27c4e748bd3cd0bd001076ee416eda993c2bae47a73b7cc9357931/coverage-7.13.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ae4578f8528569d3cf303fef2ea569c7f4c4059a38c8667ccef15c6e1f118aa5", size = 250720, upload-time = "2026-02-09T12:58:22.622Z" },
{ url = "https://files.pythonhosted.org/packages/c7/95/383609462b3ffb1fe133014a7c84fc0dd01ed55ac6140fa1093b5af7ebb1/coverage-7.13.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:6fdef321fdfbb30a197efa02d48fcd9981f0d8ad2ae8903ac318adc653f5df98", size = 254994, upload-time = "2026-02-09T12:58:24.548Z" },
{ url = "https://files.pythonhosted.org/packages/f7/ba/1761138e86c81680bfc3c49579d66312865457f9fe405b033184e5793cb3/coverage-7.13.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b0f6ccf3dbe577170bebfce1318707d0e8c3650003cb4b3a9dd744575daa8b5", size = 250531, upload-time = "2026-02-09T12:58:26.271Z" },
{ url = "https://files.pythonhosted.org/packages/f8/8e/05900df797a9c11837ab59c4d6fe94094e029582aab75c3309a93e6fb4e3/coverage-7.13.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75fcd519f2a5765db3f0e391eb3b7d150cce1a771bf4c9f861aeab86c767a3c0", size = 252189, upload-time = "2026-02-09T12:58:27.807Z" },
{ url = "https://files.pythonhosted.org/packages/00/bd/29c9f2db9ea4ed2738b8a9508c35626eb205d51af4ab7bf56a21a2e49926/coverage-7.13.4-cp314-cp314-win32.whl", hash = "sha256:8e798c266c378da2bd819b0677df41ab46d78065fb2a399558f3f6cae78b2fbb", size = 222258, upload-time = "2026-02-09T12:58:29.441Z" },
{ url = "https://files.pythonhosted.org/packages/a7/4d/1f8e723f6829977410efeb88f73673d794075091c8c7c18848d273dc9d73/coverage-7.13.4-cp314-cp314-win_amd64.whl", hash = "sha256:245e37f664d89861cf2329c9afa2c1fe9e6d4e1a09d872c947e70718aeeac505", size = 223073, upload-time = "2026-02-09T12:58:31.026Z" },
{ url = "https://files.pythonhosted.org/packages/51/5b/84100025be913b44e082ea32abcf1afbf4e872f5120b7a1cab1d331b1e13/coverage-7.13.4-cp314-cp314-win_arm64.whl", hash = "sha256:ad27098a189e5838900ce4c2a99f2fe42a0bf0c2093c17c69b45a71579e8d4a2", size = 221638, upload-time = "2026-02-09T12:58:32.599Z" },
{ url = "https://files.pythonhosted.org/packages/a7/e4/c884a405d6ead1370433dad1e3720216b4f9fd8ef5b64bfd984a2a60a11a/coverage-7.13.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:85480adfb35ffc32d40918aad81b89c69c9cc5661a9b8a81476d3e645321a056", size = 220246, upload-time = "2026-02-09T12:58:34.181Z" },
{ url = "https://files.pythonhosted.org/packages/81/5c/4d7ed8b23b233b0fffbc9dfec53c232be2e695468523242ea9fd30f97ad2/coverage-7.13.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:79be69cf7f3bf9b0deeeb062eab7ac7f36cd4cc4c4dd694bd28921ba4d8596cc", size = 220514, upload-time = "2026-02-09T12:58:35.704Z" },
{ url = "https://files.pythonhosted.org/packages/2f/6f/3284d4203fd2f28edd73034968398cd2d4cb04ab192abc8cff007ea35679/coverage-7.13.4-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:caa421e2684e382c5d8973ac55e4f36bed6821a9bad5c953494de960c74595c9", size = 261877, upload-time = "2026-02-09T12:58:37.864Z" },
{ url = "https://files.pythonhosted.org/packages/09/aa/b672a647bbe1556a85337dc95bfd40d146e9965ead9cc2fe81bde1e5cbce/coverage-7.13.4-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:14375934243ee05f56c45393fe2ce81fe5cc503c07cee2bdf1725fb8bef3ffaf", size = 264004, upload-time = "2026-02-09T12:58:39.492Z" },
{ url = "https://files.pythonhosted.org/packages/79/a1/aa384dbe9181f98bba87dd23dda436f0c6cf2e148aecbb4e50fc51c1a656/coverage-7.13.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25a41c3104d08edb094d9db0d905ca54d0cd41c928bb6be3c4c799a54753af55", size = 266408, upload-time = "2026-02-09T12:58:41.852Z" },
{ url = "https://files.pythonhosted.org/packages/53/5e/5150bf17b4019bc600799f376bb9606941e55bd5a775dc1e096b6ffea952/coverage-7.13.4-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f01afcff62bf9a08fb32b2c1d6e924236c0383c02c790732b6537269e466a72", size = 267544, upload-time = "2026-02-09T12:58:44.093Z" },
{ url = "https://files.pythonhosted.org/packages/e0/ed/f1de5c675987a4a7a672250d2c5c9d73d289dbf13410f00ed7181d8017dd/coverage-7.13.4-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eb9078108fbf0bcdde37c3f4779303673c2fa1fe8f7956e68d447d0dd426d38a", size = 260980, upload-time = "2026-02-09T12:58:45.721Z" },
{ url = "https://files.pythonhosted.org/packages/b3/e3/fe758d01850aa172419a6743fe76ba8b92c29d181d4f676ffe2dae2ba631/coverage-7.13.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0e086334e8537ddd17e5f16a344777c1ab8194986ec533711cbe6c41cde841b6", size = 263871, upload-time = "2026-02-09T12:58:47.334Z" },
{ url = "https://files.pythonhosted.org/packages/b6/76/b829869d464115e22499541def9796b25312b8cf235d3bb00b39f1675395/coverage-7.13.4-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:725d985c5ab621268b2edb8e50dfe57633dc69bda071abc470fed55a14935fd3", size = 261472, upload-time = "2026-02-09T12:58:48.995Z" },
{ url = "https://files.pythonhosted.org/packages/14/9e/caedb1679e73e2f6ad240173f55218488bfe043e38da577c4ec977489915/coverage-7.13.4-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:3c06f0f1337c667b971ca2f975523347e63ec5e500b9aa5882d91931cd3ef750", size = 265210, upload-time = "2026-02-09T12:58:51.178Z" },
{ url = "https://files.pythonhosted.org/packages/3a/10/0dd02cb009b16ede425b49ec344aba13a6ae1dc39600840ea6abcb085ac4/coverage-7.13.4-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:590c0ed4bf8e85f745e6b805b2e1c457b2e33d5255dd9729743165253bc9ad39", size = 260319, upload-time = "2026-02-09T12:58:53.081Z" },
{ url = "https://files.pythonhosted.org/packages/92/8e/234d2c927af27c6d7a5ffad5bd2cf31634c46a477b4c7adfbfa66baf7ebb/coverage-7.13.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:eb30bf180de3f632cd043322dad5751390e5385108b2807368997d1a92a509d0", size = 262638, upload-time = "2026-02-09T12:58:55.258Z" },
{ url = "https://files.pythonhosted.org/packages/2f/64/e5547c8ff6964e5965c35a480855911b61509cce544f4d442caa759a0702/coverage-7.13.4-cp314-cp314t-win32.whl", hash = "sha256:c4240e7eded42d131a2d2c4dec70374b781b043ddc79a9de4d55ca71f8e98aea", size = 223040, upload-time = "2026-02-09T12:58:56.936Z" },
{ url = "https://files.pythonhosted.org/packages/c7/96/38086d58a181aac86d503dfa9c47eb20715a79c3e3acbdf786e92e5c09a8/coverage-7.13.4-cp314-cp314t-win_amd64.whl", hash = "sha256:4c7d3cc01e7350f2f0f6f7036caaf5673fb56b6998889ccfe9e1c1fe75a9c932", size = 224148, upload-time = "2026-02-09T12:58:58.645Z" },
{ url = "https://files.pythonhosted.org/packages/ce/72/8d10abd3740a0beb98c305e0c3faf454366221c0f37a8bcf8f60020bb65a/coverage-7.13.4-cp314-cp314t-win_arm64.whl", hash = "sha256:23e3f687cf945070d1c90f85db66d11e3025665d8dafa831301a0e0038f3db9b", size = 222172, upload-time = "2026-02-09T12:59:00.396Z" },
{ url = "https://files.pythonhosted.org/packages/0d/4a/331fe2caf6799d591109bb9c08083080f6de90a823695d412a935622abb2/coverage-7.13.4-py3-none-any.whl", hash = "sha256:1af1641e57cf7ba1bd67d677c9abdbcd6cc2ab7da3bca7fa1e2b7e50e65f2ad0", size = 211242, upload-time = "2026-02-09T12:59:02.032Z" },
]
[package.optional-dependencies]
toml = [
{ name = "tomli", marker = "python_full_version <= '3.11'" },
]
[[package]]
name = "croniter"
version = "2.0.7"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "python-dateutil" },
{ name = "pytz" },
]
sdist = { url = "https://files.pythonhosted.org/packages/3d/70/240ea4efb2e03b513d820e8da48b784258cbc88770b4b061931cf0269cf8/croniter-2.0.7.tar.gz", hash = "sha256:1041b912b4b1e03751a0993531becf77851ae6e8b334c9c76ffeffb8f055f53f", size = 49655, upload-time = "2024-07-16T15:21:23.156Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/99/1b/62e5ef33bb8cd599004b85f1ae648aaaf329ec396a8e210906e3f04df66a/croniter-2.0.7-py2.py3-none-any.whl", hash = "sha256:f15e80828d23920c4bb7f4d9340b932c9dcabecafc7775703c8b36d1253ed526", size = 21201, upload-time = "2024-07-16T15:21:20.433Z" },
]
[[package]]
name = "django"
version = "5.2.11"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version < '3.12'",
]
dependencies = [
{ name = "asgiref" },
{ name = "sqlparse" },
{ name = "tzdata", marker = "sys_platform == 'win32'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/17/f2/3e57ef696b95067e05ae206171e47a8e53b9c84eec56198671ef9eaa51a6/django-5.2.11.tar.gz", hash = "sha256:7f2d292ad8b9ee35e405d965fbbad293758b858c34bbf7f3df551aeeac6f02d3", size = 10885017, upload-time = "2026-02-03T13:52:50.554Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/91/a7/2b112ab430575bf3135b8304ac372248500d99c352f777485f53fdb9537e/django-5.2.11-py3-none-any.whl", hash = "sha256:e7130df33ada9ab5e5e929bc19346a20fe383f5454acb2cc004508f242ee92c0", size = 8291375, upload-time = "2026-02-03T13:52:42.47Z" },
]
[[package]]
name = "django"
version = "6.0.2"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version >= '3.12'",
]
dependencies = [
{ name = "asgiref" },
{ name = "sqlparse" },
{ name = "tzdata", marker = "sys_platform == 'win32'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/26/3e/a1c4207c5dea4697b7a3387e26584919ba987d8f9320f59dc0b5c557a4eb/django-6.0.2.tar.gz", hash = "sha256:3046a53b0e40d4b676c3b774c73411d7184ae2745fe8ce5e45c0f33d3ddb71a7", size = 10886874, upload-time = "2026-02-03T13:50:31.596Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/96/ba/a6e2992bc5b8c688249c00ea48cb1b7a9bc09839328c81dc603671460928/django-6.0.2-py3-none-any.whl", hash = "sha256:610dd3b13d15ec3f1e1d257caedd751db8033c5ad8ea0e2d1219a8acf446ecc6", size = 8339381, upload-time = "2026-02-03T13:50:15.501Z" },
]
[[package]]
name = "django-picklefield"
version = "3.4.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "django", version = "5.2.11", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "django", version = "6.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/93/03/13114bccbd1ec8c026ac1ff33dae75ae6c6a5632e4769ee9cda283b9f57e/django_picklefield-3.4.0.tar.gz", hash = "sha256:3a1f740536c0e60d0dba43aa89ccdbe86760d4c3f8ec47799eae122baa741d0a", size = 12555, upload-time = "2025-11-27T03:11:53.13Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/79/b7/139eb1419ca7b27fd714925b8d0eed6efb592479dcf2155fed6c0c87c956/django_picklefield-3.4.0-py3-none-any.whl", hash = "sha256:929bcfbae5b48bd22a52bc04521fdfdd152eee36abb9f20228f9480f9df65f45", size = 10031, upload-time = "2025-11-27T03:11:51.937Z" },
]
[[package]]
name = "django-q2"
version = "1.10.0"
source = { editable = "." }
dependencies = [
{ name = "django", version = "5.2.11", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "django", version = "6.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
{ name = "django-picklefield" },
]
[package.optional-dependencies]
croniter = [
{ name = "croniter" },
]
testing = [
{ name = "blessed" },
{ name = "boto3" },
{ name = "croniter" },
{ name = "django-redis" },
{ name = "hiredis" },
{ name = "iron-mq" },
{ name = "psutil" },
{ name = "pymongo" },
{ name = "pytest" },
{ name = "pytest-cov" },
{ name = "pytest-django" },
{ name = "redis" },
{ name = "ruff" },
{ name = "setproctitle" },
]
[package.metadata]
requires-dist = [
{ name = "blessed", marker = "extra == 'testing'" },
{ name = "boto3", marker = "extra == 'testing'" },
{ name = "croniter", marker = "extra == 'croniter'" },
{ name = "croniter", marker = "extra == 'testing'" },
{ name = "django", specifier = ">=5.2" },
{ name = "django-picklefield", specifier = ">=3.1,<4" },
{ name = "django-redis", marker = "extra == 'testing'" },
{ name = "hiredis", marker = "extra == 'testing'" },
{ name = "importlib-metadata", marker = "python_full_version < '3.10'", specifier = ">=3.6" },
{ name = "iron-mq", marker = "extra == 'testing'" },
{ name = "psutil", marker = "extra == 'testing'" },
{ name = "pymongo", marker = "extra == 'testing'" },
{ name = "pytest", marker = "extra == 'testing'" },
{ name = "pytest-cov", marker = "extra == 'testing'" },
{ name = "pytest-django", marker = "extra == 'testing'" },
{ name = "redis", marker = "extra == 'testing'" },
{ name = "ruff", marker = "extra == 'testing'" },
{ name = "setproctitle", marker = "extra == 'testing'" },
]
provides-extras = ["testing", "croniter"]
[[package]]
name = "django-redis"
version = "5.4.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "django", version = "5.2.11", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "django", version = "6.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
{ name = "redis" },
]
sdist = { url = "https://files.pythonhosted.org/packages/83/9d/2272742fdd9d0a9f0b28cd995b0539430c9467a2192e4de2cea9ea6ad38c/django-redis-5.4.0.tar.gz", hash = "sha256:6a02abaa34b0fea8bf9b707d2c363ab6adc7409950b2db93602e6cb292818c42", size = 52567, upload-time = "2023-10-01T20:22:01.221Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b7/f1/63caad7c9222c26a62082f4f777de26389233b7574629996098bf6d25a4d/django_redis-5.4.0-py3-none-any.whl", hash = "sha256:ebc88df7da810732e2af9987f7f426c96204bf89319df4c6da6ca9a2942edd5b", size = 31119, upload-time = "2023-10-01T20:21:33.009Z" },
]
[[package]]
name = "dnspython"
version = "2.8.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" },
]
[[package]]
name = "exceptiongroup"
version = "1.3.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" },
]
[[package]]
name = "hiredis"
version = "2.4.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/bc/bd/e1ba6b92634fd0a25d583a0f988c6fae6767adce46756763ada694defd1b/hiredis-2.4.0.tar.gz", hash = "sha256:90d7af678056c7889d86821344d79fec3932a6a1480ebba3d644cb29a3135348", size = 87599, upload-time = "2024-07-19T11:53:39.12Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/99/8a/3d41b452daba0cc44297680d8268b2d4a99c9f692a6332fefaae2b8777f0/hiredis-2.4.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:aee6c4e8f670ea685345ce4ca01c574a52e0a4318af2b8cdd563de9567731056", size = 81332, upload-time = "2024-07-19T11:51:40.356Z" },
{ url = "https://files.pythonhosted.org/packages/d8/70/3f39ebfb3824578c34400df3b037b268abb5af0abaa789b430ffd17dd74e/hiredis-2.4.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:76503a0edaf3d1557518127511e69e5d9fa37b6ff15598b0d9d9c2db18b08a41", size = 44669, upload-time = "2024-07-19T11:51:42.303Z" },
{ url = "https://files.pythonhosted.org/packages/ed/b7/26a56a3b991abe7fcf7bcfa8e0a08de3c3766c6caecb1ba46239342792ff/hiredis-2.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b027b53adb1df11923753d85587e3ab611fe70bc69596e9eb3269acab809c376", size = 42344, upload-time = "2024-07-19T11:51:43.407Z" },
{ url = "https://files.pythonhosted.org/packages/0c/30/18b824e556271fb7ffa33c8c24712b440e5c2d4abe053d06e2dfc533394f/hiredis-2.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5d2776c7cd6a338cd9338fb50f2a38a7ca3e16250b40ab2d0c41eb1697ebc12", size = 166428, upload-time = "2024-07-19T11:51:44.46Z" },
{ url = "https://files.pythonhosted.org/packages/d1/35/ad968258e526b05189a3a9cd5359eb5a6d5c049d376c964c0a660728b986/hiredis-2.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8767cae1474f8102ec3d362976f80c8dd4eafd4109c6072adee0a15e37ba919c", size = 177320, upload-time = "2024-07-19T11:51:46.198Z" },
{ url = "https://files.pythonhosted.org/packages/a0/de/78dd25a50c51ace6af9a42665ef0b9439c858493f4c8dd98f55d21780a8c/hiredis-2.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6dac8a5be01d92707409feec61b98721b7b5c3e77fe7e9e5c7cfb9fdd28385af", size = 166809, upload-time = "2024-07-19T11:51:47.726Z" },
{ url = "https://files.pythonhosted.org/packages/42/6e/8adaefff7e3e216b0f7bd6cafce6d5d06798f31c3e2852dc3db6a7d758c9/hiredis-2.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87a8ece3e893f45354395c6b9dc0479744c1c8c6ee4471b60945d96c9b5ce6c2", size = 166538, upload-time = "2024-07-19T11:51:49.195Z" },
{ url = "https://files.pythonhosted.org/packages/15/5b/e2525aa0141e6b77cd6e5a4969a8a3f7952ce24c017547935614d4ba3445/hiredis-2.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c85110f536e59fe19ea4b002d04228f57f55462add1630a0785cd6ec62e70415", size = 162859, upload-time = "2024-07-19T11:51:50.599Z" },
{ url = "https://files.pythonhosted.org/packages/53/e5/bcb02b046a46b475ca6db822833cabf13f307c3cbbdf0b61ea2a4c458bb9/hiredis-2.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cb62c82a2518b8446be1cc5eb4319e282776bf96fdb2964e81ff2c15d632248b", size = 160729, upload-time = "2024-07-19T11:51:51.784Z" },
{ url = "https://files.pythonhosted.org/packages/1f/66/8be3100839dd367594fa6397e0fd13bc85701c2d9cdaaec9823af888a0fd/hiredis-2.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9ae4b19cab270fae77d7f944d56bbb308c9886d9577891b347a8deea75563995", size = 159832, upload-time = "2024-07-19T11:51:53.068Z" },
{ url = "https://files.pythonhosted.org/packages/19/d6/f3ec8d231b3fcf8e3a883c6b935c72ec1d45c78e955b1c65e3cd1b446723/hiredis-2.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:9fc1a6c78197eff8b4d125bb98410b661e732f3ec563c03264d2d7378cf9e613", size = 171704, upload-time = "2024-07-19T11:51:54.156Z" },
{ url = "https://files.pythonhosted.org/packages/9f/7c/19d5cbdbcff97b2029e65f453aa5eb4f49e1df36430c3b916a7d36b503cf/hiredis-2.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:38dd931f1124bd9781d3027a0cd6fb6f5a75b5c4ba4fe5540584105239b1f901", size = 164062, upload-time = "2024-07-19T11:51:55.236Z" },
{ url = "https://files.pythonhosted.org/packages/24/6f/b020cde8b146f1025549a93ed67b19fe49d6e1cbf7647da3cc0fb9abdcf0/hiredis-2.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2a21e2740c33347740dceb106b64b8a384e91da49aac7e8b3f2a25a9b33714b9", size = 161773, upload-time = "2024-07-19T11:51:56.535Z" },
{ url = "https://files.pythonhosted.org/packages/9c/ab/ac130f162e67ab9350dec362b337ddf224f6567d05b3d95e7dd20ca9849b/hiredis-2.4.0-cp310-cp310-win32.whl", hash = "sha256:b0adbe8f33f57f2b6bfa8a2ea18f3e4ed91676503673f70f796bfbd06a1a2214", size = 20076, upload-time = "2024-07-19T11:51:57.803Z" },
{ url = "https://files.pythonhosted.org/packages/58/85/e30d47313524c3ea6e1a1a199fca0d518ef5cce7b26f45552959915b7ab1/hiredis-2.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:168de1672bd73f7f3cdf0097084b4a71651ac35f7d99d0229ea8f223358d3a79", size = 21534, upload-time = "2024-07-19T11:51:59.28Z" },
{ url = "https://files.pythonhosted.org/packages/c1/78/fff35558ed059bfe0e2e2255314538b3f42ee01cb748ad6441ac3426254d/hiredis-2.4.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:ac9d91b4d9c306e66a1abd224524fada07684a57f7da72a675e4b8bee9302b38", size = 81334, upload-time = "2024-07-19T11:52:00.629Z" },
{ url = "https://files.pythonhosted.org/packages/18/01/d63ea43b6d4991f2b7cc142550b45e951e7588415a8c8c200c878fb01aa6/hiredis-2.4.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:f74bfa9f1b91718d6664d4708d092f7d44e2f0f825a5fab82819d43d41e0302d", size = 44669, upload-time = "2024-07-19T11:52:01.641Z" },
{ url = "https://files.pythonhosted.org/packages/31/8e/329eccbb7c64bca74619fb93037b0d911f99218e0ebc43ae74bac608a172/hiredis-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:668b02556d12046e7ce94ded5bfe0ad9989d26e6977ecc55941b9a1a4a49d7d5", size = 42349, upload-time = "2024-07-19T11:52:02.906Z" },
{ url = "https://files.pythonhosted.org/packages/50/e2/78d431c22abdf26d4ad8a68340e20103518c8bcfa0d43843389688d921ad/hiredis-2.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6033cc6caaf056969af9ce372282a6ef2838559f2eadffe7ddb73bf65dcb27d6", size = 167118, upload-time = "2024-07-19T11:52:03.87Z" },
{ url = "https://files.pythonhosted.org/packages/4b/09/0dd0e8f877cf9329de40613f24780b686241097a756be1ef1db2beebb194/hiredis-2.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f76fcf2867d19259b53680c08314435b46f632d20a4d7b9f0ccbb5dd3e925e79", size = 177993, upload-time = "2024-07-19T11:52:05.257Z" },
{ url = "https://files.pythonhosted.org/packages/eb/04/e68bb0f8c4538c743e30d274bcca7493e5b599e4547228f714ace63faa5b/hiredis-2.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c0e706e0c3d1ec54d8243410e0fd5974b1c7b69db5c54cd9ae6a3a4b64fae33", size = 167659, upload-time = "2024-07-19T11:52:07.28Z" },
{ url = "https://files.pythonhosted.org/packages/29/aa/32818b9e459281b11758e31290fef367b1a14cc90778413d69a47b711a39/hiredis-2.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06815c3b9bf7225c4dcc9dd9dfb5a9fa91b4f680104443ef3fcd78410d7eb027", size = 167309, upload-time = "2024-07-19T11:52:09.527Z" },
{ url = "https://files.pythonhosted.org/packages/ba/6a/3acc8ac22fd3e43cc7417423d247ae220c49948e267b2b28f070d27144ac/hiredis-2.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f44715d6a3313d614ff7550e52ecff67a283776909d960f338701b57e6013542", size = 163170, upload-time = "2024-07-19T11:52:10.941Z" },
{ url = "https://files.pythonhosted.org/packages/ef/d6/c7f68ca3de4e5194823cb7e18704d83987fb7bcdbe4a8d53d64a4db716ac/hiredis-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:39e1c7212dea1bbed0b075574808bc7c3192b324f54ea5d9ee522f6c35014ce7", size = 161323, upload-time = "2024-07-19T11:52:12.518Z" },
{ url = "https://files.pythonhosted.org/packages/26/12/4c56451806c66e1d3616856b414b3e6f5357ab24f643b8a6bbb80f362fd1/hiredis-2.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b385fc7fc7b0811c3fcac4b0a35e5606eca693efba0d1446623ef0158a078034", size = 160186, upload-time = "2024-07-19T11:52:13.739Z" },
{ url = "https://files.pythonhosted.org/packages/ad/7f/382918c9bb3d99ba92effe6e88a47284334ca5b50433834c1dc798c87ff5/hiredis-2.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:0a87a249124666db2b795a0eb77cea5b8af8b148566616a681304826b4405869", size = 172406, upload-time = "2024-07-19T11:52:14.851Z" },
{ url = "https://files.pythonhosted.org/packages/d6/a9/1c7a25ed0a30d0b2cd8998c96beaabeccad659177fe5e1aa97eec6f54ac1/hiredis-2.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9b4039cd40335f66e55a8bee314b6a795f169fb02d70215d482023ec74613371", size = 164644, upload-time = "2024-07-19T11:52:16.161Z" },
{ url = "https://files.pythonhosted.org/packages/ee/52/07beb17f0dd6ef1079f0ac9d80481dc5dd96abf2ddbd41ff6fb027bb8c31/hiredis-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c77113fbdbd7ca5de72dd3b7d113856609a1b878f6164de09dd95d12e6a51de2", size = 162356, upload-time = "2024-07-19T11:52:17.766Z" },
{ url = "https://files.pythonhosted.org/packages/f4/26/d1c128faa2a51c122c2b7e29545a9e854f8c81a7581c6d89b11caf701b9a/hiredis-2.4.0-cp311-cp311-win32.whl", hash = "sha256:469c1a85017abf11d854fb16eca9a4093ebe1f2dacf777fed869d726f02b1389", size = 20083, upload-time = "2024-07-19T11:52:18.882Z" },
{ url = "https://files.pythonhosted.org/packages/a5/84/bfbfeedeb98c49a7977d3995eda554acb0d7a2ed65410f50eac983dd91bd/hiredis-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:a5c3a32af789b0ec413a606c99b55579abbcb6c86220610a5c5041da8688e7ca", size = 21534, upload-time = "2024-07-19T11:52:19.799Z" },
{ url = "https://files.pythonhosted.org/packages/cc/69/680b4675f578433e8be026229683293110d66d21a87dcae9bae31d611d96/hiredis-2.4.0-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:8b88390a5e31572e05e8eab476ed3176cc3d2f9622ccc059398ffdb02aaefec4", size = 81433, upload-time = "2024-07-19T11:52:20.729Z" },
{ url = "https://files.pythonhosted.org/packages/a6/36/b926bcc56113b6cfedfeaabcb97f63d90c6809ed63269628272909c099a8/hiredis-2.4.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:fa4842977924209ae653e856238a30b1c68e579ecde5cf1c16c4de471b35cec7", size = 44733, upload-time = "2024-07-19T11:52:22.136Z" },
{ url = "https://files.pythonhosted.org/packages/ce/b0/506c37793d81d112318b90e2481b8727bbc3c96a09fecc533768872a30a8/hiredis-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a459b7ff3d802792254d6fc6a622e53ca9cf9f002ed79db7e4dee536b2e20e5d", size = 42405, upload-time = "2024-07-19T11:52:23.107Z" },
{ url = "https://files.pythonhosted.org/packages/f4/5b/7e2aa081a03f92b82e1a4e6700ed4e4707d3950f1a9550e8c655e651c1a5/hiredis-2.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5c711c8ca8d5767ed8ecd5fb5602c12eaf8fb256a5f4308ae36f2dc79e6f853", size = 169078, upload-time = "2024-07-19T11:52:24.051Z" },
{ url = "https://files.pythonhosted.org/packages/1a/3f/1783b24d1a4b02a63b629c06dfee6463f17144b5f70cac5c97b7b89ab745/hiredis-2.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a4f733882b67407d4b667eafd61fce86e8e204b158258cc1d0cb0843f6bb4708", size = 179911, upload-time = "2024-07-19T11:52:25.468Z" },
{ url = "https://files.pythonhosted.org/packages/19/d7/87004b1cb044a1e0736d55a8750514c76fffa4710d2b465486a83010d9c0/hiredis-2.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:605fe35ebb482b7c8d5daadcf3d264dc5edd205a352d89ee3a983861ef73cda8", size = 169403, upload-time = "2024-07-19T11:52:26.552Z" },
{ url = "https://files.pythonhosted.org/packages/dd/98/160037832cbc702ec92b71a8f94000e3227e427ae7866c44bd8f089be31f/hiredis-2.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a40f1d985047fe4654a1afb4702cbe0daeacde3868d52be9e4652615d387e05b", size = 169884, upload-time = "2024-07-19T11:52:28.189Z" },
{ url = "https://files.pythonhosted.org/packages/ec/24/c8950993aeaa4af2d7dcaad1966b62cf01bc45633f06e308c9246f7ef58a/hiredis-2.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fc8d3edbc9f32da930da6ea33d43ce0c3239e6b2018a77907fbf4e9836bd6def", size = 165399, upload-time = "2024-07-19T11:52:29.383Z" },
{ url = "https://files.pythonhosted.org/packages/54/25/26f291cee841b76dbb2f64fb8874033ad3eed246f8969b96cc922ad417aa/hiredis-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5b0b2463906cc4119187dfaad493c48a7b2e17120946feb3eb7c2328c8cb4bca", size = 163335, upload-time = "2024-07-19T11:52:30.802Z" },
{ url = "https://files.pythonhosted.org/packages/66/97/5f77048ce1e0ee8453cc11be919adf8c2c34474acf970dbeae8aea328eee/hiredis-2.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5e45171fd046bbed2ce6ac485071cd0575d18ae98b5bbcf6533356e443ec47ea", size = 161909, upload-time = "2024-07-19T11:52:32.451Z" },
{ url = "https://files.pythonhosted.org/packages/5d/f1/318c5a99d1c39e2cfe1c563132b18843d0e9f90d82cdb2804e3e860f9316/hiredis-2.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:68e39d2c0beed53e5361caacd0de98f864b3532344edb79e27e62efba2262de5", size = 174283, upload-time = "2024-07-19T11:52:33.537Z" },
{ url = "https://files.pythonhosted.org/packages/1b/eb/f7febe81159fc19472c2c2ad698f1dafd71d72cd2ce24ffad6a95949bc54/hiredis-2.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2b76a5600047387c73c1b3d950e4ae3feffaefd442b20ba2f5fea773881d9bcd", size = 166667, upload-time = "2024-07-19T11:52:35.112Z" },
{ url = "https://files.pythonhosted.org/packages/cc/07/28f88471603a5bfd7844df225b06c50169705b8d383684c2f758efdf1011/hiredis-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1537d13eefe4f48cb979362264851ee90d2bb7a221c8c350e9ceeda9f0392228", size = 164525, upload-time = "2024-07-19T11:52:36.21Z" },
{ url = "https://files.pythonhosted.org/packages/9e/9a/944764cce2a12215b4262c855734bbc34e77857ee761b5e0d71a71883c23/hiredis-2.4.0-cp312-cp312-win32.whl", hash = "sha256:1bfa50491d3222e3c2297b52c14e835ac52702ac8a91ec3fc1ff5201912623bb", size = 20237, upload-time = "2024-07-19T11:52:37.933Z" },
{ url = "https://files.pythonhosted.org/packages/de/2c/43be81cd76c806bc96ca3dd0fb26cbbb2e11d86e211bb1fc88b6c1de680c/hiredis-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:9aabc6098ef00e158598489db5a8b9e12d57a55ea5a4ec35ba3b527dfb88d16e", size = 21633, upload-time = "2024-07-19T11:52:38.818Z" },
{ url = "https://files.pythonhosted.org/packages/22/b6/2202807078b63c9f7a8f8dcdbe98f1b36bd246b757b261da790728beb1f4/hiredis-2.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:aeb60452d5b6150075974bc36e1cc74a46bd4b125cd5e72a86a04f4d6abf4e67", size = 39903, upload-time = "2024-07-19T11:53:16.673Z" },
{ url = "https://files.pythonhosted.org/packages/26/21/4b0abb18e76860b354e77a734c82e18ffbb9153e6f263eaad47d1d154c5e/hiredis-2.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:4da6d881033a1bcb31bba152ea0925344127f0a98f86a6cf2ceb01cf6ecd29e2", size = 36991, upload-time = "2024-07-19T11:53:17.648Z" },
{ url = "https://files.pythonhosted.org/packages/65/b2/3c9eb8804073afe5cc4ff40760e6f0b15e5234557a8cab194d447189ecf8/hiredis-2.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9d559775a95aee0ff06c0aaac638691619d6342b7cde85c62ad228804f82829", size = 47969, upload-time = "2024-07-19T11:53:18.626Z" },
{ url = "https://files.pythonhosted.org/packages/c3/6f/7786187814df1ff1c017939725d1374ffbb23d973f56e871cfb5a46b51d8/hiredis-2.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48baae8fbebf3b11660db6e51a55ff51516ed32edcd44a57f51ea9b373aca330", size = 48364, upload-time = "2024-07-19T11:53:19.652Z" },
{ url = "https://files.pythonhosted.org/packages/51/3a/85f08eb7f2f0463691cf432cbb4768ee39d556aa2651ce23b20a011178cf/hiredis-2.4.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d851b7ff732ebc9d823de3c7cc95a5ed4261a0226acd46861a18369ac9568f36", size = 55692, upload-time = "2024-07-19T11:53:20.724Z" },
{ url = "https://files.pythonhosted.org/packages/0b/cc/d88dfd4cdf5fd9f7ca117e8fa0e609eed702db8d1cb3f3652a51fc3ab250/hiredis-2.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:1d16f5023c1d9971f284231eb7036a25d4d123138a5adc4512c92a73d83b9a77", size = 21631, upload-time = "2024-07-19T11:53:21.738Z" },
]
[[package]]
name = "idna"
version = "3.11"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" },
]
[[package]]
name = "iniconfig"
version = "2.3.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
]
[[package]]
name = "iron-core"
version = "1.2.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "python-dateutil" },
{ name = "requests" },
]
sdist = { url = "https://files.pythonhosted.org/packages/0a/48/9192fb85b687a5bb5d4981aa64edaa13d5fa280576140a43edcfafb89902/iron-core-1.2.1.tar.gz", hash = "sha256:b7190b86afbe5470da8389fbb412c0fa0529c87f85261736a87e5983ab6f1b95", size = 6152, upload-time = "2022-03-15T16:00:13.945Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/16/9a/8661bcbf6291a955e4f4ba6994e6b60cb6779248d83c8339e723d5e8294d/iron_core-1.2.1-py3-none-any.whl", hash = "sha256:fd5ed3f9b441b9256bae1f829ae6f1da73fae62872aef395336f7d0ac2f041f7", size = 5801, upload-time = "2022-03-15T16:00:12.798Z" },
]
[[package]]
name = "iron-mq"
version = "0.9"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "iron-core" },
]
sdist = { url = "https://files.pythonhosted.org/packages/1a/2e/dd6cee26ed27e25b8700f3de79a3dbf2386b4b69a28a7be20b72d7242e7b/iron-mq-0.9.tar.gz", hash = "sha256:c90441d872d9c08968343810a2ad1cca1664d80fd2ad3a3a2dbec57b7b38ecfa", size = 7442, upload-time = "2016-05-31T12:03:24.055Z" }
[[package]]
name = "jinxed"
version = "1.3.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "ansicon" },
]
sdist = { url = "https://files.pythonhosted.org/packages/20/d0/59b2b80e7a52d255f9e0ad040d2e826342d05580c4b1d7d7747cfb8db731/jinxed-1.3.0.tar.gz", hash = "sha256:1593124b18a41b7a3da3b078471442e51dbad3d77b4d4f2b0c26ab6f7d660dbf", size = 80981, upload-time = "2024-07-31T22:39:18.854Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/27/e3/0e0014d6ab159d48189e92044ace13b1e1fe9aa3024ba9f4e8cf172aa7c2/jinxed-1.3.0-py2.py3-none-any.whl", hash = "sha256:b993189f39dc2d7504d802152671535b06d380b26d78070559551cbf92df4fc5", size = 33085, upload-time = "2024-07-31T22:39:17.426Z" },
]
[[package]]
name = "jmespath"
version = "1.1.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d3/59/322338183ecda247fb5d1763a6cbe46eff7222eaeebafd9fa65d4bf5cb11/jmespath-1.1.0.tar.gz", hash = "sha256:472c87d80f36026ae83c6ddd0f1d05d4e510134ed462851fd5f754c8c3cbb88d", size = 27377, upload-time = "2026-01-22T16:35:26.279Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl", hash = "sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64", size = 20419, upload-time = "2026-01-22T16:35:24.919Z" },
]
[[package]]
name = "packaging"
version = "26.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" },
]
[[package]]
name = "pluggy"
version = "1.6.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
]
[[package]]
name = "psutil"
version = "5.9.8"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/90/c7/6dc0a455d111f68ee43f27793971cf03fe29b6ef972042549db29eec39a2/psutil-5.9.8.tar.gz", hash = "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c", size = 503247, upload-time = "2024-01-19T20:47:09.517Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e7/e3/07ae864a636d70a8a6f58da27cb1179192f1140d5d1da10886ade9405797/psutil-5.9.8-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81", size = 248702, upload-time = "2024-01-19T20:47:36.303Z" },
{ url = "https://files.pythonhosted.org/packages/b3/bd/28c5f553667116b2598b9cc55908ec435cb7f77a34f2bff3e3ca765b0f78/psutil-5.9.8-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421", size = 285242, upload-time = "2024-01-19T20:47:39.65Z" },
{ url = "https://files.pythonhosted.org/packages/c5/4f/0e22aaa246f96d6ac87fe5ebb9c5a693fbe8877f537a1022527c47ca43c5/psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4", size = 288191, upload-time = "2024-01-19T20:47:43.078Z" },
{ url = "https://files.pythonhosted.org/packages/6e/f5/2aa3a4acdc1e5940b59d421742356f133185667dd190b166dbcfcf5d7b43/psutil-5.9.8-cp37-abi3-win32.whl", hash = "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0", size = 251252, upload-time = "2024-01-19T20:47:52.88Z" },
{ url = "https://files.pythonhosted.org/packages/93/52/3e39d26feae7df0aa0fd510b14012c3678b36ed068f7d78b8d8784d61f0e/psutil-5.9.8-cp37-abi3-win_amd64.whl", hash = "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf", size = 255090, upload-time = "2024-01-19T20:47:56.019Z" },
{ url = "https://files.pythonhosted.org/packages/05/33/2d74d588408caedd065c2497bdb5ef83ce6082db01289a1e1147f6639802/psutil-5.9.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8", size = 249898, upload-time = "2024-01-19T20:47:59.238Z" },
]
[[package]]
name = "pymongo"
version = "4.16.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "dnspython" },
]
sdist = { url = "https://files.pythonhosted.org/packages/65/9c/a4895c4b785fc9865a84a56e14b5bd21ca75aadc3dab79c14187cdca189b/pymongo-4.16.0.tar.gz", hash = "sha256:8ba8405065f6e258a6f872fe62d797a28f383a12178c7153c01ed04e845c600c", size = 2495323, upload-time = "2026-01-07T18:05:48.107Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/4d/93/c36c0998dd91ad8b5031d2e77a903d5cd705b5ba05ca92bcc8731a2c3a8d/pymongo-4.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ed162b2227f98d5b270ecbe1d53be56c8c81db08a1a8f5f02d89c7bb4d19591d", size = 807993, upload-time = "2026-01-07T18:03:40.302Z" },
{ url = "https://files.pythonhosted.org/packages/f3/96/d2117d792fa9fedb2f6ccf0608db31f851e8382706d7c3c88c6ac92cc958/pymongo-4.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4a9390dce61d705a88218f0d7b54d7e1fa1b421da8129fc7c009e029a9a6b81e", size = 808355, upload-time = "2026-01-07T18:03:42.13Z" },
{ url = "https://files.pythonhosted.org/packages/ae/2e/e79b7b86c0dd6323d0985c201583c7921d67b842b502aae3f3327cbe3935/pymongo-4.16.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:92a232af9927710de08a6c16a9710cc1b175fb9179c0d946cd4e213b92b2a69a", size = 1182337, upload-time = "2026-01-07T18:03:44.126Z" },
{ url = "https://files.pythonhosted.org/packages/7b/82/07ec9966381c57d941fddc52637e9c9653e63773be410bd8605f74683084/pymongo-4.16.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4d79aa147ce86aef03079096d83239580006ffb684eead593917186aee407767", size = 1200928, upload-time = "2026-01-07T18:03:45.52Z" },
{ url = "https://files.pythonhosted.org/packages/44/15/9d45e3cc6fa428b0a3600b0c1c86b310f28c91251c41493460695ab40b6b/pymongo-4.16.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:19a1c96e7f39c7a59a9cfd4d17920cf9382f6f684faeff4649bf587dc59f8edc", size = 1239418, upload-time = "2026-01-07T18:03:47.03Z" },
{ url = "https://files.pythonhosted.org/packages/c8/b3/f35ee51e2a3f05f673ad4f5e803ae1284c42f4413e8d121c4958f1af4eb9/pymongo-4.16.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efe020c46ce3c3a89af6baec6569635812129df6fb6cf76d4943af3ba6ee2069", size = 1229045, upload-time = "2026-01-07T18:03:48.377Z" },
{ url = "https://files.pythonhosted.org/packages/18/2d/1688b88d7c0a5c01da8c703dea831419435d9ce67c6ddbb0ac629c9c72d2/pymongo-4.16.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9dc2c00bed568732b89e211b6adca389053d5e6d2d5a8979e80b813c3ec4d1f9", size = 1196517, upload-time = "2026-01-07T18:03:50.205Z" },
{ url = "https://files.pythonhosted.org/packages/e6/c6/e89db0f23bd20757b627a5d8c73a609ffd6741887b9004ab229208a79764/pymongo-4.16.0-cp310-cp310-win32.whl", hash = "sha256:5b9c6d689bbe5beb156374508133218610e14f8c81e35bc17d7a14e30ab593e6", size = 794911, upload-time = "2026-01-07T18:03:52.701Z" },
{ url = "https://files.pythonhosted.org/packages/37/54/e00a5e517153f310a33132375159e42dceb12bee45b51b35aa0df14f1866/pymongo-4.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:2290909275c9b8f637b0a92eb9b89281e18a72922749ebb903403ab6cc7da914", size = 804801, upload-time = "2026-01-07T18:03:57.671Z" },
{ url = "https://files.pythonhosted.org/packages/e5/0a/2572faf89195a944c99c6d756227019c8c5f4b5658ecc261c303645dfe69/pymongo-4.16.0-cp310-cp310-win_arm64.whl", hash = "sha256:6af1aaa26f0835175d2200e62205b78e7ec3ffa430682e322cc91aaa1a0dbf28", size = 797579, upload-time = "2026-01-07T18:03:59.1Z" },
{ url = "https://files.pythonhosted.org/packages/e6/3a/907414a763c4270b581ad6d960d0c6221b74a70eda216a1fdd8fa82ba89f/pymongo-4.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6f2077ec24e2f1248f9cac7b9a2dfb894e50cc7939fcebfb1759f99304caabef", size = 862561, upload-time = "2026-01-07T18:04:00.628Z" },
{ url = "https://files.pythonhosted.org/packages/8c/58/787d8225dd65cb2383c447346ea5e200ecfde89962d531111521e3b53018/pymongo-4.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4d4f7ba040f72a9f43a44059872af5a8c8c660aa5d7f90d5344f2ed1c3c02721", size = 862923, upload-time = "2026-01-07T18:04:02.213Z" },
{ url = "https://files.pythonhosted.org/packages/5d/a7/cc2865aae32bc77ade7b35f957a58df52680d7f8506f93c6edbf458e5738/pymongo-4.16.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8a0f73af1ea56c422b2dcfc0437459148a799ef4231c6aee189d2d4c59d6728f", size = 1426779, upload-time = "2026-01-07T18:04:03.942Z" },
{ url = "https://files.pythonhosted.org/packages/81/25/3e96eb7998eec05382174da2fefc58d28613f46bbdf821045539d0ed60ab/pymongo-4.16.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa30cd16ddd2f216d07ba01d9635c873e97ddb041c61cf0847254edc37d1c60e", size = 1454207, upload-time = "2026-01-07T18:04:05.387Z" },
{ url = "https://files.pythonhosted.org/packages/86/7b/8e817a7df8c5d565d39dd4ca417a5e0ef46cc5cc19aea9405f403fec6449/pymongo-4.16.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d638b0b1b294d95d0fdc73688a3b61e05cc4188872818cd240d51460ccabcb5", size = 1511654, upload-time = "2026-01-07T18:04:08.458Z" },
{ url = "https://files.pythonhosted.org/packages/39/7a/50c4d075ccefcd281cdcfccc5494caa5665b096b85e65a5d6afabb80e09e/pymongo-4.16.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:21d02cc10a158daa20cb040985e280e7e439832fc6b7857bff3d53ef6914ad50", size = 1496794, upload-time = "2026-01-07T18:04:10.355Z" },
{ url = "https://files.pythonhosted.org/packages/0f/cd/ebdc1aaca5deeaf47310c369ef4083e8550e04e7bf7e3752cfb7d95fcdb8/pymongo-4.16.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4fbb8d3552c2ad99d9e236003c0b5f96d5f05e29386ba7abae73949bfebc13dd", size = 1448371, upload-time = "2026-01-07T18:04:11.76Z" },
{ url = "https://files.pythonhosted.org/packages/3d/c9/50fdd78c37f68ea49d590c027c96919fbccfd98f3a4cb39f84f79970bd37/pymongo-4.16.0-cp311-cp311-win32.whl", hash = "sha256:be1099a8295b1a722d03fb7b48be895d30f4301419a583dcf50e9045968a041c", size = 841024, upload-time = "2026-01-07T18:04:13.522Z" },
{ url = "https://files.pythonhosted.org/packages/4a/dd/a3aa1ade0cf9980744db703570afac70a62c85b432c391dea0577f6da7bb/pymongo-4.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:61567f712bda04c7545a037e3284b4367cad8d29b3dec84b4bf3b2147020a75b", size = 855838, upload-time = "2026-01-07T18:04:14.923Z" },
{ url = "https://files.pythonhosted.org/packages/bf/10/9ad82593ccb895e8722e4884bad4c5ce5e8ff6683b740d7823a6c2bcfacf/pymongo-4.16.0-cp311-cp311-win_arm64.whl", hash = "sha256:c53338613043038005bf2e41a2fafa08d29cdbc0ce80891b5366c819456c1ae9", size = 845007, upload-time = "2026-01-07T18:04:17.099Z" },
{ url = "https://files.pythonhosted.org/packages/6a/03/6dd7c53cbde98de469a3e6fb893af896dca644c476beb0f0c6342bcc368b/pymongo-4.16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bd4911c40a43a821dfd93038ac824b756b6e703e26e951718522d29f6eb166a8", size = 917619, upload-time = "2026-01-07T18:04:19.173Z" },
{ url = "https://files.pythonhosted.org/packages/73/e1/328915f2734ea1f355dc9b0e98505ff670f5fab8be5e951d6ed70971c6aa/pymongo-4.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25a6b03a68f9907ea6ec8bc7cf4c58a1b51a18e23394f962a6402f8e46d41211", size = 917364, upload-time = "2026-01-07T18:04:20.861Z" },
{ url = "https://files.pythonhosted.org/packages/41/fe/4769874dd9812a1bc2880a9785e61eba5340da966af888dd430392790ae0/pymongo-4.16.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:91ac0cb0fe2bf17616c2039dac88d7c9a5088f5cb5829b27c9d250e053664d31", size = 1686901, upload-time = "2026-01-07T18:04:22.219Z" },
{ url = "https://files.pythonhosted.org/packages/fa/8d/15707b9669fdc517bbc552ac60da7124dafe7ac1552819b51e97ed4038b4/pymongo-4.16.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cf0ec79e8ca7077f455d14d915d629385153b6a11abc0b93283ed73a8013e376", size = 1723034, upload-time = "2026-01-07T18:04:24.055Z" },
{ url = "https://files.pythonhosted.org/packages/5b/af/3d5d16ff11d447d40c1472da1b366a31c7380d7ea2922a449c7f7f495567/pymongo-4.16.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2d0082631a7510318befc2b4fdab140481eb4b9dd62d9245e042157085da2a70", size = 1797161, upload-time = "2026-01-07T18:04:25.964Z" },
{ url = "https://files.pythonhosted.org/packages/fb/04/725ab8664eeec73ec125b5a873448d80f5d8cf2750aaaf804cbc538a50a5/pymongo-4.16.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:85dc2f3444c346ea019a371e321ac868a4fab513b7a55fe368f0cc78de8177cc", size = 1780938, upload-time = "2026-01-07T18:04:28.745Z" },
{ url = "https://files.pythonhosted.org/packages/22/50/dd7e9095e1ca35f93c3c844c92eb6eb0bc491caeb2c9bff3b32fe3c9b18f/pymongo-4.16.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dabbf3c14de75a20cc3c30bf0c6527157224a93dfb605838eabb1a2ee3be008d", size = 1714342, upload-time = "2026-01-07T18:04:30.331Z" },
{ url = "https://files.pythonhosted.org/packages/03/c9/542776987d5c31ae8e93e92680ea2b6e5a2295f398b25756234cabf38a39/pymongo-4.16.0-cp312-cp312-win32.whl", hash = "sha256:60307bb91e0ab44e560fe3a211087748b2b5f3e31f403baf41f5b7b0a70bd104", size = 887868, upload-time = "2026-01-07T18:04:32.124Z" },
{ url = "https://files.pythonhosted.org/packages/2e/d4/b4045a7ccc5680fb496d01edf749c7a9367cc8762fbdf7516cf807ef679b/pymongo-4.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:f513b2c6c0d5c491f478422f6b5b5c27ac1af06a54c93ef8631806f7231bd92e", size = 907554, upload-time = "2026-01-07T18:04:33.685Z" },
{ url = "https://files.pythonhosted.org/packages/60/4c/33f75713d50d5247f2258405142c0318ff32c6f8976171c4fcae87a9dbdf/pymongo-4.16.0-cp312-cp312-win_arm64.whl", hash = "sha256:dfc320f08ea9a7ec5b2403dc4e8150636f0d6150f4b9792faaae539c88e7db3b", size = 892971, upload-time = "2026-01-07T18:04:35.594Z" },
{ url = "https://files.pythonhosted.org/packages/47/84/148d8b5da8260f4679d6665196ae04ab14ffdf06f5fe670b0ab11942951f/pymongo-4.16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d15f060bc6d0964a8bb70aba8f0cb6d11ae99715438f640cff11bbcf172eb0e8", size = 972009, upload-time = "2026-01-07T18:04:38.303Z" },
{ url = "https://files.pythonhosted.org/packages/1e/5e/9f3a8daf583d0adaaa033a3e3e58194d2282737dc164014ff33c7a081103/pymongo-4.16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4a19ea46a0fe71248965305a020bc076a163311aefbaa1d83e47d06fa30ac747", size = 971784, upload-time = "2026-01-07T18:04:39.669Z" },
{ url = "https://files.pythonhosted.org/packages/ad/f2/b6c24361fcde24946198573c0176406bfd5f7b8538335f3d939487055322/pymongo-4.16.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:311d4549d6bf1f8c61d025965aebb5ba29d1481dc6471693ab91610aaffbc0eb", size = 1947174, upload-time = "2026-01-07T18:04:41.368Z" },
{ url = "https://files.pythonhosted.org/packages/47/1a/8634192f98cf740b3d174e1018dd0350018607d5bd8ac35a666dc49c732b/pymongo-4.16.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46ffb728d92dd5b09fc034ed91acf5595657c7ca17d4cf3751322cd554153c17", size = 1991727, upload-time = "2026-01-07T18:04:42.965Z" },
{ url = "https://files.pythonhosted.org/packages/5a/2f/0c47ac84572b28e23028a23a3798a1f725e1c23b0cf1c1424678d16aff42/pymongo-4.16.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:acda193f440dd88c2023cb00aa8bd7b93a9df59978306d14d87a8b12fe426b05", size = 2082497, upload-time = "2026-01-07T18:04:44.652Z" },
{ url = "https://files.pythonhosted.org/packages/ba/57/9f46ef9c862b2f0cf5ce798f3541c201c574128d31ded407ba4b3918d7b6/pymongo-4.16.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5d9fdb386cf958e6ef6ff537d6149be7edb76c3268cd6833e6c36aa447e4443f", size = 2064947, upload-time = "2026-01-07T18:04:46.228Z" },
{ url = "https://files.pythonhosted.org/packages/b8/56/5421c0998f38e32288100a07f6cb2f5f9f352522157c901910cb2927e211/pymongo-4.16.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:91899dd7fb9a8c50f09c3c1cf0cb73bfbe2737f511f641f19b9650deb61c00ca", size = 1980478, upload-time = "2026-01-07T18:04:48.017Z" },
{ url = "https://files.pythonhosted.org/packages/92/93/bfc448d025e12313a937d6e1e0101b50cc9751636b4b170e600fe3203063/pymongo-4.16.0-cp313-cp313-win32.whl", hash = "sha256:2cd60cd1e05de7f01927f8e25ca26b3ea2c09de8723241e5d3bcfdc70eaff76b", size = 934672, upload-time = "2026-01-07T18:04:49.538Z" },
{ url = "https://files.pythonhosted.org/packages/96/10/12710a5e01218d50c3dd165fd72c5ed2699285f77348a3b1a119a191d826/pymongo-4.16.0-cp313-cp313-win_amd64.whl", hash = "sha256:3ead8a0050c53eaa55935895d6919d393d0328ec24b2b9115bdbe881aa222673", size = 959237, upload-time = "2026-01-07T18:04:51.382Z" },
{ url = "https://files.pythonhosted.org/packages/0c/56/d288bcd1d05bc17ec69df1d0b1d67bc710c7c5dbef86033a5a4d2e2b08e6/pymongo-4.16.0-cp313-cp313-win_arm64.whl", hash = "sha256:dbbc5b254c36c37d10abb50e899bc3939bbb7ab1e7c659614409af99bd3e7675", size = 940909, upload-time = "2026-01-07T18:04:52.904Z" },
{ url = "https://files.pythonhosted.org/packages/30/9e/4d343f8d0512002fce17915a89477b9f916bda1205729e042d8f23acf194/pymongo-4.16.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:8a254d49a9ffe9d7f888e3c677eed3729b14ce85abb08cd74732cead6ccc3c66", size = 1026634, upload-time = "2026-01-07T18:04:54.359Z" },
{ url = "https://files.pythonhosted.org/packages/c3/e3/341f88c5535df40c0450fda915f582757bb7d988cdfc92990a5e27c4c324/pymongo-4.16.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a1bf44e13cf2d44d2ea2e928a8140d5d667304abe1a61c4d55b4906f389fbe64", size = 1026252, upload-time = "2026-01-07T18:04:56.642Z" },
{ url = "https://files.pythonhosted.org/packages/af/64/9471b22eb98f0a2ca0b8e09393de048502111b2b5b14ab1bd9e39708aab5/pymongo-4.16.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f1c5f1f818b669875d191323a48912d3fcd2e4906410e8297bb09ac50c4d5ccc", size = 2207399, upload-time = "2026-01-07T18:04:58.255Z" },
{ url = "https://files.pythonhosted.org/packages/87/ac/47c4d50b25a02f21764f140295a2efaa583ee7f17992a5e5fa542b3a690f/pymongo-4.16.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:77cfd37a43a53b02b7bd930457c7994c924ad8bbe8dff91817904bcbf291b371", size = 2260595, upload-time = "2026-01-07T18:04:59.788Z" },
{ url = "https://files.pythonhosted.org/packages/ee/1b/0ce1ce9dd036417646b2fe6f63b58127acff3cf96eeb630c34ec9cd675ff/pymongo-4.16.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:36ef2fee50eee669587d742fb456e349634b4fcf8926208766078b089054b24b", size = 2366958, upload-time = "2026-01-07T18:05:01.942Z" },
{ url = "https://files.pythonhosted.org/packages/3e/3c/a5a17c0d413aa9d6c17bc35c2b472e9e79cda8068ba8e93433b5f43028e9/pymongo-4.16.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:55f8d5a6fe2fa0b823674db2293f92d74cd5f970bc0360f409a1fc21003862d3", size = 2346081, upload-time = "2026-01-07T18:05:03.576Z" },
{ url = "https://files.pythonhosted.org/packages/65/19/f815533d1a88fb8a3b6c6e895bb085ffdae68ccb1e6ed7102202a307f8e2/pymongo-4.16.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9caacac0dd105e2555521002e2d17afc08665187017b466b5753e84c016628e6", size = 2246053, upload-time = "2026-01-07T18:05:05.459Z" },
{ url = "https://files.pythonhosted.org/packages/c6/88/4be3ec78828dc64b212c123114bd6ae8db5b7676085a7b43cc75d0131bd2/pymongo-4.16.0-cp314-cp314-win32.whl", hash = "sha256:c789236366525c3ee3cd6e4e450a9ff629a7d1f4d88b8e18a0aea0615fd7ecf8", size = 989461, upload-time = "2026-01-07T18:05:07.018Z" },
{ url = "https://files.pythonhosted.org/packages/af/5a/ab8d5af76421b34db483c9c8ebc3a2199fb80ae63dc7e18f4cf1df46306a/pymongo-4.16.0-cp314-cp314-win_amd64.whl", hash = "sha256:2b0714d7764efb29bf9d3c51c964aed7c4c7237b341f9346f15ceaf8321fdb35", size = 1017803, upload-time = "2026-01-07T18:05:08.499Z" },
{ url = "https://files.pythonhosted.org/packages/f6/f4/98d68020728ac6423cf02d17cfd8226bf6cce5690b163d30d3f705e8297e/pymongo-4.16.0-cp314-cp314-win_arm64.whl", hash = "sha256:12762e7cc0f8374a8cae3b9f9ed8dabb5d438c7b33329232dd9b7de783454033", size = 997184, upload-time = "2026-01-07T18:05:09.944Z" },
{ url = "https://files.pythonhosted.org/packages/50/00/dc3a271daf06401825b9c1f4f76f018182c7738281ea54b9762aea0560c1/pymongo-4.16.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1c01e8a7cd0ea66baf64a118005535ab5bf9f9eb63a1b50ac3935dccf9a54abe", size = 1083303, upload-time = "2026-01-07T18:05:11.702Z" },
{ url = "https://files.pythonhosted.org/packages/b8/4b/b5375ee21d12eababe46215011ebc63801c0d2c5ffdf203849d0d79f9852/pymongo-4.16.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:4c4872299ebe315a79f7f922051061634a64fda95b6b17677ba57ef00b2ba2a4", size = 1083233, upload-time = "2026-01-07T18:05:13.182Z" },
{ url = "https://files.pythonhosted.org/packages/ee/e3/52efa3ca900622c7dcb56c5e70f15c906816d98905c22d2ee1f84d9a7b60/pymongo-4.16.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:78037d02389745e247fe5ab0bcad5d1ab30726eaac3ad79219c7d6bbb07eec53", size = 2527438, upload-time = "2026-01-07T18:05:14.981Z" },
{ url = "https://files.pythonhosted.org/packages/cb/96/43b1be151c734e7766c725444bcbfa1de6b60cc66bfb406203746839dd25/pymongo-4.16.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c126fb72be2518395cc0465d4bae03125119136462e1945aea19840e45d89cfc", size = 2600399, upload-time = "2026-01-07T18:05:16.794Z" },
{ url = "https://files.pythonhosted.org/packages/e7/62/fa64a5045dfe3a1cd9217232c848256e7bc0136cffb7da4735c5e0d30e40/pymongo-4.16.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f3867dc225d9423c245a51eaac2cfcd53dde8e0a8d8090bb6aed6e31bd6c2d4f", size = 2720960, upload-time = "2026-01-07T18:05:18.498Z" },
{ url = "https://files.pythonhosted.org/packages/54/7b/01577eb97e605502821273a5bc16ce0fb0be5c978fe03acdbff471471202/pymongo-4.16.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f25001a955073b80510c0c3db0e043dbbc36904fd69e511c74e3d8640b8a5111", size = 2699344, upload-time = "2026-01-07T18:05:20.073Z" },
{ url = "https://files.pythonhosted.org/packages/55/68/6ef6372d516f703479c3b6cbbc45a5afd307173b1cbaccd724e23919bb1a/pymongo-4.16.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d9885aad05f82fd7ea0c9ca505d60939746b39263fa273d0125170da8f59098", size = 2577133, upload-time = "2026-01-07T18:05:22.052Z" },
{ url = "https://files.pythonhosted.org/packages/15/c7/b5337093bb01da852f945802328665f85f8109dbe91d81ea2afe5ff059b9/pymongo-4.16.0-cp314-cp314t-win32.whl", hash = "sha256:948152b30eddeae8355495f9943a3bf66b708295c0b9b6f467de1c620f215487", size = 1040560, upload-time = "2026-01-07T18:05:23.888Z" },
{ url = "https://files.pythonhosted.org/packages/96/8c/5b448cd1b103f3889d5713dda37304c81020ff88e38a826e8a75ddff4610/pymongo-4.16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f6e42c1bc985d9beee884780ae6048790eb4cd565c46251932906bdb1630034a", size = 1075081, upload-time = "2026-01-07T18:05:26.874Z" },
{ url = "https://files.pythonhosted.org/packages/32/cd/ddc794cdc8500f6f28c119c624252fb6dfb19481c6d7ed150f13cf468a6d/pymongo-4.16.0-cp314-cp314t-win_arm64.whl", hash = "sha256:6b2a20edb5452ac8daa395890eeb076c570790dfce6b7a44d788af74c2f8cf96", size = 1047725, upload-time = "2026-01-07T18:05:28.47Z" },
]
[[package]]
name = "pytest"
version = "7.4.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
{ name = "iniconfig" },
{ name = "packaging" },
{ name = "pluggy" },
{ name = "tomli", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/80/1f/9d8e98e4133ffb16c90f3b405c43e38d3abb715bb5d7a63a5a684f7e46a3/pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280", size = 1357116, upload-time = "2023-12-31T12:00:18.035Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8", size = 325287, upload-time = "2023-12-31T12:00:13.963Z" },
]
[[package]]
name = "pytest-cov"
version = "4.1.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "coverage", extra = ["toml"] },
{ name = "pytest" },
]
sdist = { url = "https://files.pythonhosted.org/packages/7a/15/da3df99fd551507694a9b01f512a2f6cf1254f33601605843c3775f39460/pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6", size = 63245, upload-time = "2023-05-24T18:44:56.845Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a7/4b/8b78d126e275efa2379b1c2e09dc52cf70df16fc3b90613ef82531499d73/pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a", size = 21949, upload-time = "2023-05-24T18:44:54.079Z" },
]
[[package]]
name = "pytest-django"
version = "4.12.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pytest" },
]
sdist = { url = "https://files.pythonhosted.org/packages/13/2b/db9a193df89e5660137f5428063bcc2ced7ad790003b26974adf5c5ceb3b/pytest_django-4.12.0.tar.gz", hash = "sha256:df94ec819a83c8979c8f6de13d9cdfbe76e8c21d39473cfe2b40c9fc9be3c758", size = 91156, upload-time = "2026-02-14T18:40:49.235Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/83/a5/41d091f697c09609e7ef1d5d61925494e0454ebf51de7de05f0f0a728f1d/pytest_django-4.12.0-py3-none-any.whl", hash = "sha256:3ff300c49f8350ba2953b90297d23bf5f589db69545f56f1ec5f8cff5da83e85", size = 26123, upload-time = "2026-02-14T18:40:47.381Z" },
]
[[package]]
name = "python-dateutil"
version = "2.9.0.post0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "six" },
]
sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
]
[[package]]
name = "pytz"
version = "2025.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" },
]
[[package]]
name = "redis"
version = "4.6.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "async-timeout", marker = "python_full_version <= '3.11.2'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/73/88/63d802c2b18dd9eaa5b846cbf18917c6b2882f20efda398cc16a7500b02c/redis-4.6.0.tar.gz", hash = "sha256:585dc516b9eb042a619ef0a39c3d7d55fe81bdb4df09a52c9cdde0d07bf1aa7d", size = 4561721, upload-time = "2023-06-25T13:13:57.139Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/20/2e/409703d645363352a20c944f5d119bdae3eb3034051a53724a7c5fee12b8/redis-4.6.0-py3-none-any.whl", hash = "sha256:e2b03db868160ee4591de3cb90d40ebb50a90dd302138775937f6a42b7ed183c", size = 241149, upload-time = "2023-06-25T13:13:54.563Z" },
]
[[package]]
name = "requests"
version = "2.32.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "certifi" },
{ name = "charset-normalizer" },
{ name = "idna" },
{ name = "urllib3" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" },
]
[[package]]
name = "ruff"
version = "0.4.10"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ea/04/b660bc832ebfa40e1788edf6934388340751cbc6f733d1f807edca9d96e6/ruff-0.4.10.tar.gz", hash = "sha256:3aa4f2bc388a30d346c56524f7cacca85945ba124945fe489952aadb6b5cd804", size = 2577674, upload-time = "2024-06-20T17:42:56.184Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/53/0d/134fdd72f566d37b0c59b6e55f60993c705f93a0fe3c1faa6f8a269057c7/ruff-0.4.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5c2c4d0859305ac5a16310eec40e4e9a9dec5dcdfbe92697acd99624e8638dac", size = 8510271, upload-time = "2024-06-20T17:41:49.591Z" },
{ url = "https://files.pythonhosted.org/packages/46/5e/4ac799ffec39ef5012052c1f144a0f7a63a0322ebd328b802d64beb3d091/ruff-0.4.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a79489607d1495685cdd911a323a35871abfb7a95d4f98fc6f85e799227ac46e", size = 8107776, upload-time = "2024-06-20T17:41:55.14Z" },
{ url = "https://files.pythonhosted.org/packages/78/6f/37af054d3ced5a6196201f6c248eeaec6b3b844136cf3da510d591dbfd89/ruff-0.4.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1dd1681dfa90a41b8376a61af05cc4dc5ff32c8f14f5fe20dba9ff5deb80cd6", size = 9868358, upload-time = "2024-06-20T17:41:58.162Z" },
{ url = "https://files.pythonhosted.org/packages/c7/38/070baf0393ba0da9d85409bdd63874776926acfc372e8e9f0ed21957aeee/ruff-0.4.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c75c53bb79d71310dc79fb69eb4902fba804a81f374bc86a9b117a8d077a1784", size = 9172824, upload-time = "2024-06-20T17:42:02.386Z" },
{ url = "https://files.pythonhosted.org/packages/e7/9d/bad51d81c918e1ce1648b24480a63f5605662efe69b55fad05825b5711ff/ruff-0.4.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18238c80ee3d9100d3535d8eb15a59c4a0753b45cc55f8bf38f38d6a597b9739", size = 9997887, upload-time = "2024-06-20T17:42:06.309Z" },
{ url = "https://files.pythonhosted.org/packages/ec/a4/1310b3d003cb67f3c86cb8cc5c5e475dab152b1eef88558abd11e55daaad/ruff-0.4.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d8f71885bce242da344989cae08e263de29752f094233f932d4f5cfb4ef36a81", size = 10743762, upload-time = "2024-06-20T17:42:11.13Z" },
{ url = "https://files.pythonhosted.org/packages/b8/c1/5373bc5a4c3782c0a368ce5ca4ec3a689574daf71f68f55720a6a64321d4/ruff-0.4.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:330421543bd3222cdfec481e8ff3460e8702ed1e58b494cf9d9e4bf90db52b9d", size = 10329524, upload-time = "2024-06-20T17:42:15.294Z" },
{ url = "https://files.pythonhosted.org/packages/48/dc/2c057e7717a3eaaa89ea848a26ef085930a2509f9b66ceae55319668c03d/ruff-0.4.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e9b6fb3a37b772628415b00c4fc892f97954275394ed611056a4b8a2631365e", size = 11208593, upload-time = "2024-06-20T17:42:20.077Z" },
{ url = "https://files.pythonhosted.org/packages/11/c3/3f89b1e967a869642bd9198f27e2b89b8300862555d3e1e39b4ccaf92e8b/ruff-0.4.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f54c481b39a762d48f64d97351048e842861c6662d63ec599f67d515cb417f6", size = 10041835, upload-time = "2024-06-20T17:42:24.487Z" },
{ url = "https://files.pythonhosted.org/packages/d0/e6/734aed23112de8df5a2f3bc02e9e45cd3910fe83b0d2bb2456e200c52d98/ruff-0.4.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:67fe086b433b965c22de0b4259ddfe6fa541c95bf418499bedb9ad5fb8d1c631", size = 9842683, upload-time = "2024-06-20T17:42:28.324Z" },
{ url = "https://files.pythonhosted.org/packages/cf/13/bc788b2e21d3e4db74d1375da22f50f944bc1fef064c4749f307b0c8794f/ruff-0.4.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:acfaaab59543382085f9eb51f8e87bac26bf96b164839955f244d07125a982ef", size = 9283929, upload-time = "2024-06-20T17:42:32.221Z" },
{ url = "https://files.pythonhosted.org/packages/f0/09/f3c6560f9d81a4c5d800996090c9cc54d794ea14ab8f8af46b7483005963/ruff-0.4.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3cea07079962b2941244191569cf3a05541477286f5cafea638cd3aa94b56815", size = 9617526, upload-time = "2024-06-20T17:42:36.588Z" },
{ url = "https://files.pythonhosted.org/packages/d3/9e/11ae4e8587efe40aa083835665d0818626f8f4a10aa4ebc097cdbfae7624/ruff-0.4.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:338a64ef0748f8c3a80d7f05785930f7965d71ca260904a9321d13be24b79695", size = 10114053, upload-time = "2024-06-20T17:42:41.144Z" },
{ url = "https://files.pythonhosted.org/packages/e8/94/3bb62a0086e9c61d0506e546e7cf68456fd93bf569a8adfa5e324812970d/ruff-0.4.10-py3-none-win32.whl", hash = "sha256:ffe3cd2f89cb54561c62e5fa20e8f182c0a444934bf430515a4b422f1ab7b7ca", size = 7707741, upload-time = "2024-06-20T17:42:45.061Z" },
{ url = "https://files.pythonhosted.org/packages/d8/4e/6fd32ebd0a09f25ed9911b77c5273b7a6b3b50a78d6ed0508d66a24398b8/ruff-0.4.10-py3-none-win_amd64.whl", hash = "sha256:67f67cef43c55ffc8cc59e8e0b97e9e60b4837c8f21e8ab5ffd5d66e196e25f7", size = 8519153, upload-time = "2024-06-20T17:42:48.907Z" },
{ url = "https://files.pythonhosted.org/packages/dc/78/5109b7db3b44a64157b025e45eec6591e4beb53732104637d8e0ee0c5570/ruff-0.4.10-py3-none-win_arm64.whl", hash = "sha256:dd1fcee327c20addac7916ca4e2653fbbf2e8388d8a6477ce5b4e986b68ae6c0", size = 7906942, upload-time = "2024-06-20T17:42:52.972Z" },
]
[[package]]
name = "s3transfer"
version = "0.16.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "botocore" },
]
sdist = { url = "https://files.pythonhosted.org/packages/05/04/74127fc843314818edfa81b5540e26dd537353b123a4edc563109d8f17dd/s3transfer-0.16.0.tar.gz", hash = "sha256:8e990f13268025792229cd52fa10cb7163744bf56e719e0b9cb925ab79abf920", size = 153827, upload-time = "2025-12-01T02:30:59.114Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/fc/51/727abb13f44c1fcf6d145979e1535a35794db0f6e450a0cb46aa24732fe2/s3transfer-0.16.0-py3-none-any.whl", hash = "sha256:18e25d66fed509e3868dc1572b3f427ff947dd2c56f844a5bf09481ad3f3b2fe", size = 86830, upload-time = "2025-12-01T02:30:57.729Z" },
]
[[package]]
name = "setproctitle"
version = "1.3.7"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/8d/48/49393a96a2eef1ab418b17475fb92b8fcfad83d099e678751b05472e69de/setproctitle-1.3.7.tar.gz", hash = "sha256:bc2bc917691c1537d5b9bca1468437176809c7e11e5694ca79a9ca12345dcb9e", size = 27002, upload-time = "2025-09-05T12:51:25.278Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f2/48/fb401ec8c4953d519d05c87feca816ad668b8258448ff60579ac7a1c1386/setproctitle-1.3.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cf555b6299f10a6eb44e4f96d2f5a3884c70ce25dc5c8796aaa2f7b40e72cb1b", size = 18079, upload-time = "2025-09-05T12:49:07.732Z" },
{ url = "https://files.pythonhosted.org/packages/cc/a3/c2b0333c2716fb3b4c9a973dd113366ac51b4f8d56b500f4f8f704b4817a/setproctitle-1.3.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:690b4776f9c15aaf1023bb07d7c5b797681a17af98a4a69e76a1d504e41108b7", size = 13099, upload-time = "2025-09-05T12:49:09.222Z" },
{ url = "https://files.pythonhosted.org/packages/0e/f8/17bda581c517678260e6541b600eeb67745f53596dc077174141ba2f6702/setproctitle-1.3.7-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:00afa6fc507967d8c9d592a887cdc6c1f5742ceac6a4354d111ca0214847732c", size = 31793, upload-time = "2025-09-05T12:49:10.297Z" },
{ url = "https://files.pythonhosted.org/packages/27/d1/76a33ae80d4e788ecab9eb9b53db03e81cfc95367ec7e3fbf4989962fedd/setproctitle-1.3.7-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9e02667f6b9fc1238ba753c0f4b0a37ae184ce8f3bbbc38e115d99646b3f4cd3", size = 32779, upload-time = "2025-09-05T12:49:12.157Z" },
{ url = "https://files.pythonhosted.org/packages/59/27/1a07c38121967061564f5e0884414a5ab11a783260450172d4fc68c15621/setproctitle-1.3.7-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:83fcd271567d133eb9532d3b067c8a75be175b2b3b271e2812921a05303a693f", size = 34578, upload-time = "2025-09-05T12:49:13.393Z" },
{ url = "https://files.pythonhosted.org/packages/d8/d4/725e6353935962d8bb12cbf7e7abba1d0d738c7f6935f90239d8e1ccf913/setproctitle-1.3.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13fe37951dda1a45c35d77d06e3da5d90e4f875c4918a7312b3b4556cfa7ff64", size = 32030, upload-time = "2025-09-05T12:49:15.362Z" },
{ url = "https://files.pythonhosted.org/packages/67/24/e4677ae8e1cb0d549ab558b12db10c175a889be0974c589c428fece5433e/setproctitle-1.3.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a05509cfb2059e5d2ddff701d38e474169e9ce2a298cf1b6fd5f3a213a553fe5", size = 33363, upload-time = "2025-09-05T12:49:16.829Z" },
{ url = "https://files.pythonhosted.org/packages/55/d4/69ce66e4373a48fdbb37489f3ded476bb393e27f514968c3a69a67343ae0/setproctitle-1.3.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6da835e76ae18574859224a75db6e15c4c2aaa66d300a57efeaa4c97ca4c7381", size = 31508, upload-time = "2025-09-05T12:49:18.032Z" },
{ url = "https://files.pythonhosted.org/packages/4b/5a/42c1ed0e9665d068146a68326529b5686a1881c8b9197c2664db4baf6aeb/setproctitle-1.3.7-cp310-cp310-win32.whl", hash = "sha256:9e803d1b1e20240a93bac0bc1025363f7f80cb7eab67dfe21efc0686cc59ad7c", size = 12558, upload-time = "2025-09-05T12:49:19.742Z" },
{ url = "https://files.pythonhosted.org/packages/dc/fe/dd206cc19a25561921456f6cb12b405635319299b6f366e0bebe872abc18/setproctitle-1.3.7-cp310-cp310-win_amd64.whl", hash = "sha256:a97200acc6b64ec4cada52c2ecaf1fba1ef9429ce9c542f8a7db5bcaa9dcbd95", size = 13245, upload-time = "2025-09-05T12:49:21.023Z" },
{ url = "https://files.pythonhosted.org/packages/04/cd/1b7ba5cad635510720ce19d7122154df96a2387d2a74217be552887c93e5/setproctitle-1.3.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a600eeb4145fb0ee6c287cb82a2884bd4ec5bbb076921e287039dcc7b7cc6dd0", size = 18085, upload-time = "2025-09-05T12:49:22.183Z" },
{ url = "https://files.pythonhosted.org/packages/8f/1a/b2da0a620490aae355f9d72072ac13e901a9fec809a6a24fc6493a8f3c35/setproctitle-1.3.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:97a090fed480471bb175689859532709e28c085087e344bca45cf318034f70c4", size = 13097, upload-time = "2025-09-05T12:49:23.322Z" },
{ url = "https://files.pythonhosted.org/packages/18/2e/bd03ff02432a181c1787f6fc2a678f53b7dacdd5ded69c318fe1619556e8/setproctitle-1.3.7-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1607b963e7b53e24ec8a2cb4e0ab3ae591d7c6bf0a160feef0551da63452b37f", size = 32191, upload-time = "2025-09-05T12:49:24.567Z" },
{ url = "https://files.pythonhosted.org/packages/28/78/1e62fc0937a8549f2220445ed2175daacee9b6764c7963b16148119b016d/setproctitle-1.3.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a20fb1a3974e2dab857870cf874b325b8705605cb7e7e8bcbb915bca896f52a9", size = 33203, upload-time = "2025-09-05T12:49:25.871Z" },
{ url = "https://files.pythonhosted.org/packages/a0/3c/65edc65db3fa3df400cf13b05e9d41a3c77517b4839ce873aa6b4043184f/setproctitle-1.3.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f8d961bba676e07d77665204f36cffaa260f526e7b32d07ab3df6a2c1dfb44ba", size = 34963, upload-time = "2025-09-05T12:49:27.044Z" },
{ url = "https://files.pythonhosted.org/packages/a1/32/89157e3de997973e306e44152522385f428e16f92f3cf113461489e1e2ee/setproctitle-1.3.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:db0fd964fbd3a9f8999b502f65bd2e20883fdb5b1fae3a424e66db9a793ed307", size = 32398, upload-time = "2025-09-05T12:49:28.909Z" },
{ url = "https://files.pythonhosted.org/packages/4a/18/77a765a339ddf046844cb4513353d8e9dcd8183da9cdba6e078713e6b0b2/setproctitle-1.3.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:db116850fcf7cca19492030f8d3b4b6e231278e8fe097a043957d22ce1bdf3ee", size = 33657, upload-time = "2025-09-05T12:49:30.323Z" },
{ url = "https://files.pythonhosted.org/packages/6b/63/f0b6205c64d74d2a24a58644a38ec77bdbaa6afc13747e75973bf8904932/setproctitle-1.3.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:316664d8b24a5c91ee244460bdaf7a74a707adaa9e14fbe0dc0a53168bb9aba1", size = 31836, upload-time = "2025-09-05T12:49:32.309Z" },
{ url = "https://files.pythonhosted.org/packages/ba/51/e1277f9ba302f1a250bbd3eedbbee747a244b3cc682eb58fb9733968f6d8/setproctitle-1.3.7-cp311-cp311-win32.whl", hash = "sha256:b74774ca471c86c09b9d5037c8451fff06bb82cd320d26ae5a01c758088c0d5d", size = 12556, upload-time = "2025-09-05T12:49:33.529Z" },
{ url = "https://files.pythonhosted.org/packages/b6/7b/822a23f17e9003dfdee92cd72758441ca2a3680388da813a371b716fb07f/setproctitle-1.3.7-cp311-cp311-win_amd64.whl", hash = "sha256:acb9097213a8dd3410ed9f0dc147840e45ca9797785272928d4be3f0e69e3be4", size = 13243, upload-time = "2025-09-05T12:49:34.553Z" },
{ url = "https://files.pythonhosted.org/packages/fb/f0/2dc88e842077719d7384d86cc47403e5102810492b33680e7dadcee64cd8/setproctitle-1.3.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2dc99aec591ab6126e636b11035a70991bc1ab7a261da428491a40b84376654e", size = 18049, upload-time = "2025-09-05T12:49:36.241Z" },
{ url = "https://files.pythonhosted.org/packages/f0/b4/50940504466689cda65680c9e9a1e518e5750c10490639fa687489ac7013/setproctitle-1.3.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cdd8aa571b7aa39840fdbea620e308a19691ff595c3a10231e9ee830339dd798", size = 13079, upload-time = "2025-09-05T12:49:38.088Z" },
{ url = "https://files.pythonhosted.org/packages/d0/99/71630546b9395b095f4082be41165d1078204d1696c2d9baade3de3202d0/setproctitle-1.3.7-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2906b6c7959cdb75f46159bf0acd8cc9906cf1361c9e1ded0d065fe8f9039629", size = 32932, upload-time = "2025-09-05T12:49:39.271Z" },
{ url = "https://files.pythonhosted.org/packages/50/22/cee06af4ffcfb0e8aba047bd44f5262e644199ae7527ae2c1f672b86495c/setproctitle-1.3.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6915964a6dda07920a1159321dcd6d94fc7fc526f815ca08a8063aeca3c204f1", size = 33736, upload-time = "2025-09-05T12:49:40.565Z" },
{ url = "https://files.pythonhosted.org/packages/5c/00/a5949a8bb06ef5e7df214fc393bb2fb6aedf0479b17214e57750dfdd0f24/setproctitle-1.3.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cff72899861c765bd4021d1ff1c68d60edc129711a2fdba77f9cb69ef726a8b6", size = 35605, upload-time = "2025-09-05T12:49:42.362Z" },
{ url = "https://files.pythonhosted.org/packages/b0/3a/50caca532a9343828e3bf5778c7a84d6c737a249b1796d50dd680290594d/setproctitle-1.3.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b7cb05bd446687ff816a3aaaf831047fc4c364feff7ada94a66024f1367b448c", size = 33143, upload-time = "2025-09-05T12:49:43.515Z" },
{ url = "https://files.pythonhosted.org/packages/ca/14/b843a251296ce55e2e17c017d6b9f11ce0d3d070e9265de4ecad948b913d/setproctitle-1.3.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3a57b9a00de8cae7e2a1f7b9f0c2ac7b69372159e16a7708aa2f38f9e5cc987a", size = 34434, upload-time = "2025-09-05T12:49:45.31Z" },
{ url = "https://files.pythonhosted.org/packages/c8/b7/06145c238c0a6d2c4bc881f8be230bb9f36d2bf51aff7bddcb796d5eed67/setproctitle-1.3.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d8828b356114f6b308b04afe398ed93803d7fca4a955dd3abe84430e28d33739", size = 32795, upload-time = "2025-09-05T12:49:46.419Z" },
{ url = "https://files.pythonhosted.org/packages/ef/dc/ef76a81fac9bf27b84ed23df19c1f67391a753eed6e3c2254ebcb5133f56/setproctitle-1.3.7-cp312-cp312-win32.whl", hash = "sha256:b0304f905efc845829ac2bc791ddebb976db2885f6171f4a3de678d7ee3f7c9f", size = 12552, upload-time = "2025-09-05T12:49:47.635Z" },
{ url = "https://files.pythonhosted.org/packages/e2/5b/a9fe517912cd6e28cf43a212b80cb679ff179a91b623138a99796d7d18a0/setproctitle-1.3.7-cp312-cp312-win_amd64.whl", hash = "sha256:9888ceb4faea3116cf02a920ff00bfbc8cc899743e4b4ac914b03625bdc3c300", size = 13247, upload-time = "2025-09-05T12:49:49.16Z" },
{ url = "https://files.pythonhosted.org/packages/5d/2f/fcedcade3b307a391b6e17c774c6261a7166aed641aee00ed2aad96c63ce/setproctitle-1.3.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c3736b2a423146b5e62230502e47e08e68282ff3b69bcfe08a322bee73407922", size = 18047, upload-time = "2025-09-05T12:49:50.271Z" },
{ url = "https://files.pythonhosted.org/packages/23/ae/afc141ca9631350d0a80b8f287aac79a76f26b6af28fd8bf92dae70dc2c5/setproctitle-1.3.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3384e682b158d569e85a51cfbde2afd1ab57ecf93ea6651fe198d0ba451196ee", size = 13073, upload-time = "2025-09-05T12:49:51.46Z" },
{ url = "https://files.pythonhosted.org/packages/87/ed/0a4f00315bc02510395b95eec3d4aa77c07192ee79f0baae77ea7b9603d8/setproctitle-1.3.7-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0564a936ea687cd24dffcea35903e2a20962aa6ac20e61dd3a207652401492dd", size = 33284, upload-time = "2025-09-05T12:49:52.741Z" },
{ url = "https://files.pythonhosted.org/packages/fc/e4/adf3c4c0a2173cb7920dc9df710bcc67e9bcdbf377e243b7a962dc31a51a/setproctitle-1.3.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a5d1cb3f81531f0eb40e13246b679a1bdb58762b170303463cb06ecc296f26d0", size = 34104, upload-time = "2025-09-05T12:49:54.416Z" },
{ url = "https://files.pythonhosted.org/packages/52/4f/6daf66394152756664257180439d37047aa9a1cfaa5e4f5ed35e93d1dc06/setproctitle-1.3.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a7d159e7345f343b44330cbba9194169b8590cb13dae940da47aa36a72aa9929", size = 35982, upload-time = "2025-09-05T12:49:56.295Z" },
{ url = "https://files.pythonhosted.org/packages/1b/62/f2c0595403cf915db031f346b0e3b2c0096050e90e0be658a64f44f4278a/setproctitle-1.3.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0b5074649797fd07c72ca1f6bff0406f4a42e1194faac03ecaab765ce605866f", size = 33150, upload-time = "2025-09-05T12:49:58.025Z" },
{ url = "https://files.pythonhosted.org/packages/a0/29/10dd41cde849fb2f9b626c846b7ea30c99c81a18a5037a45cc4ba33c19a7/setproctitle-1.3.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:61e96febced3f61b766115381d97a21a6265a0f29188a791f6df7ed777aef698", size = 34463, upload-time = "2025-09-05T12:49:59.424Z" },
{ url = "https://files.pythonhosted.org/packages/71/3c/cedd8eccfaf15fb73a2c20525b68c9477518917c9437737fa0fda91e378f/setproctitle-1.3.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:047138279f9463f06b858e579cc79580fbf7a04554d24e6bddf8fe5dddbe3d4c", size = 32848, upload-time = "2025-09-05T12:50:01.107Z" },
{ url = "https://files.pythonhosted.org/packages/d1/3e/0a0e27d1c9926fecccfd1f91796c244416c70bf6bca448d988638faea81d/setproctitle-1.3.7-cp313-cp313-win32.whl", hash = "sha256:7f47accafac7fe6535ba8ba9efd59df9d84a6214565108d0ebb1199119c9cbbd", size = 12544, upload-time = "2025-09-05T12:50:15.81Z" },
{ url = "https://files.pythonhosted.org/packages/36/1b/6bf4cb7acbbd5c846ede1c3f4d6b4ee52744d402e43546826da065ff2ab7/setproctitle-1.3.7-cp313-cp313-win_amd64.whl", hash = "sha256:fe5ca35aeec6dc50cabab9bf2d12fbc9067eede7ff4fe92b8f5b99d92e21263f", size = 13235, upload-time = "2025-09-05T12:50:16.89Z" },
{ url = "https://files.pythonhosted.org/packages/e6/a4/d588d3497d4714750e3eaf269e9e8985449203d82b16b933c39bd3fc52a1/setproctitle-1.3.7-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:10e92915c4b3086b1586933a36faf4f92f903c5554f3c34102d18c7d3f5378e9", size = 18058, upload-time = "2025-09-05T12:50:02.501Z" },
{ url = "https://files.pythonhosted.org/packages/05/77/7637f7682322a7244e07c373881c7e982567e2cb1dd2f31bd31481e45500/setproctitle-1.3.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:de879e9c2eab637f34b1a14c4da1e030c12658cdc69ee1b3e5be81b380163ce5", size = 13072, upload-time = "2025-09-05T12:50:03.601Z" },
{ url = "https://files.pythonhosted.org/packages/52/09/f366eca0973cfbac1470068d1313fa3fe3de4a594683385204ec7f1c4101/setproctitle-1.3.7-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c18246d88e227a5b16248687514f95642505000442165f4b7db354d39d0e4c29", size = 34490, upload-time = "2025-09-05T12:50:04.948Z" },
{ url = "https://files.pythonhosted.org/packages/71/36/611fc2ed149fdea17c3677e1d0df30d8186eef9562acc248682b91312706/setproctitle-1.3.7-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7081f193dab22df2c36f9fc6d113f3793f83c27891af8fe30c64d89d9a37e152", size = 35267, upload-time = "2025-09-05T12:50:06.015Z" },
{ url = "https://files.pythonhosted.org/packages/88/a4/64e77d0671446bd5a5554387b69e1efd915274686844bea733714c828813/setproctitle-1.3.7-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9cc9b901ce129350637426a89cfd650066a4adc6899e47822e2478a74023ff7c", size = 37376, upload-time = "2025-09-05T12:50:07.484Z" },
{ url = "https://files.pythonhosted.org/packages/89/bc/ad9c664fe524fb4a4b2d3663661a5c63453ce851736171e454fa2cdec35c/setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:80e177eff2d1ec172188d0d7fd9694f8e43d3aab76a6f5f929bee7bf7894e98b", size = 33963, upload-time = "2025-09-05T12:50:09.056Z" },
{ url = "https://files.pythonhosted.org/packages/ab/01/a36de7caf2d90c4c28678da1466b47495cbbad43badb4e982d8db8167ed4/setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:23e520776c445478a67ee71b2a3c1ffdafbe1f9f677239e03d7e2cc635954e18", size = 35550, upload-time = "2025-09-05T12:50:10.791Z" },
{ url = "https://files.pythonhosted.org/packages/dd/68/17e8aea0ed5ebc17fbf03ed2562bfab277c280e3625850c38d92a7b5fcd9/setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5fa1953126a3b9bd47049d58c51b9dac72e78ed120459bd3aceb1bacee72357c", size = 33727, upload-time = "2025-09-05T12:50:12.032Z" },
{ url = "https://files.pythonhosted.org/packages/b2/33/90a3bf43fe3a2242b4618aa799c672270250b5780667898f30663fd94993/setproctitle-1.3.7-cp313-cp313t-win32.whl", hash = "sha256:4a5e212bf438a4dbeece763f4962ad472c6008ff6702e230b4f16a037e2f6f29", size = 12549, upload-time = "2025-09-05T12:50:13.074Z" },
{ url = "https://files.pythonhosted.org/packages/0b/0e/50d1f07f3032e1f23d814ad6462bc0a138f369967c72494286b8a5228e40/setproctitle-1.3.7-cp313-cp313t-win_amd64.whl", hash = "sha256:cf2727b733e90b4f874bac53e3092aa0413fe1ea6d4f153f01207e6ce65034d9", size = 13243, upload-time = "2025-09-05T12:50:14.146Z" },
{ url = "https://files.pythonhosted.org/packages/89/c7/43ac3a98414f91d1b86a276bc2f799ad0b4b010e08497a95750d5bc42803/setproctitle-1.3.7-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:80c36c6a87ff72eabf621d0c79b66f3bdd0ecc79e873c1e9f0651ee8bf215c63", size = 18052, upload-time = "2025-09-05T12:50:17.928Z" },
{ url = "https://files.pythonhosted.org/packages/cd/2c/dc258600a25e1a1f04948073826bebc55e18dbd99dc65a576277a82146fa/setproctitle-1.3.7-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b53602371a52b91c80aaf578b5ada29d311d12b8a69c0c17fbc35b76a1fd4f2e", size = 13071, upload-time = "2025-09-05T12:50:19.061Z" },
{ url = "https://files.pythonhosted.org/packages/ab/26/8e3bb082992f19823d831f3d62a89409deb6092e72fc6940962983ffc94f/setproctitle-1.3.7-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fcb966a6c57cf07cc9448321a08f3be6b11b7635be502669bc1d8745115d7e7f", size = 33180, upload-time = "2025-09-05T12:50:20.395Z" },
{ url = "https://files.pythonhosted.org/packages/f1/af/ae692a20276d1159dd0cf77b0bcf92cbb954b965655eb4a69672099bb214/setproctitle-1.3.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46178672599b940368d769474fe13ecef1b587d58bb438ea72b9987f74c56ea5", size = 34043, upload-time = "2025-09-05T12:50:22.454Z" },
{ url = "https://files.pythonhosted.org/packages/34/b2/6a092076324dd4dac1a6d38482bedebbff5cf34ef29f58585ec76e47bc9d/setproctitle-1.3.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7f9e9e3ff135cbcc3edd2f4cf29b139f4aca040d931573102742db70ff428c17", size = 35892, upload-time = "2025-09-05T12:50:23.937Z" },
{ url = "https://files.pythonhosted.org/packages/1c/1a/8836b9f28cee32859ac36c3df85aa03e1ff4598d23ea17ca2e96b5845a8f/setproctitle-1.3.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:14c7eba8d90c93b0e79c01f0bd92a37b61983c27d6d7d5a3b5defd599113d60e", size = 32898, upload-time = "2025-09-05T12:50:25.617Z" },
{ url = "https://files.pythonhosted.org/packages/ef/22/8fabdc24baf42defb599714799d8445fe3ae987ec425a26ec8e80ea38f8e/setproctitle-1.3.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:9e64e98077fb30b6cf98073d6c439cd91deb8ebbf8fc62d9dbf52bd38b0c6ac0", size = 34308, upload-time = "2025-09-05T12:50:26.827Z" },
{ url = "https://files.pythonhosted.org/packages/15/1b/b9bee9de6c8cdcb3b3a6cb0b3e773afdb86bbbc1665a3bfa424a4294fda2/setproctitle-1.3.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b91387cc0f02a00ac95dcd93f066242d3cca10ff9e6153de7ee07069c6f0f7c8", size = 32536, upload-time = "2025-09-05T12:50:28.5Z" },
{ url = "https://files.pythonhosted.org/packages/37/0c/75e5f2685a5e3eda0b39a8b158d6d8895d6daf3ba86dec9e3ba021510272/setproctitle-1.3.7-cp314-cp314-win32.whl", hash = "sha256:52b054a61c99d1b72fba58b7f5486e04b20fefc6961cd76722b424c187f362ed", size = 12731, upload-time = "2025-09-05T12:50:43.955Z" },
{ url = "https://files.pythonhosted.org/packages/d2/ae/acddbce90d1361e1786e1fb421bc25baeb0c22ef244ee5d0176511769ec8/setproctitle-1.3.7-cp314-cp314-win_amd64.whl", hash = "sha256:5818e4080ac04da1851b3ec71e8a0f64e3748bf9849045180566d8b736702416", size = 13464, upload-time = "2025-09-05T12:50:45.057Z" },
{ url = "https://files.pythonhosted.org/packages/01/6d/20886c8ff2e6d85e3cabadab6aab9bb90acaf1a5cfcb04d633f8d61b2626/setproctitle-1.3.7-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:6fc87caf9e323ac426910306c3e5d3205cd9f8dcac06d233fcafe9337f0928a3", size = 18062, upload-time = "2025-09-05T12:50:29.78Z" },
{ url = "https://files.pythonhosted.org/packages/9a/60/26dfc5f198715f1343b95c2f7a1c16ae9ffa45bd89ffd45a60ed258d24ea/setproctitle-1.3.7-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6134c63853d87a4897ba7d5cc0e16abfa687f6c66fc09f262bb70d67718f2309", size = 13075, upload-time = "2025-09-05T12:50:31.604Z" },
{ url = "https://files.pythonhosted.org/packages/21/9c/980b01f50d51345dd513047e3ba9e96468134b9181319093e61db1c47188/setproctitle-1.3.7-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1403d2abfd32790b6369916e2313dffbe87d6b11dca5bbd898981bcde48e7a2b", size = 34744, upload-time = "2025-09-05T12:50:32.777Z" },
{ url = "https://files.pythonhosted.org/packages/86/b4/82cd0c86e6d1c4538e1a7eb908c7517721513b801dff4ba3f98ef816a240/setproctitle-1.3.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e7c5bfe4228ea22373e3025965d1a4116097e555ee3436044f5c954a5e63ac45", size = 35589, upload-time = "2025-09-05T12:50:34.13Z" },
{ url = "https://files.pythonhosted.org/packages/8a/4f/9f6b2a7417fd45673037554021c888b31247f7594ff4bd2239918c5cd6d0/setproctitle-1.3.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:585edf25e54e21a94ccb0fe81ad32b9196b69ebc4fc25f81da81fb8a50cca9e4", size = 37698, upload-time = "2025-09-05T12:50:35.524Z" },
{ url = "https://files.pythonhosted.org/packages/20/92/927b7d4744aac214d149c892cb5fa6dc6f49cfa040cb2b0a844acd63dcaf/setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:96c38cdeef9036eb2724c2210e8d0b93224e709af68c435d46a4733a3675fee1", size = 34201, upload-time = "2025-09-05T12:50:36.697Z" },
{ url = "https://files.pythonhosted.org/packages/0a/0c/fd4901db5ba4b9d9013e62f61d9c18d52290497f956745cd3e91b0d80f90/setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:45e3ef48350abb49cf937d0a8ba15e42cee1e5ae13ca41a77c66d1abc27a5070", size = 35801, upload-time = "2025-09-05T12:50:38.314Z" },
{ url = "https://files.pythonhosted.org/packages/e7/e3/54b496ac724e60e61cc3447f02690105901ca6d90da0377dffe49ff99fc7/setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:1fae595d032b30dab4d659bece20debd202229fce12b55abab978b7f30783d73", size = 33958, upload-time = "2025-09-05T12:50:39.841Z" },
{ url = "https://files.pythonhosted.org/packages/ea/a8/c84bb045ebf8c6fdc7f7532319e86f8380d14bbd3084e6348df56bdfe6fd/setproctitle-1.3.7-cp314-cp314t-win32.whl", hash = "sha256:02432f26f5d1329ab22279ff863c83589894977063f59e6c4b4845804a08f8c2", size = 12745, upload-time = "2025-09-05T12:50:41.377Z" },
{ url = "https://files.pythonhosted.org/packages/08/b6/3a5a4f9952972791a9114ac01dfc123f0df79903577a3e0a7a404a695586/setproctitle-1.3.7-cp314-cp314t-win_amd64.whl", hash = "sha256:cbc388e3d86da1f766d8fc2e12682e446064c01cea9f88a88647cfe7c011de6a", size = 13469, upload-time = "2025-09-05T12:50:42.67Z" },
{ url = "https://files.pythonhosted.org/packages/34/8a/aff5506ce89bc3168cb492b18ba45573158d528184e8a9759a05a09088a9/setproctitle-1.3.7-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:eb440c5644a448e6203935ed60466ec8d0df7278cd22dc6cf782d07911bcbea6", size = 12654, upload-time = "2025-09-05T12:51:17.141Z" },
{ url = "https://files.pythonhosted.org/packages/41/89/5b6f2faedd6ced3d3c085a5efbd91380fb1f61f4c12bc42acad37932f4e9/setproctitle-1.3.7-pp310-pypy310_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:502b902a0e4c69031b87870ff4986c290ebbb12d6038a70639f09c331b18efb2", size = 14284, upload-time = "2025-09-05T12:51:18.393Z" },
{ url = "https://files.pythonhosted.org/packages/0a/c0/4312fed3ca393a29589603fd48f17937b4ed0638b923bac75a728382e730/setproctitle-1.3.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f6f268caeabb37ccd824d749e7ce0ec6337c4ed954adba33ec0d90cc46b0ab78", size = 13282, upload-time = "2025-09-05T12:51:19.703Z" },
{ url = "https://files.pythonhosted.org/packages/c3/5b/5e1c117ac84e3cefcf8d7a7f6b2461795a87e20869da065a5c087149060b/setproctitle-1.3.7-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:b1cac6a4b0252b8811d60b6d8d0f157c0fdfed379ac89c25a914e6346cf355a1", size = 12587, upload-time = "2025-09-05T12:51:21.195Z" },
{ url = "https://files.pythonhosted.org/packages/73/02/b9eadc226195dcfa90eed37afe56b5dd6fa2f0e5220ab8b7867b8862b926/setproctitle-1.3.7-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f1704c9e041f2b1dc38f5be4552e141e1432fba3dd52c72eeffd5bc2db04dc65", size = 14286, upload-time = "2025-09-05T12:51:22.61Z" },
{ url = "https://files.pythonhosted.org/packages/28/26/1be1d2a53c2a91ec48fa2ff4a409b395f836798adf194d99de9c059419ea/setproctitle-1.3.7-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b08b61976ffa548bd5349ce54404bf6b2d51bd74d4f1b241ed1b0f25bce09c3a", size = 13282, upload-time = "2025-09-05T12:51:24.094Z" },
]
[[package]]
name = "six"
version = "1.17.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
]
[[package]]
name = "sqlparse"
version = "0.5.5"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/90/76/437d71068094df0726366574cf3432a4ed754217b436eb7429415cf2d480/sqlparse-0.5.5.tar.gz", hash = "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e", size = 120815, upload-time = "2025-12-19T07:17:45.073Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba", size = 46138, upload-time = "2025-12-19T07:17:46.573Z" },
]
[[package]]
name = "tomli"
version = "2.4.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/82/30/31573e9457673ab10aa432461bee537ce6cef177667deca369efb79df071/tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c", size = 17477, upload-time = "2026-01-11T11:22:38.165Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/3c/d9/3dc2289e1f3b32eb19b9785b6a006b28ee99acb37d1d47f78d4c10e28bf8/tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867", size = 153663, upload-time = "2026-01-11T11:21:45.27Z" },
{ url = "https://files.pythonhosted.org/packages/51/32/ef9f6845e6b9ca392cd3f64f9ec185cc6f09f0a2df3db08cbe8809d1d435/tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9", size = 148469, upload-time = "2026-01-11T11:21:46.873Z" },
{ url = "https://files.pythonhosted.org/packages/d6/c2/506e44cce89a8b1b1e047d64bd495c22c9f71f21e05f380f1a950dd9c217/tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95", size = 236039, upload-time = "2026-01-11T11:21:48.503Z" },
{ url = "https://files.pythonhosted.org/packages/b3/40/e1b65986dbc861b7e986e8ec394598187fa8aee85b1650b01dd925ca0be8/tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76", size = 243007, upload-time = "2026-01-11T11:21:49.456Z" },
{ url = "https://files.pythonhosted.org/packages/9c/6f/6e39ce66b58a5b7ae572a0f4352ff40c71e8573633deda43f6a379d56b3e/tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d", size = 240875, upload-time = "2026-01-11T11:21:50.755Z" },
{ url = "https://files.pythonhosted.org/packages/aa/ad/cb089cb190487caa80204d503c7fd0f4d443f90b95cf4ef5cf5aa0f439b0/tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576", size = 246271, upload-time = "2026-01-11T11:21:51.81Z" },
{ url = "https://files.pythonhosted.org/packages/0b/63/69125220e47fd7a3a27fd0de0c6398c89432fec41bc739823bcc66506af6/tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a", size = 96770, upload-time = "2026-01-11T11:21:52.647Z" },
{ url = "https://files.pythonhosted.org/packages/1e/0d/a22bb6c83f83386b0008425a6cd1fa1c14b5f3dd4bad05e98cf3dbbf4a64/tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa", size = 107626, upload-time = "2026-01-11T11:21:53.459Z" },
{ url = "https://files.pythonhosted.org/packages/2f/6d/77be674a3485e75cacbf2ddba2b146911477bd887dda9d8c9dfb2f15e871/tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614", size = 94842, upload-time = "2026-01-11T11:21:54.831Z" },
{ url = "https://files.pythonhosted.org/packages/3c/43/7389a1869f2f26dba52404e1ef13b4784b6b37dac93bac53457e3ff24ca3/tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1", size = 154894, upload-time = "2026-01-11T11:21:56.07Z" },
{ url = "https://files.pythonhosted.org/packages/e9/05/2f9bf110b5294132b2edf13fe6ca6ae456204f3d749f623307cbb7a946f2/tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8", size = 149053, upload-time = "2026-01-11T11:21:57.467Z" },
{ url = "https://files.pythonhosted.org/packages/e8/41/1eda3ca1abc6f6154a8db4d714a4d35c4ad90adc0bcf700657291593fbf3/tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a", size = 243481, upload-time = "2026-01-11T11:21:58.661Z" },
{ url = "https://files.pythonhosted.org/packages/d2/6d/02ff5ab6c8868b41e7d4b987ce2b5f6a51d3335a70aa144edd999e055a01/tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1", size = 251720, upload-time = "2026-01-11T11:22:00.178Z" },
{ url = "https://files.pythonhosted.org/packages/7b/57/0405c59a909c45d5b6f146107c6d997825aa87568b042042f7a9c0afed34/tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b", size = 247014, upload-time = "2026-01-11T11:22:01.238Z" },
{ url = "https://files.pythonhosted.org/packages/2c/0e/2e37568edd944b4165735687cbaf2fe3648129e440c26d02223672ee0630/tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51", size = 251820, upload-time = "2026-01-11T11:22:02.727Z" },
{ url = "https://files.pythonhosted.org/packages/5a/1c/ee3b707fdac82aeeb92d1a113f803cf6d0f37bdca0849cb489553e1f417a/tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729", size = 97712, upload-time = "2026-01-11T11:22:03.777Z" },
{ url = "https://files.pythonhosted.org/packages/69/13/c07a9177d0b3bab7913299b9278845fc6eaaca14a02667c6be0b0a2270c8/tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da", size = 108296, upload-time = "2026-01-11T11:22:04.86Z" },
{ url = "https://files.pythonhosted.org/packages/18/27/e267a60bbeeee343bcc279bb9e8fbed0cbe224bc7b2a3dc2975f22809a09/tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3", size = 94553, upload-time = "2026-01-11T11:22:05.854Z" },
{ url = "https://files.pythonhosted.org/packages/34/91/7f65f9809f2936e1f4ce6268ae1903074563603b2a2bd969ebbda802744f/tomli-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0", size = 154915, upload-time = "2026-01-11T11:22:06.703Z" },
{ url = "https://files.pythonhosted.org/packages/20/aa/64dd73a5a849c2e8f216b755599c511badde80e91e9bc2271baa7b2cdbb1/tomli-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e", size = 149038, upload-time = "2026-01-11T11:22:07.56Z" },
{ url = "https://files.pythonhosted.org/packages/9e/8a/6d38870bd3d52c8d1505ce054469a73f73a0fe62c0eaf5dddf61447e32fa/tomli-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4", size = 242245, upload-time = "2026-01-11T11:22:08.344Z" },
{ url = "https://files.pythonhosted.org/packages/59/bb/8002fadefb64ab2669e5b977df3f5e444febea60e717e755b38bb7c41029/tomli-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e", size = 250335, upload-time = "2026-01-11T11:22:09.951Z" },
{ url = "https://files.pythonhosted.org/packages/a5/3d/4cdb6f791682b2ea916af2de96121b3cb1284d7c203d97d92d6003e91c8d/tomli-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c", size = 245962, upload-time = "2026-01-11T11:22:11.27Z" },
{ url = "https://files.pythonhosted.org/packages/f2/4a/5f25789f9a460bd858ba9756ff52d0830d825b458e13f754952dd15fb7bb/tomli-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f", size = 250396, upload-time = "2026-01-11T11:22:12.325Z" },
{ url = "https://files.pythonhosted.org/packages/aa/2f/b73a36fea58dfa08e8b3a268750e6853a6aac2a349241a905ebd86f3047a/tomli-2.4.0-cp313-cp313-win32.whl", hash = "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86", size = 97530, upload-time = "2026-01-11T11:22:13.865Z" },
{ url = "https://files.pythonhosted.org/packages/3b/af/ca18c134b5d75de7e8dc551c5234eaba2e8e951f6b30139599b53de9c187/tomli-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87", size = 108227, upload-time = "2026-01-11T11:22:15.224Z" },
{ url = "https://files.pythonhosted.org/packages/22/c3/b386b832f209fee8073c8138ec50f27b4460db2fdae9ffe022df89a57f9b/tomli-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132", size = 94748, upload-time = "2026-01-11T11:22:16.009Z" },
{ url = "https://files.pythonhosted.org/packages/f3/c4/84047a97eb1004418bc10bdbcfebda209fca6338002eba2dc27cc6d13563/tomli-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6", size = 154725, upload-time = "2026-01-11T11:22:17.269Z" },
{ url = "https://files.pythonhosted.org/packages/a8/5d/d39038e646060b9d76274078cddf146ced86dc2b9e8bbf737ad5983609a0/tomli-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc", size = 148901, upload-time = "2026-01-11T11:22:18.287Z" },
{ url = "https://files.pythonhosted.org/packages/73/e5/383be1724cb30f4ce44983d249645684a48c435e1cd4f8b5cded8a816d3c/tomli-2.4.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66", size = 243375, upload-time = "2026-01-11T11:22:19.154Z" },
{ url = "https://files.pythonhosted.org/packages/31/f0/bea80c17971c8d16d3cc109dc3585b0f2ce1036b5f4a8a183789023574f2/tomli-2.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d", size = 250639, upload-time = "2026-01-11T11:22:20.168Z" },
{ url = "https://files.pythonhosted.org/packages/2c/8f/2853c36abbb7608e3f945d8a74e32ed3a74ee3a1f468f1ffc7d1cb3abba6/tomli-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702", size = 246897, upload-time = "2026-01-11T11:22:21.544Z" },
{ url = "https://files.pythonhosted.org/packages/49/f0/6c05e3196ed5337b9fe7ea003e95fd3819a840b7a0f2bf5a408ef1dad8ed/tomli-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8", size = 254697, upload-time = "2026-01-11T11:22:23.058Z" },
{ url = "https://files.pythonhosted.org/packages/f3/f5/2922ef29c9f2951883525def7429967fc4d8208494e5ab524234f06b688b/tomli-2.4.0-cp314-cp314-win32.whl", hash = "sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776", size = 98567, upload-time = "2026-01-11T11:22:24.033Z" },
{ url = "https://files.pythonhosted.org/packages/7b/31/22b52e2e06dd2a5fdbc3ee73226d763b184ff21fc24e20316a44ccc4d96b/tomli-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475", size = 108556, upload-time = "2026-01-11T11:22:25.378Z" },
{ url = "https://files.pythonhosted.org/packages/48/3d/5058dff3255a3d01b705413f64f4306a141a8fd7a251e5a495e3f192a998/tomli-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2", size = 96014, upload-time = "2026-01-11T11:22:26.138Z" },
{ url = "https://files.pythonhosted.org/packages/b8/4e/75dab8586e268424202d3a1997ef6014919c941b50642a1682df43204c22/tomli-2.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9", size = 163339, upload-time = "2026-01-11T11:22:27.143Z" },
{ url = "https://files.pythonhosted.org/packages/06/e3/b904d9ab1016829a776d97f163f183a48be6a4deb87304d1e0116a349519/tomli-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0", size = 159490, upload-time = "2026-01-11T11:22:28.399Z" },
{ url = "https://files.pythonhosted.org/packages/e3/5a/fc3622c8b1ad823e8ea98a35e3c632ee316d48f66f80f9708ceb4f2a0322/tomli-2.4.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df", size = 269398, upload-time = "2026-01-11T11:22:29.345Z" },
{ url = "https://files.pythonhosted.org/packages/fd/33/62bd6152c8bdd4c305ad9faca48f51d3acb2df1f8791b1477d46ff86e7f8/tomli-2.4.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d", size = 276515, upload-time = "2026-01-11T11:22:30.327Z" },
{ url = "https://files.pythonhosted.org/packages/4b/ff/ae53619499f5235ee4211e62a8d7982ba9e439a0fb4f2f351a93d67c1dd2/tomli-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f", size = 273806, upload-time = "2026-01-11T11:22:32.56Z" },
{ url = "https://files.pythonhosted.org/packages/47/71/cbca7787fa68d4d0a9f7072821980b39fbb1b6faeb5f5cf02f4a5559fa28/tomli-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b", size = 281340, upload-time = "2026-01-11T11:22:33.505Z" },
{ url = "https://files.pythonhosted.org/packages/f5/00/d595c120963ad42474cf6ee7771ad0d0e8a49d0f01e29576ee9195d9ecdf/tomli-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087", size = 108106, upload-time = "2026-01-11T11:22:34.451Z" },
{ url = "https://files.pythonhosted.org/packages/de/69/9aa0c6a505c2f80e519b43764f8b4ba93b5a0bbd2d9a9de6e2b24271b9a5/tomli-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd", size = 120504, upload-time = "2026-01-11T11:22:35.764Z" },
{ url = "https://files.pythonhosted.org/packages/b3/9f/f1668c281c58cfae01482f7114a4b88d345e4c140386241a1a24dcc9e7bc/tomli-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4", size = 99561, upload-time = "2026-01-11T11:22:36.624Z" },
{ url = "https://files.pythonhosted.org/packages/23/d1/136eb2cb77520a31e1f64cbae9d33ec6df0d78bdf4160398e86eec8a8754/tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a", size = 14477, upload-time = "2026-01-11T11:22:37.446Z" },
]
[[package]]
name = "typing-extensions"
version = "4.15.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
]
[[package]]
name = "tzdata"
version = "2025.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" },
]
[[package]]
name = "urllib3"
version = "2.6.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" },
]
[[package]]
name = "wcwidth"
version = "0.6.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/35/a2/8e3becb46433538a38726c948d3399905a4c7cabd0df578ede5dc51f0ec2/wcwidth-0.6.0.tar.gz", hash = "sha256:cdc4e4262d6ef9a1a57e018384cbeb1208d8abbc64176027e2c2455c81313159", size = 159684, upload-time = "2026-02-06T19:19:40.919Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/68/5a/199c59e0a824a3db2b89c5d2dade7ab5f9624dbf6448dc291b46d5ec94d3/wcwidth-0.6.0-py3-none-any.whl", hash = "sha256:1a3a1e510b553315f8e146c54764f4fb6264ffad731b3d78088cdb1478ffbdad", size = 94189, upload-time = "2026-02-06T19:19:39.646Z" },
]
+8 -3
View File
@@ -1,11 +1,16 @@
version: '3'
services: services:
web: web:
restart: always restart: always
command: python manage.py runserver 0.0.0.0:8000 command: bash -c "python manage.py migrate && python manage.py runserver 0.0.0.0:8000"
ports: ports:
- "127.0.0.1:8000:8000" - "127.0.0.1:8000:8000"
build: . build: .
volumes: volumes:
- .:/app - .:/app
django-q:
restart: always
command: bash -c "python manage.py migrate && python manage.py qcluster"
build: .
volumes:
- .:/app