pax_global_header00006660000000000000000000000064145711242050014513gustar00rootroot0000000000000052 comment=f5eb92898637454343b177734b258f588dc2ca20 django-celery-beat-2.6.0/000077500000000000000000000000001457112420500151545ustar00rootroot00000000000000django-celery-beat-2.6.0/.bumpversion.cfg000066400000000000000000000005411457112420500202640ustar00rootroot00000000000000[bumpversion] current_version = 2.6.0 commit = True tag = True parse = (?P\d+)\.(?P\d+)\.(?P\d+)(?P[a-z]+)? serialize = {major}.{minor}.{patch}{releaselevel} {major}.{minor}.{patch} [bumpversion:file:django_celery_beat/__init__.py] [bumpversion:file:docs/includes/introduction.txt] [bumpversion:file:README.rst] django-celery-beat-2.6.0/.cookiecutterrc000066400000000000000000000016571457112420500202130ustar00rootroot00000000000000# This file exists so you can easily regenerate your project. # # `cookiepatcher` is a convenient shim around `cookiecutter` # for regenerating projects (it will generate a .cookiecutterrc # automatically for any template). To use it: # # pip install cookiepatcher # cookiepatcher gh:ionelmc/cookiecutter-pylibrary project-path # # See: # https://pypi.python.org/pypi/cookiecutter # # Alternatively, you can run: # # cookiecutter --overwrite-if-exists --config-file=project-path/.cookiecutterrc gh:ionelmc/cookiecutter-pylibrary default_context: email: 'ask@celeryproject.org' full_name: 'Ask Solem' github_username: 'celery' project_name: 'django-celery-beat' project_short_description: 'Database-backed Periodic Tasks' project_slug: 'django-celery-beat' version: '1.0.0' year: '2016' django-celery-beat-2.6.0/.coveragerc000066400000000000000000000002511457112420500172730ustar00rootroot00000000000000[run] branch = 1 cover_pylib = 0 include = *django_celery_beat/* omit = django_celery_beat.tests.* [report] omit = */python?.?/* */site-packages/* */pypy/* django-celery-beat-2.6.0/.editorconfig000066400000000000000000000003151457112420500176300ustar00rootroot00000000000000# http://editorconfig.org root = true [*] indent_style = space indent_size = 4 trim_trailing_whitespace = true insert_final_newline = true charset = utf-8 end_of_line = lf [Makefile] indent_style = tab django-celery-beat-2.6.0/.env.sample000066400000000000000000000006671457112420500172360ustar00rootroot00000000000000# CELERY # ----------------------------------------------------------------------------- # CELERY_BROKER_URL=amqp://guest:guest@rabbitmq:5672/ # DJANGO # ----------------------------------------------------------------------------- DJANGO_PORT=58000 DJANGO_HOST=127.0.0.1 # RABBITMQ # ----------------------------------------------------------------------------- # RABBITMQ_HOST= # RABBITMQ_PASSWORD= RABBITMQ_PORT=5672 # RABBITMQ_USER= django-celery-beat-2.6.0/.github/000077500000000000000000000000001457112420500165145ustar00rootroot00000000000000django-celery-beat-2.6.0/.github/dependabot.yml000066400000000000000000000003131457112420500213410ustar00rootroot00000000000000version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "daily" - package-ecosystem: "pip" directory: "/" schedule: interval: "daily" django-celery-beat-2.6.0/.github/workflows/000077500000000000000000000000001457112420500205515ustar00rootroot00000000000000django-celery-beat-2.6.0/.github/workflows/codeql-analysis.yml000066400000000000000000000043701457112420500243700ustar00rootroot00000000000000# For most projects, this workflow file will not need changing; you simply need # to commit it to your repository. # # You may wish to alter this file to override the set of languages analyzed, # or to provide custom queries or build logic. # # ******** NOTE ******** # We have attempted to detect the languages in your repository. Please check # the `language` matrix defined below to confirm you have the correct set of # supported CodeQL languages. # name: "CodeQL" on: push: branches: [ main ] pull_request: # The branches below must be a subset of the branches above branches: [ main ] jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: language: [ 'python' ] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] # Learn more about CodeQL language support at https://git.io/codeql-language-support steps: - name: Checkout repository uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. # queries: ./path/to/local/query, your-org/your-repo/queries@main # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild uses: github/codeql-action/autobuild@v3 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines # and modify them (or add more) to build your code if your project # uses a compiled language #- run: | # make bootstrap # make release - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 django-celery-beat-2.6.0/.github/workflows/test.yml000066400000000000000000000023031457112420500222510ustar00rootroot00000000000000name: CI on: push: branches: [ main ] pull_request: branches: [ main ] jobs: build: runs-on: ubuntu-latest strategy: fail-fast: false matrix: # https://docs.djangoproject.com/en/stable/faq/install/#what-python-version-can-i-use-with-django django-version: ["3.2", "4.2", "5.0"] python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', 'pypy-3.10'] exclude: - django-version: "3.2" python-version: "3.11" - django-version: "3.2" python-version: "3.12" - django-version: "5.0" python-version: "3.8" - django-version: "5.0" python-version: "3.9" services: rabbitmq: image: rabbitmq ports: - "5672:5672" steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | python -m pip install --upgrade pip python -m pip install tox tox-gh-actions - name: Test with tox run: tox env: DJANGO: ${{ matrix.django-version }} django-celery-beat-2.6.0/.gitignore000066400000000000000000000005071457112420500171460ustar00rootroot00000000000000.DS_Store *.pyc *$py.class *~ .*.sw[pon] dist/ *.egg-info *.egg *.egg/ build/ .build/ _build/ pip-log.txt .directory erl_crash.dump *.db Documentation/ .tox/ .ropeproject/ .project .pydevproject .idea/ .coverage celery/tests/cover/ .ve* cover/ .vagrant/ *.sqlite3 .cache/ htmlcov/ coverage.xml .eggs/ .python-version venv .env django-celery-beat-2.6.0/.pre-commit-config.yaml000066400000000000000000000014031457112420500214330ustar00rootroot00000000000000--- exclude: "migrations" repos: - repo: https://github.com/asottile/pyupgrade rev: v3.15.1 hooks: - id: pyupgrade args: ["--py37-plus"] - repo: https://github.com/PyCQA/flake8 rev: 7.0.0 hooks: - id: flake8 - repo: https://github.com/asottile/yesqa rev: v1.5.0 hooks: - id: yesqa - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.5.0 hooks: - id: check-merge-conflict - id: check-toml - id: check-yaml - id: mixed-line-ending - repo: https://github.com/pycqa/isort rev: 5.13.2 hooks: - id: isort - repo: https://github.com/adamchainz/django-upgrade rev: 1.16.0 hooks: - id: django-upgrade args: [--target-version, "3.2"] django-celery-beat-2.6.0/.readthedocs.yaml000066400000000000000000000002441457112420500204030ustar00rootroot00000000000000version: 2 build: os: ubuntu-20.04 tools: python: "3.8" sphinx: configuration: docs/conf.py python: install: - requirements: requirements/docs.txt django-celery-beat-2.6.0/AUTHORS000066400000000000000000000062771457112420500162400ustar00rootroot00000000000000========= AUTHORS ========= :order: sorted Aaron Ross Adam Endicott Alex Stapleton Alvaro Vega Andrew Frankel Andrew Watts Andrii Kostenko Anton Novosyolov Ask Solem Asif Saif Uddin Augusto Becciu Ben Firshman Brad Jasper Brett Gibson Brian Rosner Charlie DeTar Christopher Grebs Dan LaMotte Darjus Loktevic David Fischer David Ziegler Diego Andres Sanabria Martin Dmitriy Krasilnikov Donald Stufft Eldon Stegall Eugene Nagornyi Felix Berger Glenn Washburn Gnrhxni Greg Taylor Grégoire Cachet Hari Idan Zalzberg Ionel Maries Cristian Jaeyoung Heo Jannis Leidel Jason Baker Jay States Jeff Balogh Jeff Fischer Jeffrey Hu Jens Alm Jerzy Kozera Jesper Noehr Jimmy Bradshaw Joey Wilhelm John Andrews John Watson Jonas Haag Jonatan Heyman Josh Drake José Moreira Jude Nagurney Justin Quick Keith Perkins Kirill Panshin Mark Hellewell Mark Heppner Mark Lavin Mark Stover Maxim Bodyansky Michael Elsdoerfer Michael van Tellingen Mikhail Korobov Olivier Tabone Patrick Altman Piotr Bulinski Piotr Sikora Reza Lotun Rockallite Wulf Roger Barnes Roman Imankulov Rune Halvorsen Sam Cooke Scott Rubin Sean Creeley Serj Zavadsky Simon Charette Spencer Ellinor Theo Spears Timo Sugliani Vincent Driessen Vitaly Babiy Vladislav Poluhin Weipin Xia Wes Turner Wes Winham Williams Mendez WoLpH dongweiming django-celery-beat-2.6.0/Changelog000066400000000000000000000213311457112420500167660ustar00rootroot00000000000000.. _changelog: ================ Change history ================ Next ==== .. _version-2.6.0: 2.6.0 ===== :release-date: 2024-03-03 :release-by: Christian Clauss - Avoid crash when can not get human readable description (#648). - Update codeql-analysis.yml (#653). - Fix CI: Change assert self.app.timezone.zone to assert self.app.timezone.key (#664). - Drop Django 4.0 from CI to avoid security issues (#662). - Fix Issue #388: Celery Beat scheduled tasks may be executed repeatedly (#660). - Update README.rst (#670). - Update runtime.txt to include Django 5.0 (#681). - Replace case.patching fixture with mockeypatch + MagicMock (#692). - Update README.rst - Crontab effect description (#689). - Update supported Python & Django version in setup.py (#672). - Add Python 3.12 to test matrix and add classifier (#690). - Django v5.0: django.utils.timezone.utc alias --> datetime.timezone.utc (#703). - Upgrade GitHub Actions and PyPy 3.10 and Django 5.0 (#699). - Testing Django v5.0 on pypy-3.10-v7.3.14 passes (#705). - Prepare for release v2.6.0 to support Py3.12 and Dj5.0 (#712). - GitHub Actions: Do not hardcode an out-of-date version of PyPy (#715). - Use the same order in the admin as in the cron schedule expression (#716). - Upgrade pip and GitHub Actions dependencies with dependabot (#721). - Bump github/codeql-action from 2 to 3 (#722). - Bump actions/checkout from 3 to 4 (#723). - Update pytest requirement from <8.0,>=6.2.5 to >=6.2.5,<9.0 (#724). - Remove requirements/test-djangoXY.txt (#728). - Remove code for unsupported django.VERSION < (3, 2) (#729). - Added sphinxcontrib-django to extensions (#736). .. _version-2.5.0: 2.5.0 ===== :release-date: 2023-03-14 4:00 p.m. UTC+6:00 :release-by: Asif Saif Uddin - Prefetch_related on PeriodicTaskQuerySet.enabled (#608). - Clarify month range (#615). - Declare support for Django 4.2 & Python 3.11. - Adding human readable descriptions of crontab schedules (#622). - Start time heap block fix (#636). .. _version-2.4.0: 2.4.0 ===== :release-date: 2022-10-19 7:15 p.m. UTC+6:00 :release-by: Asif Saif Uddin - Fixed error path for zh-Hans translate (#548). - Django>=3.2,<4.2 (#567). - fix: downgrade importlib-metadata<5.0 until celery 5.3.0 release. - Fixed signals can not connect to OneToOneField (#572) (#573). - Remove superseded ExtendedQuerySet as it's functionality is built in. - Wrapped fieldset labels of PeriodicTaskAdmin around gettext_lazy. - fix: update PeriodicTask from entry (#344). .. _version-2.3.0: 2.3.0 ===== :release-date: :release-by: - Admin "disable_tasks" action also updates PeriodicTask's last_run_at field - feat: add periodic_task_name in favor of celery/django-celery-results - Fix ClockedSchedule and PeriodicTasks showing UTC time when Time Zone - Change last_run_at=None when using disable tasks admin action (#501) - fix the conflict with celery configuration (#525) - A unit Test to make sure ClockedSchedule and PeriodicTasks are shown - Django 4.0 and Python 3.10 support (#528) .. _version-2.2.1: 2.2.1 ===== :release-date: 2021-07-02 11:15 a.m. UTC+6:00 :release-by: Asif Saif Uddin - Require celery>=5.0,<6.0 - Enable Django 3.2 CI and add default_auto_field - Fix locale in dir tree - Do not blindly delete duplicate schedules (#389) - Use `python:3.8-slim` for lighter builds .. _version-2.2.0: 2.2.0 ===== :release-date: 2021-01-19 2:30 p.m. UTC+6:00 :release-by: Asif Saif Uddin - Fixed compatibility with django-timezone-field>=4.1.0 - Fixed deprecation warnings: 'assertEquals' in tests. - Fixed SolarSchedule event choices i18n support. - Updated 'es' .po file metadata - Update 'fr' .po file metadata - New schema migrations for SolarSchedule events choices changes in models. .. _version-2.1.0: 2.1.0 ===== :release-date: 2020-10-20 :release-by: Asif Saif Uddin - Fix string representation of CrontabSchedule, so it matches UNIX CRON expression format (#318) - If no schedule is selected in PeriodicTask form, raise a non-field error instead of an error bounded to the `interval` field (#327) - Fix some Spanish translations (#339) - Log "Writing entries..." message as DEBUG instead of INFO (#342) - Use CELERY_TIMEZONE setting as `CrontabSchedule.timezone` default instead of UTC (#346) - Fix bug in ClockedSchedule that made the schedule stuck after a clocked task was executed. The `enabled` field of ClockedSchedule has been dropped (#341) - Drop support for Python < 3.6 (#368) - Add support for Celery 5 and Django 3.1 (#368) .. _version-2.0.0: 2.0.0 ===== :release-date: 2020-03-18 :release-by: Asif Saif Uddin - Added support for Django 3.0 - Dropped support for Django < 2.2 and Python < 3.5 .. _version-1.6.0: 1.6.0 ===== :release-date: 2020-02-01 4:30 p.m. UTC+6:00 :release-by: Asif Saif Uddin - Fixed invalid long_description (#255) - Exposed read-only field PeriodicTask.last_run_at in Django admin (#257) - Added docker config to ease development (#260, #261, #264, #288) - Added validation schedule validation on save (#271) - Added French translation (#286) - Fixed case where last_run_at = None and CELERY_TIMEZONE != TIME_ZONE (#294) .. _version-1.5.0: 1.5.0 ===== :release-date: 2019-05-21 17:00 p.m. UTC+6:00 :release-by: Asif Saif Uddin - Fixed delay returned when a task has a start_time in the future. (#208) - PeriodicTaskAdmin: Declare some filtering, for usability (#215) - fix _default_now is_aware bug (#216) - Adds support for message headers for periodic tasks (#98) - make last_run_at tz aware before passing to celery (#233) .. _version-1.4.0: 1.4.0 ===== :release-date: 2018-12-09 1:30 p.m. UTC+2:00 :release-by: Omer Katz - Fix migrations dependencies. - Added the DJANGO_CELERY_BEAT_TZ_AWARE setting. .. _version-1.3.0: 1.3.0 ===== :release-date: 2018-11-12 17:30 p.m. UTC+2:00 :release-by: Omer Katz - Fix transaction handling while syncing the schedule. - Fix schedule type validation logic. - Scheduler no longer forgets the tasks after first schedule change. - Fix race condition for schedule_changed() resulting in erroneously closed connections. - Add support for task priorities when using RabbitMQ or Redis as broker. - Disabled tasks are now correctly deleted from the schedule. - Added name as search filter. .. _version-1.2.0: 1.2.0 ===== :release-date: 2018-10-08 16:00 p.m. UTC+3:00 :release-by: Omer Katz - Allow timezone-aware Cron schedules. - Retry later in case of InterfaceError in sync. - Show Periodic Task Description in panel admin. - Fix CrontabSchedule example. - Support Periodic Tasks with a start date and one-off tasks. - Fixes a problem with beat not reconnecting to MySQL (server restart, network problem, etc.) when checking if schedule has changed. - Add toggle admin action which allows to activate disabled tasks or deactivate enabled tasks. - Add fields validation for CrontabSchedule. - Drop support for Django<1.11. - Fix task heap invalidation bug which prevented scheduled tasks from running when syncing tasks from the database. - Raise a ValidationError when more than one type (solar, crontab or interval) of schedule is provided. .. _version-1.1.1: 1.1.1 ===== :release-date: 2018-2-18 2:30 p.m. UTC+3:00 :release-by: Omer Katz - Fix interval schedules by providing nowfun. - Removing code that forced last_run_at to be timezone naive for no reason, made timezone aware. Fixes crontab schedules after celery/celery#4173. - Entry.last_run_at is no-longer timezone naive. - Use a localized PyTZ timezone object for now() otherwise conversions fail scheduling breaks resulting in constant running of tasks or possibly not running ever. - Fix endless migrations creation for solar schedules events. - Prevent MySQL has gone away errors. - Added support for Django 2.0. - Adjust CrontabSchedule's minutes, hour & day_of_month fields max length .. _version-1.1.0: 1.1.0 ===== :release-date: 2017-10-31 2:30 p.m. UTC+3:00 :release-by: Omer Katz - Adds default_app_config (Issue celery/celery#3567) - Adds "run now" admin action for tasks. - Adds admin actions to toggle tasks. - Add solar schedules (Issue #8) - Notify beat of changes when Interval/Crontab models change. (Issue celery/celery#3683) - Fix PeriodicTask.enable sync issues - Notify beat of changes when Solar model changes. - Resolve CSS class conflict with django-adminlte2 package. - We now support Django 1.11 - Deletes are now performed cascadingly. - Return schedule for solar periodic tasks so that Celery Beat does not crash when one is scheduled. - Adding nowfun to solar and crontab schedulers so that the Django timezone is used. .. _version-1.0.1: 1.0.1 ===== :release-date: 2016-11-07 02:28 p.m. PST :release-by: Ask Solem - Now depends on Celery 4.0.0. - Migration modules were not included in the distribution. - Adds documentation: http://django-celery-beat.readthedocs.io/ .. _version-1.0.0: 1.0.0 ===== :release-date: 2016-09-08 03:19 p.m. PDT :release-by: Ask Solem - Initial release django-celery-beat-2.6.0/LICENSE000066400000000000000000000050741457112420500161670ustar00rootroot00000000000000Copyright (c) 2015-2016 Ask Solem. All Rights Reserved. Copyright (c) 2012-2014 GoPivotal, Inc. All Rights Reserved. Copyright (c) 2009-2012 Ask Solem. All Rights Reserved. django-celery-beat is licensed under The BSD License (3 Clause, also known as the new BSD license). The license is an OSI approved Open Source license and is GPL-compatible(1). The license text can also be found here: http://www.opensource.org/licenses/BSD-3-Clause License ======= Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Ask Solem nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Ask Solem OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Documentation License ===================== The documentation portion of django-celery-beat (the rendered contents of the "docs" directory of a software distribution or checkout) is supplied under the "Creative Commons Attribution-ShareAlike 4.0 International" (CC BY-SA 4.0) License as described by http://creativecommons.org/licenses/by-sa/4.0/ Footnotes ========= (1) A GPL-compatible license makes it possible to combine django-celery-beat with other software that is released under the GPL, it does not mean that we're distributing django-celery-beat under the GPL license. The BSD license, unlike the GPL, let you distribute a modified version without making your changes open source. django-celery-beat-2.6.0/MANIFEST.in000066400000000000000000000006521457112420500167150ustar00rootroot00000000000000include Changelog include LICENSE include README.rst include MANIFEST.in include setup.cfg include setup.py include manage.py recursive-include docs * recursive-include extra/* recursive-include examples * recursive-include requirements *.txt *.rst recursive-include django_celery_beat *.py *.html *.po *.mo recursive-include t *.py recursive-exclude * __pycache__ recursive-exclude * *.py[co] recursive-exclude * .*.sw[a-z] django-celery-beat-2.6.0/Makefile000066400000000000000000000072761457112420500166300ustar00rootroot00000000000000PROJ=django_celery_beat PGPIDENT="Celery Security Team" PYTHON=python PYTEST=pytest GIT=git TOX=tox ICONV=iconv FLAKE8=flake8 FLAKEPLUS=flakeplus PYDOCSTYLE=pydocstyle SPHINX2RST=sphinx2rst SPHINX_DIR=docs/ SPHINX_BUILDDIR="${SPHINX_DIR}/_build" README=README.rst README_SRC="docs/templates/readme.txt" CONTRIBUTING=CONTRIBUTING.rst CONTRIBUTING_SRC="docs/contributing.rst" SPHINX_HTMLDIR="${SPHINX_BUILDDIR}/html" DOCUMENTATION=Documentation FLAKEPLUSTARGET=2.7 TESTDIR=t all: help help: @echo "docs - Build documentation." @echo "test-all - Run tests for all supported python versions." @echo "distcheck ---------- - Check distribution for problems." @echo " test - Run unittests using current python." @echo " lint ------------ - Check codebase for problems." @echo " apicheck - Check API reference coverage." @echo " configcheck - Check configuration reference coverage." @echo " readmecheck - Check README.rst encoding." @echo " contribcheck - Check CONTRIBUTING.rst encoding" @echo " flakes -------- - Check code for syntax and style errors." @echo " flakecheck - Run flake8 on the source code." @echo " flakepluscheck - Run flakeplus on the source code." @echo " pep257check - Run flakeplus on the source code." @echo "readme - Regenerate README.rst file." @echo "contrib - Regenerate CONTRIBUTING.rst file" @echo "clean-dist --------- - Clean all distribution build artifacts." @echo " clean-git-force - Remove all uncomitted files." @echo " clean ------------ - Non-destructive clean" @echo " clean-pyc - Remove .pyc/__pycache__ files" @echo " clean-docs - Remove documentation build artifacts." @echo " clean-build - Remove setup artifacts." @echo "bump - Bump patch version number." @echo "bump-minor - Bump minor version number." @echo "bump-major - Bump major version number." @echo "release - Make PyPI release." clean: clean-docs clean-pyc clean-build clean-dist: clean clean-git-force bump: bumpversion patch bump-minor: bumpversion minor bump-major: bumpversion major release: python setup.py register sdist bdist_wheel upload --sign --identity="$(PGPIDENT)" Documentation: (cd "$(SPHINX_DIR)"; $(MAKE) html) mv "$(SPHINX_HTMLDIR)" $(DOCUMENTATION) docs: Documentation clean-docs: -rm -rf "$(SPHINX_BUILDDIR)" lint: flakecheck apicheck configcheck readmecheck apicheck: (cd "$(SPHINX_DIR)"; $(MAKE) apicheck) configcheck: true flakecheck: $(FLAKE8) "$(PROJ)" "$(TESTDIR)" flakediag: -$(MAKE) flakecheck flakepluscheck: $(FLAKEPLUS) --$(FLAKEPLUSTARGET) "$(PROJ)" "$(TESTDIR)" flakeplusdiag: -$(MAKE) flakepluscheck pep257check: $(PYDOCSTYLE) "$(PROJ)" flakes: flakediag flakeplusdiag pep257check clean-readme: -rm -f $(README) readmecheck: $(ICONV) -f ascii -t ascii $(README) >/dev/null $(README): $(SPHINX2RST) "$(README_SRC)" --ascii > $@ readme: clean-readme $(README) readmecheck clean-contrib: -rm -f "$(CONTRIBUTING)" $(CONTRIBUTING): $(SPHINX2RST) "$(CONTRIBUTING_SRC)" > $@ contrib: clean-contrib $(CONTRIBUTING) clean-pyc: -find . -type f -a \( -name "*.pyc" -o -name "*$$py.class" \) | xargs rm -find . -type d -name "__pycache__" | xargs rm -r removepyc: clean-pyc clean-build: rm -rf build/ dist/ .eggs/ *.egg-info/ .tox/ .coverage cover/ clean-git: $(GIT) clean -xdn clean-git-force: $(GIT) clean -xdf test-all: clean-pyc $(TOX) test: $(PYTHON) setup.py test cov: (cd $(TESTDIR); $(PYTEST) -x --cov="$(PROJ)" --cov-report=html) build: $(PYTHON) setup.py sdist bdist_wheel distcheck: lint test clean dist: readme contrib clean-dist build django-celery-beat-2.6.0/README.rst000066400000000000000000000257151457112420500166550ustar00rootroot00000000000000===================================================================== Database-backed Periodic Tasks ===================================================================== |build-status| |coverage| |license| |wheel| |pyversion| |pyimp| :Version: 2.6.0 :Web: http://django-celery-beat.readthedocs.io/ :Download: http://pypi.python.org/pypi/django-celery-beat :Source: http://github.com/celery/django-celery-beat :Keywords: django, celery, beat, periodic task, cron, scheduling About ===== This extension enables you to store the periodic task schedule in the database. The periodic tasks can be managed from the Django Admin interface, where you can create, edit and delete periodic tasks and how often they should run. Using the Extension =================== Usage and installation instructions for this extension are available from the `Celery documentation`_. .. _`Celery documentation`: http://docs.celeryproject.org/en/latest/userguide/periodic-tasks.html#using-custom-scheduler-classes Important Warning about Time Zones ================================== .. warning:: If you change the Django ``TIME_ZONE`` setting your periodic task schedule will still be based on the old timezone. To fix that you would have to reset the "last run time" for each periodic task: .. code-block:: Python >>> from django_celery_beat.models import PeriodicTask, PeriodicTasks >>> PeriodicTask.objects.all().update(last_run_at=None) >>> for task in PeriodicTask.objects.all(): >>> PeriodicTasks.changed(task) .. note:: This will reset the state as if the periodic tasks have never run before. Models ====== - ``django_celery_beat.models.PeriodicTask`` This model defines a single periodic task to be run. It must be associated with a schedule, which defines how often the task should run. - ``django_celery_beat.models.IntervalSchedule`` A schedule that runs at a specific interval (e.g. every 5 seconds). - ``django_celery_beat.models.CrontabSchedule`` A schedule with fields like entries in cron: ``minute hour day-of-week day_of_month month_of_year``. - ``django_celery_beat.models.PeriodicTasks`` This model is only used as an index to keep track of when the schedule has changed. Whenever you update a ``PeriodicTask`` a counter in this table is also incremented, which tells the ``celery beat`` service to reload the schedule from the database. If you update periodic tasks in bulk, you will need to update the counter manually: .. code-block:: Python >>> from django_celery_beat.models import PeriodicTasks >>> PeriodicTasks.update_changed() Example creating interval-based periodic task --------------------------------------------- To create a periodic task executing at an interval you must first create the interval object: .. code-block:: Python >>> from django_celery_beat.models import PeriodicTask, IntervalSchedule # executes every 10 seconds. >>> schedule, created = IntervalSchedule.objects.get_or_create( ... every=10, ... period=IntervalSchedule.SECONDS, ... ) That's all the fields you need: a period type and the frequency. You can choose between a specific set of periods: - ``IntervalSchedule.DAYS`` - ``IntervalSchedule.HOURS`` - ``IntervalSchedule.MINUTES`` - ``IntervalSchedule.SECONDS`` - ``IntervalSchedule.MICROSECONDS`` .. note:: If you have multiple periodic tasks executing every 10 seconds, then they should all point to the same schedule object. There's also a "choices tuple" available should you need to present this to the user: .. code-block:: Python >>> IntervalSchedule.PERIOD_CHOICES Now that we have defined the schedule object, we can create the periodic task entry: .. code-block:: Python >>> PeriodicTask.objects.create( ... interval=schedule, # we created this above. ... name='Importing contacts', # simply describes this periodic task. ... task='proj.tasks.import_contacts', # name of task. ... ) Note that this is a very basic example, you can also specify the arguments and keyword arguments used to execute the task, the ``queue`` to send it to[*], and set an expiry time. Here's an example specifying the arguments, note how JSON serialization is required: .. code-block:: Python >>> import json >>> from datetime import datetime, timedelta >>> PeriodicTask.objects.create( ... interval=schedule, # we created this above. ... name='Importing contacts', # simply describes this periodic task. ... task='proj.tasks.import_contacts', # name of task. ... args=json.dumps(['arg1', 'arg2']), ... kwargs=json.dumps({ ... 'be_careful': True, ... }), ... expires=datetime.utcnow() + timedelta(seconds=30) ... ) .. [*] you can also use low-level AMQP routing using the ``exchange`` and ``routing_key`` fields. Example creating crontab-based periodic task -------------------------------------------- A crontab schedule has the fields: ``minute``, ``hour``, ``day_of_week``, ``day_of_month`` and ``month_of_year``, so if you want the equivalent of a ``30 * * * *`` (execute 30 minutes past every hour) crontab entry you specify: .. code-block:: Python >>> from django_celery_beat.models import CrontabSchedule, PeriodicTask >>> schedule, _ = CrontabSchedule.objects.get_or_create( ... minute='30', ... hour='*', ... day_of_week='*', ... day_of_month='*', ... month_of_year='*', ... timezone=zoneinfo.ZoneInfo('Canada/Pacific') ... ) The crontab schedule is linked to a specific timezone using the 'timezone' input parameter. Then to create a periodic task using this schedule, use the same approach as the interval-based periodic task earlier in this document, but instead of ``interval=schedule``, specify ``crontab=schedule``: .. code-block:: Python >>> PeriodicTask.objects.create( ... crontab=schedule, ... name='Importing contacts', ... task='proj.tasks.import_contacts', ... ) Temporarily disable a periodic task ----------------------------------- You can use the ``enabled`` flag to temporarily disable a periodic task: .. code-block:: Python >>> periodic_task.enabled = False >>> periodic_task.save() Example running periodic tasks ----------------------------------- The periodic tasks still need 'workers' to execute them. So make sure the default **Celery** package is installed. (If not installed, please follow the installation instructions here: https://github.com/celery/celery) Both the worker and beat services need to be running at the same time. 1. Start a Celery worker service (specify your Django project name):: $ celery -A [project-name] worker --loglevel=info 2. As a separate process, start the beat service (specify the Django scheduler):: $ celery -A [project-name] beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler **OR** you can use the -S (scheduler flag), for more options see ``celery beat --help``):: $ celery -A [project-name] beat -l info -S django Also, as an alternative, you can run the two steps above (worker and beat services) with only one command (recommended for **development environment only**):: $ celery -A [project-name] worker --beat --scheduler django --loglevel=info 3. Now you can add and manage your periodic tasks from the Django Admin interface. Installation ============ You can install django-celery-beat either via the Python Package Index (PyPI) or from source. To install using ``pip``: .. code-block:: bash $ pip install -U django-celery-beat Downloading and installing from source -------------------------------------- Download the latest version of django-celery-beat from http://pypi.python.org/pypi/django-celery-beat You can install it by doing the following : .. code-block:: bash $ tar xvfz django-celery-beat-0.0.0.tar.gz $ cd django-celery-beat-0.0.0 $ python setup.py build # python setup.py install The last command must be executed as a privileged user if you are not currently using a virtualenv. After installation, add ``django_celery_beat`` to Django's settings module: .. code-block:: Python INSTALLED_APPS = [ ..., 'django_celery_beat', ] Run the ``django_celery_beat`` migrations using: .. code-block:: bash $ python manage.py migrate django_celery_beat Using the development version ----------------------------- With pip ~~~~~~~~ You can install the latest main version of django-celery-beat using the following pip command: .. code-block:: bash $ pip install git+https://github.com/celery/django-celery-beat#egg=django-celery-beat Developing django-celery-beat ----------------------------- To spin up a local development copy of django-celery-beat with Django admin at http://127.0.0.1:58000/admin/ run: .. code-block:: bash $ docker-compose up --build Log-in as user ``admin`` with password ``admin``. TZ Awareness: ------------- If you have a project that is time zone naive, you can set ``DJANGO_CELERY_BEAT_TZ_AWARE=False`` in your settings file. .. |build-status| image:: https://secure.travis-ci.org/celery/django-celery-beat.svg?branch=master :alt: Build status :target: https://travis-ci.org/celery/django-celery-beat .. |coverage| image:: https://codecov.io/github/celery/django-celery-beat/coverage.svg?branch=master :target: https://codecov.io/github/celery/django-celery-beat?branch=master .. |license| image:: https://img.shields.io/pypi/l/django-celery-beat.svg#foo :alt: BSD License :target: https://opensource.org/licenses/BSD-3-Clause .. |wheel| image:: https://img.shields.io/pypi/wheel/django-celery-beat.svg#foo :alt: django-celery-beat can be installed via wheel :target: http://pypi.python.org/pypi/django-celery-beat/ .. |pyversion| image:: https://img.shields.io/pypi/pyversions/django-celery-beat.svg#foo :alt: Supported Python versions. :target: http://pypi.python.org/pypi/django-celery-beat/ .. |pyimp| image:: https://img.shields.io/pypi/implementation/django-celery-beat.svg#foo :alt: Support Python implementations. :target: http://pypi.python.org/pypi/django-celery-beat/ django-celery-beat as part of the Tidelift Subscription ------------------------------------------------------- The maintainers of django-celery-beat and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. `Learn more`_. .. _Learn more: https://tidelift.com/subscription/pkg/pypi-django-celery-beat?utm_source=pypi-django-celery-beat&utm_medium=referral&utm_campaign=readme&utm_term=repo django-celery-beat-2.6.0/django_celery_beat/000077500000000000000000000000001457112420500207545ustar00rootroot00000000000000django-celery-beat-2.6.0/django_celery_beat/__init__.py000066400000000000000000000015341457112420500230700ustar00rootroot00000000000000"""Database-backed Periodic Tasks.""" # :copyright: (c) 2016, Ask Solem. # All rights reserved. # :license: BSD (3 Clause), see LICENSE for more details. import re from collections import namedtuple __version__ = '2.6.0' __author__ = 'Asif Saif Uddin, Ask Solem' __contact__ = 'auvipy@gmail.com, ask@celeryproject.org' __homepage__ = 'https://github.com/celery/django-celery-beat' __docformat__ = 'restructuredtext' # -eof meta- version_info_t = namedtuple('version_info_t', ( 'major', 'minor', 'micro', 'releaselevel', 'serial', )) # bumpversion can only search for {current_version} # so we have to parse the version here. _temp = re.match( r'(\d+)\.(\d+).(\d+)(.+)?', __version__).groups() VERSION = version_info = version_info_t( int(_temp[0]), int(_temp[1]), int(_temp[2]), _temp[3] or '', '') del _temp del re __all__ = [] django-celery-beat-2.6.0/django_celery_beat/admin.py000066400000000000000000000217461457112420500224300ustar00rootroot00000000000000"""Periodic Task Admin interface.""" from celery import current_app from celery.utils import cached_property from django import forms from django.conf import settings from django.contrib import admin, messages from django.db.models import Case, Value, When from django.forms.widgets import Select from django.template.defaultfilters import pluralize from django.utils.translation import gettext_lazy as _ from kombu.utils.json import loads from .models import (ClockedSchedule, CrontabSchedule, IntervalSchedule, PeriodicTask, PeriodicTasks, SolarSchedule) from .utils import is_database_scheduler class TaskSelectWidget(Select): """Widget that lets you choose between task names.""" celery_app = current_app _choices = None def tasks_as_choices(self): _ = self._modules tasks = list(sorted(name for name in self.celery_app.tasks if not name.startswith('celery.'))) return (('', ''), ) + tuple(zip(tasks, tasks)) @property def choices(self): if self._choices is None: self._choices = self.tasks_as_choices() return self._choices @choices.setter def choices(self, _): # ChoiceField.__init__ sets ``self.choices = choices`` # which would override ours. pass @cached_property def _modules(self): self.celery_app.loader.import_default_modules() class TaskChoiceField(forms.ChoiceField): """Field that lets you choose between task names.""" widget = TaskSelectWidget def valid_value(self, value): return True class PeriodicTaskForm(forms.ModelForm): """Form that lets you create and modify periodic tasks.""" regtask = TaskChoiceField( label=_('Task (registered)'), required=False, ) task = forms.CharField( label=_('Task (custom)'), required=False, max_length=200, ) class Meta: """Form metadata.""" model = PeriodicTask exclude = () def clean(self): data = super().clean() regtask = data.get('regtask') if regtask: data['task'] = regtask if not data['task']: exc = forms.ValidationError(_('Need name of task')) self._errors['task'] = self.error_class(exc.messages) raise exc if data.get('expire_seconds') is not None and data.get('expires'): raise forms.ValidationError( _('Only one can be set, in expires and expire_seconds') ) return data def _clean_json(self, field): value = self.cleaned_data[field] try: loads(value) except ValueError as exc: raise forms.ValidationError( _('Unable to parse JSON: %s') % exc, ) return value def clean_args(self): return self._clean_json('args') def clean_kwargs(self): return self._clean_json('kwargs') @admin.register(PeriodicTask) class PeriodicTaskAdmin(admin.ModelAdmin): """Admin-interface for periodic tasks.""" form = PeriodicTaskForm model = PeriodicTask celery_app = current_app date_hierarchy = 'start_time' list_display = ('name', 'enabled', 'scheduler', 'interval', 'start_time', 'last_run_at', 'one_off') list_filter = ['enabled', 'one_off', 'task', 'start_time', 'last_run_at'] actions = ('enable_tasks', 'disable_tasks', 'toggle_tasks', 'run_tasks') search_fields = ('name',) fieldsets = ( (None, { 'fields': ('name', 'regtask', 'task', 'enabled', 'description',), 'classes': ('extrapretty', 'wide'), }), (_('Schedule'), { 'fields': ('interval', 'crontab', 'crontab_translation', 'solar', 'clocked', 'start_time', 'last_run_at', 'one_off'), 'classes': ('extrapretty', 'wide'), }), (_('Arguments'), { 'fields': ('args', 'kwargs'), 'classes': ('extrapretty', 'wide', 'collapse', 'in'), }), (_('Execution Options'), { 'fields': ('expires', 'expire_seconds', 'queue', 'exchange', 'routing_key', 'priority', 'headers'), 'classes': ('extrapretty', 'wide', 'collapse', 'in'), }), ) readonly_fields = ( 'last_run_at', 'crontab_translation', ) def crontab_translation(self, obj): return obj.crontab.human_readable change_form_template = 'admin/djcelery/change_periodictask_form.html' def changeform_view(self, request, object_id=None, form_url='', extra_context=None): extra_context = extra_context or {} crontabs = CrontabSchedule.objects.all() crontab_dict = {} for crontab in crontabs: crontab_dict[crontab.id] = crontab.human_readable extra_context['readable_crontabs'] = crontab_dict return super().changeform_view(request, object_id, extra_context=extra_context) def changelist_view(self, request, extra_context=None): extra_context = extra_context or {} scheduler = getattr(settings, 'CELERY_BEAT_SCHEDULER', None) extra_context['wrong_scheduler'] = not is_database_scheduler(scheduler) return super().changelist_view( request, extra_context) def get_queryset(self, request): qs = super().get_queryset(request) return qs.select_related('interval', 'crontab', 'solar', 'clocked') def _message_user_about_update(self, request, rows_updated, verb): """Send message about action to user. `verb` should shortly describe what have changed (e.g. 'enabled'). """ self.message_user( request, _('{0} task{1} {2} successfully {3}').format( rows_updated, pluralize(rows_updated), pluralize(rows_updated, _('was,were')), verb, ), ) @admin.action( description=_('Enable selected tasks') ) def enable_tasks(self, request, queryset): rows_updated = queryset.update(enabled=True) PeriodicTasks.update_changed() self._message_user_about_update(request, rows_updated, 'enabled') @admin.action( description=_('Disable selected tasks') ) def disable_tasks(self, request, queryset): rows_updated = queryset.update(enabled=False, last_run_at=None) PeriodicTasks.update_changed() self._message_user_about_update(request, rows_updated, 'disabled') def _toggle_tasks_activity(self, queryset): return queryset.update(enabled=Case( When(enabled=True, then=Value(False)), default=Value(True), )) @admin.action( description=_('Toggle activity of selected tasks') ) def toggle_tasks(self, request, queryset): rows_updated = self._toggle_tasks_activity(queryset) PeriodicTasks.update_changed() self._message_user_about_update(request, rows_updated, 'toggled') @admin.action( description=_('Run selected tasks') ) def run_tasks(self, request, queryset): self.celery_app.loader.import_default_modules() tasks = [(self.celery_app.tasks.get(task.task), loads(task.args), loads(task.kwargs), task.queue, task.name) for task in queryset] if any(t[0] is None for t in tasks): for i, t in enumerate(tasks): if t[0] is None: break # variable "i" will be set because list "tasks" is not empty not_found_task_name = queryset[i].task self.message_user( request, _(f'task "{not_found_task_name}" not found'), level=messages.ERROR, ) return task_ids = [ task.apply_async(args=args, kwargs=kwargs, queue=queue, periodic_task_name=periodic_task_name) if queue and len(queue) else task.apply_async(args=args, kwargs=kwargs, periodic_task_name=periodic_task_name) for task, args, kwargs, queue, periodic_task_name in tasks ] tasks_run = len(task_ids) self.message_user( request, _('{0} task{1} {2} successfully run').format( tasks_run, pluralize(tasks_run), pluralize(tasks_run, _('was,were')), ), ) @admin.register(ClockedSchedule) class ClockedScheduleAdmin(admin.ModelAdmin): """Admin-interface for clocked schedules.""" fields = ( 'clocked_time', ) list_display = ( 'clocked_time', ) @admin.register(CrontabSchedule) class CrontabScheduleAdmin(admin.ModelAdmin): """Admin class for CrontabSchedule.""" list_display = ('__str__', 'human_readable') admin.site.register(IntervalSchedule) admin.site.register(SolarSchedule) django-celery-beat-2.6.0/django_celery_beat/apps.py000066400000000000000000000007621457112420500222760ustar00rootroot00000000000000"""Django Application configuration.""" from django.apps import AppConfig from django.utils.translation import gettext_lazy as _ __all__ = ['BeatConfig'] class BeatConfig(AppConfig): """Default configuration for django_celery_beat app.""" name = 'django_celery_beat' label = 'django_celery_beat' verbose_name = _('Periodic Tasks') default_auto_field = 'django.db.models.AutoField' def ready(self): from .signals import signals_connect signals_connect() django-celery-beat-2.6.0/django_celery_beat/clockedschedule.py000066400000000000000000000023661457112420500244560ustar00rootroot00000000000000"""Clocked schedule Implementation.""" from celery import schedules from celery.utils.time import maybe_make_aware from .utils import NEVER_CHECK_TIMEOUT class clocked(schedules.BaseSchedule): """clocked schedule. Depends on PeriodicTask one_off=True """ def __init__(self, clocked_time, nowfun=None, app=None): """Initialize clocked.""" self.clocked_time = maybe_make_aware(clocked_time) super().__init__(nowfun=nowfun, app=app) def remaining_estimate(self, last_run_at): return self.clocked_time - self.now() def is_due(self, last_run_at): rem_delta = self.remaining_estimate(None) remaining_s = max(rem_delta.total_seconds(), 0) if remaining_s == 0: return schedules.schedstate(is_due=True, next=NEVER_CHECK_TIMEOUT) return schedules.schedstate(is_due=False, next=remaining_s) def __repr__(self): return f'' def __eq__(self, other): if isinstance(other, clocked): return self.clocked_time == other.clocked_time return False def __ne__(self, other): return not self.__eq__(other) def __reduce__(self): return self.__class__, (self.clocked_time, self.nowfun) django-celery-beat-2.6.0/django_celery_beat/locale/000077500000000000000000000000001457112420500222135ustar00rootroot00000000000000django-celery-beat-2.6.0/django_celery_beat/locale/de/000077500000000000000000000000001457112420500226035ustar00rootroot00000000000000django-celery-beat-2.6.0/django_celery_beat/locale/de/LC_MESSAGES/000077500000000000000000000000001457112420500243705ustar00rootroot00000000000000django-celery-beat-2.6.0/django_celery_beat/locale/de/LC_MESSAGES/django.mo000066400000000000000000000233631457112420500261760ustar00rootroot00000000000000q,     X CW 7 9  X, H d 13 Be     < ! 8 N V _ q      :  Y?p2=! 3AS \ f r   @ 32@,s/caDp 45&C\$  V oz X4/FPv5!/HPXa jv      " - DNmuWBSO >Lr]P!BUPTfw |A"  " 7C`f mw?sFW8=.@ ` l x  `$U-0 L a t s  `!r! !"!O!O"Bi""""!"#" ##u+# # # ####` $?k$F$X$UK%2%%%&& &)& 1& <& F&Q&e&z&& &*&"&KpnN6 e<=7%d)1+kGER*PC]oa'F$#gZ 2OY?H>0"&- jbV q 4WA`^Shm9Q[;/J!,@.8B_DT:iUf5(lLcX3\ IMAMQP Message HeadersArgumentsAstronomical dawnAstronomical duskCivil dawnCivil duskClock TimeClocked ScheduleClocked Schedule to run the task on. Set only one schedule type, leave the others null.Cron Days Of The Month to Run. Use "*" for "all". (Example: "1,15")Cron Hours to Run. Use "*" for "all". (Example: "8,20")Cron Minutes to Run. Use "*" for "all". (Example: "0,30")Cron TimezoneCrontab ScheduleCrontab Schedule to run the task on. Set only one schedule type, leave the others null.Datetime after which the schedule will no longer trigger the task to runDatetime that the schedule last triggered the task to run. Reset to None if enabled is set to False.Datetime that this PeriodicTask was last modifiedDatetime when the schedule should begin triggering the task to runDayDay(s) Of The MonthDay(s) Of The WeekDaysDescriptionDetailed description about the details of this Periodic TaskDisable selected tasksEnable selected tasksEnabledExchangeExecution OptionsExpires DatetimeExpires timedelta with secondsHomeHourHour(s)HoursIf True, the schedule will only run the task a single timeInterval PeriodInterval ScheduleInterval Schedule to run the task on. Set only one schedule type, leave the others null.JSON encoded keyword arguments (Example: {"argument": "value"})JSON encoded message headers for the AMQP message.JSON encoded positional arguments (Example: ["arg1", "arg2"])Keyword ArgumentsLast ModifiedLast Run DatetimeLatitudeLongitudeMicrosecondMicrosecondsMinuteMinute(s)MinutesMonth(s) Of The YearNameNautical dawnNautical duskNeed name of taskNumber of PeriodsNumber of interval periods to wait before running the task againOne-off TaskOnly one can be set, in expires and expire_secondsOverride Exchange for low-level AMQP routingOverride Routing Key for low-level AMQP routingPeriodic TasksPositional ArgumentsPriorityPriority Number between 0 and 255. Supported by: RabbitMQ, Redis (priority reversed, 0 is highest).Queue OverrideQueue defined in CELERY_TASK_QUEUES. Leave None for default queuing.Routing KeyRun selected tasksRun the task at clocked timeRun the task when the event happens at this latitudeRun the task when the event happens at this longitudeRunning count of how many times the schedule has triggered the taskScheduleSecondSecondsSet to False to disable the scheduleShort Description For This TaskSolar EventSolar ScheduleSolar Schedule to run the task on. Set only one schedule type, leave the others null.Solar noonStart DatetimeSunriseSunsetTask (custom)Task (registered)The Name of the Celery Task that Should be Run. (Example: "proj.tasks.import_contacts")The type of period between task runs (Example: days)The type of solar event when the job should runTimedelta with seconds which the schedule will no longer trigger the task to runTimezone to Run the Cron Schedule on. Default is UTC.Toggle activity of selected tasksTotal Run CountUnable to parse JSON: %sclockedcrontabcrontabsevery {}every {} {}intervalintervalsperiodic taskperiodic taskssolar eventsolar eventswas,were{0} task{1} {2} successfully run{0} task{1} {2} successfully {3}Project-Id-Version: Report-Msgid-Bugs-To: PO-Revision-Date: 2022-08-28 03:29+0200 Last-Translator: Language-Team: Language: de MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n != 1); X-Generator: Poedit 3.1.1 AMQP-NachrichtenheaderArgumenteAstronomische MorgendämmerungAstronomische DämmerungZivile MorgendämmerungZivile DämmerungUhrzeitGetakteter-ZeitplanGetakteter Zeitplan zum Ausführen der Aufgabe. Legen Sie nur einen Zeitplantyp fest und lassen Sie die anderen null.Cron Tage des Monats zur Ausführung. Verwenden Sie "*" für "alle". (Beispiel: "1,15")Cron Stunden zur Ausführung. Verwenden Sie "*" für "alle". (Beispiel: „8,20“)Cron Minuten zur Ausführung. Verwenden Sie "*" für "alle". (Beispiel: "0,30")Cron ZeitzoneCrontab-ZeitplanCrontab Zeitplan zum Ausführen der Aufgabe. Legen Sie nur einen Zeitplantyp fest und lassen Sie die anderen null.Zeitpunkt, nach dem der Zeitplan die Ausführung die Aufgabe nicht mehr auslöstUhrzeit, zu der der letzte Zeitplan die Ausführung die Aufgabe ausgelöst hat. Setzt auf Keine zurück, wenn "Aktiviert" ist auf False gesetzt wird.Uhrzeit zu dem diese periodische Aufgabe zuletzt modifiziert wurdeZeitpunkt, zu der der Zeitplan beginnen soll, die Ausführung der Aufgabe auszulösenTagTag(e) des MonatsTag(e) der WocheTageBeschreibungDetaillierte Beschreibung der Details dieser periodischen AufgabeAusgewählte Aufgaben deaktivierenAusgewählte Aufgaben aktivierenAktiviertExchangeAusführungsoptionenAblaufdatumAblauf-Timedelta in SekundenStartStundeStunde(n)StundenWenn aktiv, wird die Aufgabe im Zeitplan nur einmal ausgeführtIntervallperiodeIntervall-ZeitplanIntervallzeitplan zum Ausführen der Aufgabe. Legen Sie nur einen Zeitplantyp fest und lassen Sie die anderen null.JSON-Codierte Schlüsselwortargumente (Beispiel: {"argument": "wert"})JSON-Codierte Nachrichtenheader für die AMQP-Nachricht.JSON-Codierte Positionsargumente (Beispiel: ["arg1", "arg2"])Schlüsselwort-ArgumenteZuletzt geändertUhrzeit der letzten AusführungBreitengradLängengradMikrosekundeMikrosekundenMinuteMinute(n)MinutenMonat(e) des JahresNameNautische MorgendämmerungNautische DämmerungName der Aufgabe benötigtAnzahl der PeriodenAnzahl der Intervallperioden, die gewartet werden sollen, bevor der Task erneut ausgeführt wirdEinmalige AufgabeEs kann nur eine festgelegt werden, "Ablaufdatum" oder "Ablauf-Timedelta in Sekunden"Override Exchange für Low-Level-AMQP-RoutingOverride Routing Key für Low-Level-AMQP-RoutingPeriodische AufgabenPositionsargumentePrioritätPrioritätsnummer zwischen 0 und 255. Unterstützt von: RabbitMQ, Redis (Priorität umgekehrt, 0 ist am höchsten).WarteschlangenüberschreibungIn CELERY_TASK_QUEUES definierte Warteschlange. Auf None lassen, für die Standardwarteschlange.Routing-SchlüsselAusgewählte Aufgaben ausführenDie Aufgabe zur Uhrzeit ausführenFühren Sie diese Aufgabe aus, wenn das Ereignis in diesem Breitengrad auftrittFühren Sie diese Aufgabe aus, wenn das Ereignis in diesem Längengrad auftrittLaufende Zählung, wie oft der Zeitplan die Aufgabe ausgelöst hatZeitplanSekundeSekundenDeaktivieren zum deaktivieren -_-Kurzbeschreibung für diese AufgabeSonnenereignissSolar-ZeitplanSolarzeitplan, um die Aufgabe auszuführen. Legen Sie nur einen Zeitplantyp fest und lassen Sie die anderen auf null.SonnenmittagStart-DatumSonnenaufgangSonnenuntergangAufgabe (benutzerdefiniert)Aufgabe (registriert)Der Name des Celery-Tasks, der ausgeführt werden soll. (Beispiel: "proj.tasks.import_contacts")Der Typ des Zeitraums zwischen den Taskläufen (Beispiel: Tage)Die Art des Solarereignisses, wenn die Aufgabe ausgeführt werden sollTimedelta in Sekunden, die der Zeitplan nicht mehr auslöst, um die Aufgabe auszuführenZeitzone, in der der Cron-Zeitplan ausgeführt werden soll. Der Standardwert ist UTC.Aktivität ausgewählter Aufgaben ein-/ausschaltenGesamtzahl der DurchgängeAusserstande JSON zu parsen: %sGetaktetCrontabCrontabsjede {}jede {} {}IntervallIntervallePeriodische AufgabePeriodische AufgabenSonnenereignissSonnenereignissewar,waren{0} Aufgabe{1} {2} erfolgreich ausgeführt{0} Aufgabe{1} {2} erfolgreich {3}django-celery-beat-2.6.0/django_celery_beat/locale/de/LC_MESSAGES/django.po000066400000000000000000000355101457112420500261760ustar00rootroot00000000000000# 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 , YEAR. # msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-12-22 18:56+0000\n" "PO-Revision-Date: 2022-08-28 03:29+0200\n" "Last-Translator: \n" "Language-Team: \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.1.1\n" #: django_celery_beat/admin.py:60 msgid "Task (registered)" msgstr "Aufgabe (registriert)" #: django_celery_beat/admin.py:64 msgid "Task (custom)" msgstr "Aufgabe (benutzerdefiniert)" #: django_celery_beat/admin.py:81 msgid "Need name of task" msgstr "Name der Aufgabe benötigt" #: django_celery_beat/admin.py:87 django_celery_beat/models.py:605 msgid "Only one can be set, in expires and expire_seconds" msgstr "" "Es kann nur eine festgelegt werden, \"Ablaufdatum\" oder \"Ablauf-Timedelta " "in Sekunden\"" #: django_celery_beat/admin.py:97 #, python-format msgid "Unable to parse JSON: %s" msgstr "Ausserstande JSON zu parsen: %s" #: django_celery_beat/admin.py:125 msgid "Schedule" msgstr "Zeitplan" #: django_celery_beat/admin.py:130 msgid "Arguments" msgstr "Argumente" #: django_celery_beat/admin.py:134 msgid "Execution Options" msgstr "Ausführungsoptionen" #: django_celery_beat/admin.py:177 #, python-brace-format msgid "{0} task{1} {2} successfully {3}" msgstr "{0} Aufgabe{1} {2} erfolgreich {3}" #: django_celery_beat/admin.py:180 django_celery_beat/admin.py:247 msgid "was,were" msgstr "war,waren" #: django_celery_beat/admin.py:189 msgid "Enable selected tasks" msgstr "Ausgewählte Aufgaben aktivieren" #: django_celery_beat/admin.py:195 msgid "Disable selected tasks" msgstr "Ausgewählte Aufgaben deaktivieren" #: django_celery_beat/admin.py:207 msgid "Toggle activity of selected tasks" msgstr "Aktivität ausgewählter Aufgaben ein-/ausschalten" #: django_celery_beat/admin.py:228 #, fuzzy, python-brace-format #| msgid "task \"{0}\" not found" msgid "task \"{not_found_task_name}\" not found" msgstr "Aufgabe \"{0}\" nicht gefunden" #: django_celery_beat/admin.py:244 #, python-brace-format msgid "{0} task{1} {2} successfully run" msgstr "{0} Aufgabe{1} {2} erfolgreich ausgeführt" #: django_celery_beat/admin.py:250 msgid "Run selected tasks" msgstr "Ausgewählte Aufgaben ausführen" #: django_celery_beat/apps.py:13 msgid "Periodic Tasks" msgstr "Periodische Aufgaben" #: django_celery_beat/models.py:30 msgid "Days" msgstr "Tage" #: django_celery_beat/models.py:31 msgid "Hours" msgstr "Stunden" #: django_celery_beat/models.py:32 msgid "Minutes" msgstr "Minuten" #: django_celery_beat/models.py:33 msgid "Seconds" msgstr "Sekunden" #: django_celery_beat/models.py:34 msgid "Microseconds" msgstr "Mikrosekunden" #: django_celery_beat/models.py:38 msgid "Day" msgstr "Tag" #: django_celery_beat/models.py:39 msgid "Hour" msgstr "Stunde" #: django_celery_beat/models.py:40 msgid "Minute" msgstr "Minute" #: django_celery_beat/models.py:41 msgid "Second" msgstr "Sekunde" #: django_celery_beat/models.py:42 msgid "Microsecond" msgstr "Mikrosekunde" #: django_celery_beat/models.py:46 msgid "Astronomical dawn" msgstr "Astronomische Morgendämmerung" #: django_celery_beat/models.py:47 msgid "Civil dawn" msgstr "Zivile Morgendämmerung" #: django_celery_beat/models.py:48 msgid "Nautical dawn" msgstr "Nautische Morgendämmerung" #: django_celery_beat/models.py:49 msgid "Astronomical dusk" msgstr "Astronomische Dämmerung" #: django_celery_beat/models.py:50 msgid "Civil dusk" msgstr "Zivile Dämmerung" #: django_celery_beat/models.py:51 msgid "Nautical dusk" msgstr "Nautische Dämmerung" #: django_celery_beat/models.py:52 msgid "Solar noon" msgstr "Sonnenmittag" #: django_celery_beat/models.py:53 msgid "Sunrise" msgstr "Sonnenaufgang" #: django_celery_beat/models.py:54 msgid "Sunset" msgstr "Sonnenuntergang" #: django_celery_beat/models.py:88 msgid "Solar Event" msgstr "Sonnenereigniss" #: django_celery_beat/models.py:89 msgid "The type of solar event when the job should run" msgstr "Die Art des Solarereignisses, wenn die Aufgabe ausgeführt werden soll" #: django_celery_beat/models.py:93 msgid "Latitude" msgstr "Breitengrad" #: django_celery_beat/models.py:94 msgid "Run the task when the event happens at this latitude" msgstr "" "Führen Sie diese Aufgabe aus, wenn das Ereignis in diesem Breitengrad " "auftritt" #: django_celery_beat/models.py:99 msgid "Longitude" msgstr "Längengrad" #: django_celery_beat/models.py:100 msgid "Run the task when the event happens at this longitude" msgstr "" "Führen Sie diese Aufgabe aus, wenn das Ereignis in diesem Längengrad auftritt" #: django_celery_beat/models.py:107 msgid "solar event" msgstr "Sonnenereigniss" #: django_celery_beat/models.py:108 msgid "solar events" msgstr "Sonnenereignisse" #: django_celery_beat/models.py:158 msgid "Number of Periods" msgstr "Anzahl der Perioden" #: django_celery_beat/models.py:159 msgid "Number of interval periods to wait before running the task again" msgstr "" "Anzahl der Intervallperioden, die gewartet werden sollen, bevor der Task " "erneut ausgeführt wird" #: django_celery_beat/models.py:165 msgid "Interval Period" msgstr "Intervallperiode" #: django_celery_beat/models.py:166 msgid "The type of period between task runs (Example: days)" msgstr "Der Typ des Zeitraums zwischen den Taskläufen (Beispiel: Tage)" #: django_celery_beat/models.py:172 msgid "interval" msgstr "Intervall" #: django_celery_beat/models.py:173 msgid "intervals" msgstr "Intervalle" #: django_celery_beat/models.py:200 msgid "every {}" msgstr "jede {}" #: django_celery_beat/models.py:205 msgid "every {} {}" msgstr "jede {} {}" #: django_celery_beat/models.py:216 msgid "Clock Time" msgstr "Uhrzeit" #: django_celery_beat/models.py:217 msgid "Run the task at clocked time" msgstr "Die Aufgabe zur Uhrzeit ausführen" #: django_celery_beat/models.py:223 django_celery_beat/models.py:224 msgid "clocked" msgstr "Getaktet" #: django_celery_beat/models.py:264 msgid "Minute(s)" msgstr "Minute(n)" #: django_celery_beat/models.py:266 msgid "Cron Minutes to Run. Use \"*\" for \"all\". (Example: \"0,30\")" msgstr "" "Cron Minuten zur Ausführung. Verwenden Sie \"*\" für \"alle\". (Beispiel: " "\"0,30\")" #: django_celery_beat/models.py:271 msgid "Hour(s)" msgstr "Stunde(n)" #: django_celery_beat/models.py:273 msgid "Cron Hours to Run. Use \"*\" for \"all\". (Example: \"8,20\")" msgstr "" "Cron Stunden zur Ausführung. Verwenden Sie \"*\" für \"alle\". (Beispiel: " "„8,20“)" #: django_celery_beat/models.py:278 msgid "Day(s) Of The Week" msgstr "Tag(e) der Woche" #: django_celery_beat/models.py:280 #, fuzzy #| msgid "" #| "Cron Days Of The Week to Run. Use \"*\" for \"all\". (Example: \"0,5\")" msgid "" "Cron Days Of The Week to Run. Use \"*\" for \"all\", Sunday is 0 or 7, " "Monday is 1. (Example: \"0,5\")" msgstr "" "Cron Tage der Woche zur Ausführung. Verwenden Sie \"*\" für \"alle\", Sonntag ist 0 oder 7, " "Montag ist 1. (Beispiel: \"0,5\")" #: django_celery_beat/models.py:286 msgid "Day(s) Of The Month" msgstr "Tag(e) des Monats" #: django_celery_beat/models.py:288 msgid "" "Cron Days Of The Month to Run. Use \"*\" for \"all\". (Example: \"1,15\")" msgstr "" "Cron Tage des Monats zur Ausführung. Verwenden Sie \"*\" für \"alle\". " "(Beispiel: \"1,15\")" #: django_celery_beat/models.py:294 msgid "Month(s) Of The Year" msgstr "Monat(e) des Jahres" #: django_celery_beat/models.py:296 #, fuzzy #| msgid "" #| "Cron Months Of The Year to Run. Use \"*\" for \"all\". (Example: \"0,6\")" msgid "" "Cron Months (1-12) Of The Year to Run. Use \"*\" for \"all\". (Example: " "\"1,12\")" msgstr "" "Cron Monate des Jahres zur Ausführung. Verwenden Sie \"*\" für \"alle\". " "(Beispiel: \"0,6\")" #: django_celery_beat/models.py:304 msgid "Cron Timezone" msgstr "Cron Zeitzone" #: django_celery_beat/models.py:306 msgid "Timezone to Run the Cron Schedule on. Default is UTC." msgstr "" "Zeitzone, in der der Cron-Zeitplan ausgeführt werden soll. Der Standardwert " "ist UTC." #: django_celery_beat/models.py:312 msgid "crontab" msgstr "Crontab" #: django_celery_beat/models.py:313 msgid "crontabs" msgstr "Crontabs" #: django_celery_beat/models.py:404 msgid "Name" msgstr "Name" #: django_celery_beat/models.py:405 msgid "Short Description For This Task" msgstr "Kurzbeschreibung für diese Aufgabe" #: django_celery_beat/models.py:410 msgid "" "The Name of the Celery Task that Should be Run. (Example: \"proj.tasks." "import_contacts\")" msgstr "" "Der Name des Celery-Tasks, der ausgeführt werden soll. (Beispiel: \"proj." "tasks.import_contacts\")" #: django_celery_beat/models.py:418 msgid "Interval Schedule" msgstr "Intervall-Zeitplan" #: django_celery_beat/models.py:419 msgid "" "Interval Schedule to run the task on. Set only one schedule type, leave the " "others null." msgstr "" "Intervallzeitplan zum Ausführen der Aufgabe. Legen Sie nur einen Zeitplantyp " "fest und lassen Sie die anderen null." #: django_celery_beat/models.py:424 msgid "Crontab Schedule" msgstr "Crontab-Zeitplan" #: django_celery_beat/models.py:425 msgid "" "Crontab Schedule to run the task on. Set only one schedule type, leave the " "others null." msgstr "" "Crontab Zeitplan zum Ausführen der Aufgabe. Legen Sie nur einen Zeitplantyp " "fest und lassen Sie die anderen null." #: django_celery_beat/models.py:430 msgid "Solar Schedule" msgstr "Solar-Zeitplan" #: django_celery_beat/models.py:431 msgid "" "Solar Schedule to run the task on. Set only one schedule type, leave the " "others null." msgstr "" "Solarzeitplan, um die Aufgabe auszuführen. Legen Sie nur einen Zeitplantyp " "fest und lassen Sie die anderen auf null." #: django_celery_beat/models.py:436 msgid "Clocked Schedule" msgstr "Getakteter-Zeitplan" #: django_celery_beat/models.py:437 msgid "" "Clocked Schedule to run the task on. Set only one schedule type, leave the " "others null." msgstr "" "Getakteter Zeitplan zum Ausführen der Aufgabe. Legen Sie nur einen " "Zeitplantyp fest und lassen Sie die anderen null." #: django_celery_beat/models.py:443 msgid "Positional Arguments" msgstr "Positionsargumente" #: django_celery_beat/models.py:445 msgid "JSON encoded positional arguments (Example: [\"arg1\", \"arg2\"])" msgstr "JSON-Codierte Positionsargumente (Beispiel: [\"arg1\", \"arg2\"])" #: django_celery_beat/models.py:450 msgid "Keyword Arguments" msgstr "Schlüsselwort-Argumente" #: django_celery_beat/models.py:452 msgid "JSON encoded keyword arguments (Example: {\"argument\": \"value\"})" msgstr "" "JSON-Codierte Schlüsselwortargumente (Beispiel: {\"argument\": \"wert\"})" #: django_celery_beat/models.py:458 msgid "Queue Override" msgstr "Warteschlangenüberschreibung" #: django_celery_beat/models.py:460 msgid "Queue defined in CELERY_TASK_QUEUES. Leave None for default queuing." msgstr "" "In CELERY_TASK_QUEUES definierte Warteschlange. Auf None lassen, für die " "Standardwarteschlange." #: django_celery_beat/models.py:469 msgid "Exchange" msgstr "Exchange" #: django_celery_beat/models.py:470 msgid "Override Exchange for low-level AMQP routing" msgstr "Override Exchange für Low-Level-AMQP-Routing" #: django_celery_beat/models.py:474 msgid "Routing Key" msgstr "Routing-Schlüssel" #: django_celery_beat/models.py:475 msgid "Override Routing Key for low-level AMQP routing" msgstr "Override Routing Key für Low-Level-AMQP-Routing" #: django_celery_beat/models.py:479 msgid "AMQP Message Headers" msgstr "AMQP-Nachrichtenheader" #: django_celery_beat/models.py:480 msgid "JSON encoded message headers for the AMQP message." msgstr "JSON-Codierte Nachrichtenheader für die AMQP-Nachricht." #: django_celery_beat/models.py:486 msgid "Priority" msgstr "Priorität" #: django_celery_beat/models.py:488 msgid "" "Priority Number between 0 and 255. Supported by: RabbitMQ, Redis (priority " "reversed, 0 is highest)." msgstr "" "Prioritätsnummer zwischen 0 und 255. Unterstützt von: RabbitMQ, Redis " "(Priorität umgekehrt, 0 ist am höchsten)." #: django_celery_beat/models.py:493 msgid "Expires Datetime" msgstr "Ablaufdatum" #: django_celery_beat/models.py:495 msgid "" "Datetime after which the schedule will no longer trigger the task to run" msgstr "" "Zeitpunkt, nach dem der Zeitplan die Ausführung die Aufgabe nicht mehr " "auslöst" #: django_celery_beat/models.py:500 msgid "Expires timedelta with seconds" msgstr "Ablauf-Timedelta in Sekunden" #: django_celery_beat/models.py:502 msgid "" "Timedelta with seconds which the schedule will no longer trigger the task to " "run" msgstr "" "Timedelta in Sekunden, die der Zeitplan nicht mehr auslöst, um die Aufgabe " "auszuführen" #: django_celery_beat/models.py:508 msgid "One-off Task" msgstr "Einmalige Aufgabe" #: django_celery_beat/models.py:510 msgid "If True, the schedule will only run the task a single time" msgstr "Wenn aktiv, wird die Aufgabe im Zeitplan nur einmal ausgeführt" #: django_celery_beat/models.py:514 msgid "Start Datetime" msgstr "Start-Datum" #: django_celery_beat/models.py:516 msgid "Datetime when the schedule should begin triggering the task to run" msgstr "" "Zeitpunkt, zu der der Zeitplan beginnen soll, die Ausführung der Aufgabe " "auszulösen" #: django_celery_beat/models.py:521 msgid "Enabled" msgstr "Aktiviert" #: django_celery_beat/models.py:522 msgid "Set to False to disable the schedule" msgstr "Deaktivieren zum deaktivieren -_-" #: django_celery_beat/models.py:527 msgid "Last Run Datetime" msgstr "Uhrzeit der letzten Ausführung" #: django_celery_beat/models.py:529 msgid "" "Datetime that the schedule last triggered the task to run. Reset to None if " "enabled is set to False." msgstr "" "Uhrzeit, zu der der letzte Zeitplan die Ausführung die Aufgabe ausgelöst " "hat. Setzt auf Keine zurück, wenn \"Aktiviert\" ist auf False gesetzt wird." #: django_celery_beat/models.py:534 msgid "Total Run Count" msgstr "Gesamtzahl der Durchgänge" #: django_celery_beat/models.py:536 msgid "Running count of how many times the schedule has triggered the task" msgstr "Laufende Zählung, wie oft der Zeitplan die Aufgabe ausgelöst hat" #: django_celery_beat/models.py:541 msgid "Last Modified" msgstr "Zuletzt geändert" #: django_celery_beat/models.py:542 msgid "Datetime that this PeriodicTask was last modified" msgstr "Uhrzeit zu dem diese periodische Aufgabe zuletzt modifiziert wurde" #: django_celery_beat/models.py:546 msgid "Description" msgstr "Beschreibung" #: django_celery_beat/models.py:548 msgid "Detailed description about the details of this Periodic Task" msgstr "Detaillierte Beschreibung der Details dieser periodischen Aufgabe" #: django_celery_beat/models.py:557 msgid "periodic task" msgstr "Periodische Aufgabe" #: django_celery_beat/models.py:558 msgid "periodic tasks" msgstr "Periodische Aufgaben" #: django_celery_beat/templates/admin/djcelery/change_list.html:6 msgid "Home" msgstr "Start" django-celery-beat-2.6.0/django_celery_beat/locale/es/000077500000000000000000000000001457112420500226225ustar00rootroot00000000000000django-celery-beat-2.6.0/django_celery_beat/locale/es/LC_MESSAGES/000077500000000000000000000000001457112420500244075ustar00rootroot00000000000000django-celery-beat-2.6.0/django_celery_beat/locale/es/LC_MESSAGES/django.mo000066400000000000000000000240641457112420500262140ustar00rootroot00000000000000q,     X CM ` 7 9* Cd  X H di 1 B C G [ n s <       */4<:B}Y?29=l     !6 ; IWi@{ 2,/)Yh}cD >J]4z5C)0$8] }V   &X84/P5G!}    & 2?T ] ~V)@O _kwKmECEK=wY)EPK B!> ] ht*A$v?S: PE     " 3 : L _ y Q  T <P!I!!! "n "{"J"""'#88#9q#4###4#"&$ I$V$uj$$$% %%/%YB%?%9%r&C&.&&' ;'H'P'Y' a' l' v''' ''' ')'"(AKpm6 d<=n7%c)1+jGiQ*OC\o$`'F#fY 2X?H>[0"&- aUq 4VE_]Rgl9PZ;/J!,@.8B^DS:hTe5N(kLbW3 IMAMQP Message HeadersAstronomical dawnAstronomical duskCivil dawnCivil duskClock TimeClocked ScheduleClocked Schedule to run the task on. Set only one schedule type, leave the others null.Cron Days Of The Month to Run. Use "*" for "all". (Example: "1,15")Cron Days Of The Week to Run. Use "*" for "all", Sunday is 0 or 7, Monday is 1. (Example: "0,5")Cron Hours to Run. Use "*" for "all". (Example: "8,20")Cron Minutes to Run. Use "*" for "all". (Example: "0,30")Cron Months Of The Year to Run. Use "*" for "all". (Example: "0,6")Cron TimezoneCrontab ScheduleCrontab Schedule to run the task on. Set only one schedule type, leave the others null.Datetime after which the schedule will no longer trigger the task to runDatetime that the schedule last triggered the task to run. Reset to None if enabled is set to False.Datetime that this PeriodicTask was last modifiedDatetime when the schedule should begin triggering the task to runDayDay(s) Of The MonthDay(s) Of The WeekDaysDescriptionDetailed description about the details of this Periodic TaskDisable selected tasksEnable selected tasksEnabledExchangeExpires DatetimeExpires timedelta with secondsHomeHourHour(s)HoursIf True, the schedule will only run the task a single timeInterval PeriodInterval ScheduleInterval Schedule to run the task on. Set only one schedule type, leave the others null.JSON encoded keyword arguments (Example: {"argument": "value"})JSON encoded message headers for the AMQP message.JSON encoded positional arguments (Example: ["arg1", "arg2"])Keyword ArgumentsLast ModifiedLast Run DatetimeLatitudeLongitudeMicrosecondMicrosecondsMinuteMinute(s)MinutesMonth(s) Of The YearNameNautical dawnNautical duskNeed name of taskNumber of PeriodsNumber of interval periods to wait before running the task againOne-off TaskOnly one can be set, in expires and expire_secondsOverride Exchange for low-level AMQP routingOverride Routing Key for low-level AMQP routingPeriodic TasksPositional ArgumentsPriorityPriority Number between 0 and 255. Supported by: RabbitMQ, Redis (priority reversed, 0 is highest).Queue OverrideQueue defined in CELERY_TASK_QUEUES. Leave None for default queuing.Routing KeyRun selected tasksRun the task at clocked timeRun the task when the event happens at this latitudeRun the task when the event happens at this longitudeRunning count of how many times the schedule has triggered the taskSecondSecondsSet to False to disable the scheduleShort Description For This TaskSolar EventSolar ScheduleSolar Schedule to run the task on. Set only one schedule type, leave the others null.Solar noonStart DatetimeSunriseSunsetTask (custom)Task (registered)The Name of the Celery Task that Should be Run. (Example: "proj.tasks.import_contacts")The type of period between task runs (Example: days)The type of solar event when the job should runTimedelta with seconds which the schedule will no longer trigger the task to runTimezone to Run the Cron Schedule on. Default is UTC.Toggle activity of selected tasksTotal Run CountUnable to parse JSON: %sclockedcrontabcrontabsevery {}every {} {}intervalintervalsperiodic taskperiodic taskssolar eventsolar eventstask "{0}" not foundwas,were{0} task{1} {2} successfully run{0} task{1} {2} successfully {3}Project-Id-Version: PACKAGE VERSION Report-Msgid-Bugs-To: PO-Revision-Date: 2022-10-14 23:48+0200 Last-Translator: Luis Saavedra Language-Team: Language: es MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n > 1); X-Generator: Poedit 3.1.1 Cabeceras de mensaje de AMQPAmanecer astronómicoAnochecer astronómicoAmanecer civilAnochecer civilHora y díaProgramación horariaProgramación horaria con la cual ejecutar la tarea. Establece sólo un tipo de programación, deja el resto en blanco.Días del mes Cron cuando ejecutar. Usa "*" para "todos". (Ejemplo: "1,15")Días de la semana Cron cuando ejecutar. Usa "*" para "todos", Domingo es 0 o 7, Lunes es 1. (Ejemplo: "0,5")Horas Cron cuando ejecutar. Usa "*" para "todas". (Ejemplo: "8,20")Minutos Cron cuando ejecutar. Usa "*" para "todos". (Ejemplo: "0,30")Meses del año Cron cuando ejecutar. Usa "*" para "todos". (Ejemplo: "0,6")Zona horaria CronProgramación CrontabProgramación Crontab con la cual ejecutar la tarea. Establece sólo un tipo de programación, deja el resto en blanco.Fecha después de la cual la programación no provocará que la tarea vuelva a ejecutarseFecha en la cual la programación ejecutó la tarea por última vez. Reinicializa a None si enabled está establecido como falso.Fecha en la cual esta tarea periódica fue modificada por última vezFecha cuando la programación debe comenzar a provocar la ejecución de la tareaDíaDía(s) del mesDía(s) de la semanaDíasDescripciónDescripción detallada sobre los detalles de esta tarea periódicaDeshabilitar tareas seleccionadasHabilitar tareas seleccionadasHabilitadaIntercambioFecha de caducidadDelta de tiempo de expiración en segundosInicioHoraHora(s)HorasSi es verdadera, la programación sólo lanzará la tarea una vezPeríodo de intervaloIntervalo de programaciónIntervalo de programación donde ejecutar la tarea. Establece sólo un tipo de programación, deja el resto en blanco.Argumentos opcionales codificados en formato JSON. (Ejemplo: {"argument": "value"})Cacbeceras de mensaje de AMQP codificadas en formato JSON.Argumentos posicionales codificados en formato JSON. (Ejemplo: ["arg1", "arg2"])Agumentos opcionalesÚltima modificaciónFecha de última ejecuciónLatitudLongitudMicrosegundoMicrosegundosMinutoMinuto(s)MinutosMes(es) del añoNombreAmanecer náuticoAnochecer náuticoNombre de tarea necesarioNúmero de PeríodosNúmero de períodos de intervalo a esperar antes de ejecutar esta tarea de nuevoTarea de ejecución únicaSólo uno de los campos puede ser definido, en expiración y segundos de expiraciónInvalida intercambio para enrutamiento de bajo nivel de AMQPInvalida la clave de enrutamiento para enrutamiento de bajo nivel de AMQPTareas PeriódicasArgumentos posicionalesPrioridadNúmero de prioridad entre 0 and 255. Soportado por: RabbitMQ, Redis (prioridad invertida, 0 es la más alta).Invalidación de colaCola definida en CELERY_TASK_QUEUES. Dejala nula para la cola por defecto.Clave de enrutamientoEjecutar tareas seleccionadasEjecuta la tarea en el momento indicadoEjecutar la tarea cuando el evento ocurra a esta latitudEjecutar la tarea cuando el evento ocurra a esta longitudContador de cuentas veces ha sido ejecutada la tareaSegundoSegundosEstablece a Falso para deshabilitar la programaciónDescripción corta para esta tareaEvento SolarProgramación solarProgramación solar con la cual ejecutar la tarea. Establece sólo un tipo de programación, deja el resto en blanco.Mediodía solarFecha de comienzoAmanecerPuesta de solTarea (personalizada)Tarea (registrada)Nombre de la tarea Celery que debe ser ejecutada. (Ejemplo: "proj.tasks.import_contacts")El tipo de período entre ejecuciones de tarea (Ejemplo: días)El tipo de evento solar cuando el proceso debe ejecutarseDelta de Tiempo en segundos después de los cuales la programación no provocará que la tarea vuelva a ejecutarseZona horaria donde ejecutar la programación Cron. Por defecto UTC.Conmutar actividad de las tareas seleccionadasContador de ejecuciones totalesIncapaz de parsear el JSON: %scronometradocrontabcrontabscada {}cada {} {}intervalointervalostarea periódicatareas periódicasevento solareventos solarestarea "{0}" no encontradafue,fueron{0} tarea{1} {2} correctamente ejecutadas{0} tarea{1} {2} correctamente {3}django-celery-beat-2.6.0/django_celery_beat/locale/es/LC_MESSAGES/django.po000066400000000000000000000344661457112420500262260ustar00rootroot00000000000000# Spanish translation strings for django-celery-beat. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # , 2020. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-04-04 01:30+0000\n" "PO-Revision-Date: 2022-10-14 23:48+0200\n" "Last-Translator: Luis Saavedra \n" "Language-Team: \n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: Poedit 3.1.1\n" #: django_celery_beat/admin.py:64 msgid "Task (registered)" msgstr "Tarea (registrada)" #: django_celery_beat/admin.py:68 msgid "Task (custom)" msgstr "Tarea (personalizada)" #: django_celery_beat/admin.py:85 msgid "Need name of task" msgstr "Nombre de tarea necesario" #: django_celery_beat/admin.py:91 django_celery_beat/models.py:586 msgid "Only one can be set, in expires and expire_seconds" msgstr "" "Sólo uno de los campos puede ser definido, en expiración y segundos de " "expiración" #: django_celery_beat/admin.py:101 #, python-format msgid "Unable to parse JSON: %s" msgstr "Incapaz de parsear el JSON: %s" #: django_celery_beat/admin.py:167 #, python-brace-format msgid "{0} task{1} {2} successfully {3}" msgstr "{0} tarea{1} {2} correctamente {3}" #: django_celery_beat/admin.py:170 django_celery_beat/admin.py:232 msgid "was,were" msgstr "fue,fueron" #: django_celery_beat/admin.py:179 msgid "Enable selected tasks" msgstr "Habilitar tareas seleccionadas" #: django_celery_beat/admin.py:185 msgid "Disable selected tasks" msgstr "Deshabilitar tareas seleccionadas" #: django_celery_beat/admin.py:197 msgid "Toggle activity of selected tasks" msgstr "Conmutar actividad de las tareas seleccionadas" #: django_celery_beat/admin.py:217 #, python-brace-format msgid "task \"{0}\" not found" msgstr "tarea \"{0}\" no encontrada" #: django_celery_beat/admin.py:229 #, python-brace-format msgid "{0} task{1} {2} successfully run" msgstr "{0} tarea{1} {2} correctamente ejecutadas" #: django_celery_beat/admin.py:235 msgid "Run selected tasks" msgstr "Ejecutar tareas seleccionadas" #: django_celery_beat/apps.py:13 msgid "Periodic Tasks" msgstr "Tareas Periódicas" #: django_celery_beat/models.py:26 msgid "Days" msgstr "Días" #: django_celery_beat/models.py:27 msgid "Hours" msgstr "Horas" #: django_celery_beat/models.py:28 msgid "Minutes" msgstr "Minutos" #: django_celery_beat/models.py:29 msgid "Seconds" msgstr "Segundos" #: django_celery_beat/models.py:30 msgid "Microseconds" msgstr "Microsegundos" #: django_celery_beat/models.py:34 msgid "Day" msgstr "Día" #: django_celery_beat/models.py:35 msgid "Hour" msgstr "Hora" #: django_celery_beat/models.py:36 msgid "Minute" msgstr "Minuto" #: django_celery_beat/models.py:37 msgid "Second" msgstr "Segundo" #: django_celery_beat/models.py:38 msgid "Microsecond" msgstr "Microsegundo" #: django_celery_beat/models.py:42 msgid "Astronomical dawn" msgstr "Amanecer astronómico" #: django_celery_beat/models.py:43 msgid "Civil dawn" msgstr "Amanecer civil" #: django_celery_beat/models.py:44 msgid "Nautical dawn" msgstr "Amanecer náutico" #: django_celery_beat/models.py:45 msgid "Astronomical dusk" msgstr "Anochecer astronómico" #: django_celery_beat/models.py:46 msgid "Civil dusk" msgstr "Anochecer civil" #: django_celery_beat/models.py:47 msgid "Nautical dusk" msgstr "Anochecer náutico" #: django_celery_beat/models.py:48 msgid "Solar noon" msgstr "Mediodía solar" #: django_celery_beat/models.py:49 msgid "Sunrise" msgstr "Amanecer" #: django_celery_beat/models.py:50 msgid "Sunset" msgstr "Puesta de sol" #: django_celery_beat/models.py:84 msgid "Solar Event" msgstr "Evento Solar" #: django_celery_beat/models.py:85 msgid "The type of solar event when the job should run" msgstr "El tipo de evento solar cuando el proceso debe ejecutarse" #: django_celery_beat/models.py:89 msgid "Latitude" msgstr "Latitud" #: django_celery_beat/models.py:90 msgid "Run the task when the event happens at this latitude" msgstr "Ejecutar la tarea cuando el evento ocurra a esta latitud" #: django_celery_beat/models.py:95 msgid "Longitude" msgstr "Longitud" #: django_celery_beat/models.py:96 msgid "Run the task when the event happens at this longitude" msgstr "Ejecutar la tarea cuando el evento ocurra a esta longitud" #: django_celery_beat/models.py:103 msgid "solar event" msgstr "evento solar" #: django_celery_beat/models.py:104 msgid "solar events" msgstr "eventos solares" #: django_celery_beat/models.py:153 msgid "Number of Periods" msgstr "Número de Períodos" #: django_celery_beat/models.py:154 msgid "Number of interval periods to wait before running the task again" msgstr "" "Número de períodos de intervalo a esperar antes de ejecutar esta tarea de " "nuevo" #: django_celery_beat/models.py:160 msgid "Interval Period" msgstr "Período de intervalo" #: django_celery_beat/models.py:161 msgid "The type of period between task runs (Example: days)" msgstr "El tipo de período entre ejecuciones de tarea (Ejemplo: días)" #: django_celery_beat/models.py:167 msgid "interval" msgstr "intervalo" #: django_celery_beat/models.py:168 msgid "intervals" msgstr "intervalos" #: django_celery_beat/models.py:195 msgid "every {}" msgstr "cada {}" #: django_celery_beat/models.py:200 msgid "every {} {}" msgstr "cada {} {}" #: django_celery_beat/models.py:211 msgid "Clock Time" msgstr "Hora y día" #: django_celery_beat/models.py:212 msgid "Run the task at clocked time" msgstr "Ejecuta la tarea en el momento indicado" #: django_celery_beat/models.py:218 django_celery_beat/models.py:219 msgid "clocked" msgstr "cronometrado" #: django_celery_beat/models.py:258 msgid "Minute(s)" msgstr "Minuto(s)" #: django_celery_beat/models.py:260 msgid "Cron Minutes to Run. Use \"*\" for \"all\". (Example: \"0,30\")" msgstr "" "Minutos Cron cuando ejecutar. Usa \"*\" para \"todos\". (Ejemplo: \"0,30\")" #: django_celery_beat/models.py:265 msgid "Hour(s)" msgstr "Hora(s)" #: django_celery_beat/models.py:267 msgid "Cron Hours to Run. Use \"*\" for \"all\". (Example: \"8,20\")" msgstr "" "Horas Cron cuando ejecutar. Usa \"*\" para \"todas\". (Ejemplo: \"8,20\")" #: django_celery_beat/models.py:272 msgid "Day(s) Of The Week" msgstr "Día(s) de la semana" #: django_celery_beat/models.py:274 msgid "Cron Days Of The Week to Run. Use \"*\" for \"all\", Sunday is 0 or 7, Monday is 1. (Example: \"0,5\")" msgstr "" "Días de la semana Cron cuando ejecutar. Usa \"*\" para \"todos\", Domingo es 0 o 7, Lunes es 1. (Ejemplo: " "\"0,5\")" #: django_celery_beat/models.py:280 msgid "Day(s) Of The Month" msgstr "Día(s) del mes" #: django_celery_beat/models.py:282 msgid "" "Cron Days Of The Month to Run. Use \"*\" for \"all\". (Example: \"1,15\")" msgstr "" "Días del mes Cron cuando ejecutar. Usa \"*\" para \"todos\". (Ejemplo: " "\"1,15\")" #: django_celery_beat/models.py:288 msgid "Month(s) Of The Year" msgstr "Mes(es) del año" #: django_celery_beat/models.py:290 msgid "" "Cron Months Of The Year to Run. Use \"*\" for \"all\". (Example: \"0,6\")" msgstr "" "Meses del año Cron cuando ejecutar. Usa \"*\" para \"todos\". (Ejemplo: " "\"0,6\")" #: django_celery_beat/models.py:297 msgid "Cron Timezone" msgstr "Zona horaria Cron" #: django_celery_beat/models.py:299 msgid "Timezone to Run the Cron Schedule on. Default is UTC." msgstr "Zona horaria donde ejecutar la programación Cron. Por defecto UTC." #: django_celery_beat/models.py:305 msgid "crontab" msgstr "crontab" #: django_celery_beat/models.py:306 msgid "crontabs" msgstr "crontabs" #: django_celery_beat/models.py:390 msgid "Name" msgstr "Nombre" #: django_celery_beat/models.py:391 msgid "Short Description For This Task" msgstr "Descripción corta para esta tarea" #: django_celery_beat/models.py:396 msgid "" "The Name of the Celery Task that Should be Run. (Example: \"proj.tasks." "import_contacts\")" msgstr "" "Nombre de la tarea Celery que debe ser ejecutada. (Ejemplo: \"proj.tasks." "import_contacts\")" #: django_celery_beat/models.py:404 msgid "Interval Schedule" msgstr "Intervalo de programación" #: django_celery_beat/models.py:405 msgid "" "Interval Schedule to run the task on. Set only one schedule type, leave the " "others null." msgstr "" "Intervalo de programación donde ejecutar la tarea. Establece sólo un tipo de " "programación, deja el resto en blanco." #: django_celery_beat/models.py:410 msgid "Crontab Schedule" msgstr "Programación Crontab" #: django_celery_beat/models.py:411 msgid "" "Crontab Schedule to run the task on. Set only one schedule type, leave the " "others null." msgstr "" "Programación Crontab con la cual ejecutar la tarea. Establece sólo un tipo " "de programación, deja el resto en blanco." #: django_celery_beat/models.py:416 msgid "Solar Schedule" msgstr "Programación solar" #: django_celery_beat/models.py:417 msgid "" "Solar Schedule to run the task on. Set only one schedule type, leave the " "others null." msgstr "" "Programación solar con la cual ejecutar la tarea. Establece sólo un tipo de " "programación, deja el resto en blanco." #: django_celery_beat/models.py:422 msgid "Clocked Schedule" msgstr "Programación horaria" #: django_celery_beat/models.py:423 msgid "" "Clocked Schedule to run the task on. Set only one schedule type, leave the " "others null." msgstr "" "Programación horaria con la cual ejecutar la tarea. Establece sólo un tipo " "de programación, deja el resto en blanco." #: django_celery_beat/models.py:429 msgid "Positional Arguments" msgstr "Argumentos posicionales" #: django_celery_beat/models.py:431 msgid "JSON encoded positional arguments (Example: [\"arg1\", \"arg2\"])" msgstr "" "Argumentos posicionales codificados en formato JSON. (Ejemplo: [\"arg1\", " "\"arg2\"])" #: django_celery_beat/models.py:436 msgid "Keyword Arguments" msgstr "Agumentos opcionales" #: django_celery_beat/models.py:438 msgid "JSON encoded keyword arguments (Example: {\"argument\": \"value\"})" msgstr "" "Argumentos opcionales codificados en formato JSON. (Ejemplo: {\"argument\": " "\"value\"})" #: django_celery_beat/models.py:444 msgid "Queue Override" msgstr "Invalidación de cola" #: django_celery_beat/models.py:446 msgid "Queue defined in CELERY_TASK_QUEUES. Leave None for default queuing." msgstr "" "Cola definida en CELERY_TASK_QUEUES. Dejala nula para la cola por defecto." #: django_celery_beat/models.py:455 msgid "Exchange" msgstr "Intercambio" #: django_celery_beat/models.py:456 msgid "Override Exchange for low-level AMQP routing" msgstr "Invalida intercambio para enrutamiento de bajo nivel de AMQP" #: django_celery_beat/models.py:460 msgid "Routing Key" msgstr "Clave de enrutamiento" #: django_celery_beat/models.py:461 msgid "Override Routing Key for low-level AMQP routing" msgstr "" "Invalida la clave de enrutamiento para enrutamiento de bajo nivel de AMQP" #: django_celery_beat/models.py:465 msgid "AMQP Message Headers" msgstr "Cabeceras de mensaje de AMQP" #: django_celery_beat/models.py:466 msgid "JSON encoded message headers for the AMQP message." msgstr "Cacbeceras de mensaje de AMQP codificadas en formato JSON." #: django_celery_beat/models.py:472 msgid "Priority" msgstr "Prioridad" #: django_celery_beat/models.py:474 msgid "" "Priority Number between 0 and 255. Supported by: RabbitMQ, Redis (priority " "reversed, 0 is highest)." msgstr "" "Número de prioridad entre 0 and 255. Soportado por: RabbitMQ, Redis " "(prioridad invertida, 0 es la más alta)." #: django_celery_beat/models.py:479 msgid "Expires Datetime" msgstr "Fecha de caducidad" #: django_celery_beat/models.py:481 msgid "" "Datetime after which the schedule will no longer trigger the task to run" msgstr "" "Fecha después de la cual la programación no provocará que la tarea vuelva a " "ejecutarse" #: django_celery_beat/models.py:486 msgid "Expires timedelta with seconds" msgstr "Delta de tiempo de expiración en segundos" #: django_celery_beat/models.py:488 msgid "" "Timedelta with seconds which the schedule will no longer trigger the task to " "run" msgstr "" "Delta de Tiempo en segundos después de los cuales la programación no " "provocará que la tarea vuelva a ejecutarse" #: django_celery_beat/models.py:494 msgid "One-off Task" msgstr "Tarea de ejecución única" #: django_celery_beat/models.py:496 msgid "If True, the schedule will only run the task a single time" msgstr "Si es verdadera, la programación sólo lanzará la tarea una vez" #: django_celery_beat/models.py:500 msgid "Start Datetime" msgstr "Fecha de comienzo" #: django_celery_beat/models.py:502 msgid "Datetime when the schedule should begin triggering the task to run" msgstr "" "Fecha cuando la programación debe comenzar a provocar la ejecución de la " "tarea" #: django_celery_beat/models.py:507 msgid "Enabled" msgstr "Habilitada" #: django_celery_beat/models.py:508 msgid "Set to False to disable the schedule" msgstr "Establece a Falso para deshabilitar la programación" #: django_celery_beat/models.py:513 msgid "Last Run Datetime" msgstr "Fecha de última ejecución" #: django_celery_beat/models.py:515 msgid "" "Datetime that the schedule last triggered the task to run. Reset to None if " "enabled is set to False." msgstr "" "Fecha en la cual la programación ejecutó la tarea por última vez. " "Reinicializa a None si enabled está establecido como falso." #: django_celery_beat/models.py:520 msgid "Total Run Count" msgstr "Contador de ejecuciones totales" #: django_celery_beat/models.py:522 msgid "Running count of how many times the schedule has triggered the task" msgstr "Contador de cuentas veces ha sido ejecutada la tarea" #: django_celery_beat/models.py:527 msgid "Last Modified" msgstr "Última modificación" #: django_celery_beat/models.py:528 msgid "Datetime that this PeriodicTask was last modified" msgstr "Fecha en la cual esta tarea periódica fue modificada por última vez" #: django_celery_beat/models.py:532 msgid "Description" msgstr "Descripción" #: django_celery_beat/models.py:534 msgid "Detailed description about the details of this Periodic Task" msgstr "Descripción detallada sobre los detalles de esta tarea periódica" #: django_celery_beat/models.py:543 msgid "periodic task" msgstr "tarea periódica" #: django_celery_beat/models.py:544 msgid "periodic tasks" msgstr "tareas periódicas" #: django_celery_beat/templates/admin/djcelery/change_list.html:6 msgid "Home" msgstr "Inicio" django-celery-beat-2.6.0/django_celery_beat/locale/fr/000077500000000000000000000000001457112420500226225ustar00rootroot00000000000000django-celery-beat-2.6.0/django_celery_beat/locale/fr/LC_MESSAGES/000077500000000000000000000000001457112420500244075ustar00rootroot00000000000000django-celery-beat-2.6.0/django_celery_beat/locale/fr/LC_MESSAGES/django.mo000066400000000000000000000233501457112420500262110ustar00rootroot00000000000000m@ A V h z  X C 7I 9  X H3 d| 1 B V Z n  <       = B J :P   Y ?2G=z     '/D I Wew@ 2, /7gvcD LXk45C7>$Fk V  &4XF4/P5U!   % 4 @M V wK (4FNwdNI+JuwZbFKb " (J4&"-# )3C:~{D)9nC#9 B L Yg ny S<?N4<  + l5  i (!$8!(]!H!K!@"\"d"0m"$"""w" e#r#####a#F?$E$i$L6%/%% %%%& & & & *&5&H&\&p&&-&"&,0EjSd-e2M9C=)Zca 5GA:l3 \N<h f4$%6F_D7i'O@K.L>[&;8 T*+B1k#/( ?RQ]`"PJXgUHVI!mb^Y WAMQP Message HeadersAstronomical dawnAstronomical duskCivil dawnCivil duskClock TimeClocked ScheduleClocked Schedule to run the task on. Set only one schedule type, leave the others null.Cron Days Of The Month to Run. Use "*" for "all". (Example: "1,15")Cron Hours to Run. Use "*" for "all". (Example: "8,20")Cron Minutes to Run. Use "*" for "all". (Example: "0,30")Cron TimezoneCrontab ScheduleCrontab Schedule to run the task on. Set only one schedule type, leave the others null.Datetime after which the schedule will no longer trigger the task to runDatetime that the schedule last triggered the task to run. Reset to None if enabled is set to False.Datetime that this PeriodicTask was last modifiedDatetime when the schedule should begin triggering the task to runDayDay(s) Of The MonthDay(s) Of The WeekDaysDescriptionDetailed description about the details of this Periodic TaskDisable selected tasksEnable selected tasksEnabledExchangeExpires DatetimeExpires timedelta with secondsHourHour(s)HoursIf True, the schedule will only run the task a single timeInterval PeriodInterval ScheduleInterval Schedule to run the task on. Set only one schedule type, leave the others null.JSON encoded keyword arguments (Example: {"argument": "value"})JSON encoded message headers for the AMQP message.JSON encoded positional arguments (Example: ["arg1", "arg2"])Keyword ArgumentsLast ModifiedLast Run DatetimeLatitudeLongitudeMicrosecondMicrosecondsMinuteMinute(s)MinutesMonth(s) Of The YearNameNautical dawnNautical duskNeed name of taskNumber of PeriodsNumber of interval periods to wait before running the task againOne-off TaskOnly one can be set, in expires and expire_secondsOverride Exchange for low-level AMQP routingOverride Routing Key for low-level AMQP routingPeriodic TasksPositional ArgumentsPriorityPriority Number between 0 and 255. Supported by: RabbitMQ, Redis (priority reversed, 0 is highest).Queue OverrideQueue defined in CELERY_TASK_QUEUES. Leave None for default queuing.Routing KeyRun selected tasksRun the task at clocked timeRun the task when the event happens at this latitudeRun the task when the event happens at this longitudeRunning count of how many times the schedule has triggered the taskSecondSecondsSet to False to disable the scheduleShort Description For This TaskSolar EventSolar ScheduleSolar Schedule to run the task on. Set only one schedule type, leave the others null.Solar noonStart DatetimeSunriseSunsetTask (custom)Task (registered)The Name of the Celery Task that Should be Run. (Example: "proj.tasks.import_contacts")The type of period between task runs (Example: days)The type of solar event when the job should runTimedelta with seconds which the schedule will no longer trigger the task to runTimezone to Run the Cron Schedule on. Default is UTC.Toggle activity of selected tasksTotal Run CountUnable to parse JSON: %sclockedcrontabcrontabsevery {}every {} {}intervalintervalsperiodic taskperiodic taskssolar eventsolar eventswas,were{0} task{1} {2} successfully run{0} task{1} {2} successfully {3}Project-Id-Version: PACKAGE VERSION Report-Msgid-Bugs-To: PO-Revision-Date: 2022-10-14 23:48+0200 Last-Translator: Álvaro Mondéjar Language-Team: nLanguage: fr Language: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n > 1); Message d'en-têtes AMQPAube astronomiqueCrépuscule astronomiqueAube civileCrépuscule civilHorairePlanification HorairePlanification Horaire pour démarrer cette tâche. Ne mettez qu'un seul type de planification, laissez les autres videsJours Du mois Cron pour démarrer. Utilisez "*" pour "tous". (Exemple: "1,15")Heures Cron pour démarrer. Utilisez "*" pour "toutes". (Exemple: "8,20")Minutes Cron pour démarrer. Utilisez "*" pour "toutes". (Exemple: "0,30")Fuseau horaire CronPlanification CrontabPlanification Crontab pour démarrer cette tâche. Ne mettez qu'un seul type de planification, laissez les autres videsDate et heure après laquelle la planification ne déclenchera plus la tâche à démarrerDate et heure à laquelle la planification à dernièrement déclenchée la tâche à démarrer. Est remis à Vide si activé est mis à FauxDate et heure de la dernière modification de cette Tâche PériodiqueDate et heure à laquelle la planification devrait commencer à déclencher la tâche à démarrerJourJour⋅s Du moisJour⋅s de la semaineJoursDescriptionDescription détaillée à propos des détails de cette Tâche PériodiqueDésactive les tâches sélectionnéesActive les tâches sélectionnéesActivéÉchangeDate et heure d'expirationDifférence de temps en secondes d'expirationHeureHeure⋅sHeuresSi Vrai, la planification ne démarrera la tâche qu'une seule foisPériode d'IntervalePlanification intervaléePlanification intervalée pour démarrer cette tâche. Ne mettez qu'un seul type de planification, laissez les autres videsArguments Nommés encodés en JSON (Exemple: {"argument": "valeur"})Message d'en-têtes encodés en JSON pour le message AMQPArguments positionnels encodés en JSON (Exemple: ["arg1", "arg2"])Arguments NommésDernière modificationDate et heure du dernier démarrageLatitudeLongitudeMicrosecondeMicrosecondesMinuteMinute⋅sMinutesMois De L'annéeNomAube nautiqueCrépuscule nautiqueBesoin du nom de la tâcheNombre de PériodesNombre d'intervale de périodes à attendre avant de démarrer la tâche à nouveauTâche PonctuelleSeulement un peu être définie, soit expires ou expire_secondsSurcharge d'échange pour un routage AMQP bas-niveauSurcharge de clé de routage pour un routage AMQP bas-niveauTâches PériodiqueArguments PositionnelsPrioritéValeur de priorité entre 0 et 255. Supporté par: RabbitMQ, Redis (priorité inversé, 0 est plus élevé).Surcharge de file d'attenteFile d'attente définie dans CELERY_TASK_QEUEUS. Laissez Vide pour la mise en file d'attente par défaut.Clé de routageDémarre les tâches sélectionnéesDémarre la tâche à l'horaire définieDémarre cette tâche lorsque l'évènement se produit à cette latitudeDémarre cette tâche lorsque cet évènement se produit à cette longitudeCompte combien de fois la planification a déclenchée la tâcheSecondeSecondesMettre à Faux pour désactiver la planificationDescription courte pour cette tâcheÉvènement SolairePlanification SolairePlanification Solaire pour démarrer cette tâche. Ne mettez qu'un seul type de planification, laissez les autres videsMidi solaireDate et heure de démarrageLever du soleilCoucher du soleilTâche (personalisée)Tâche (enregistrée)Le nom de la tâche Celery qui devrait être démarrée. (Exemple: "proj.tasks.import_contacts")Le type de période entre chaque démarrage de tâche (Exemple: jours)Le type d'évènement solaire pour lequel la tâche devrait démarrerDifférence de temps en secondes à laquelle la planification ne déclenchera plus la tâche à démarrerFuseau horaire pour lequel démarrer la planification Cron. UTC par défaut.Bascule l'activité des tâches sélectionnéesNombre total de démarragesIncapable d'analyser le JSON: %shorairecrontabcrontabschaque {}chaque {} {}intervaleintervalestâche périodiquetâches périodiqueévènement solaireévènements solairea été,ont été{0} tâche{1} {2} a fonctionnée avec succès{0} tâche{1} {2} avec succès {3}django-celery-beat-2.6.0/django_celery_beat/locale/fr/LC_MESSAGES/django.po000066400000000000000000000357461457112420500262300ustar00rootroot00000000000000# French translation strings for django-celery-beat. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # , 2019. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-12-22 19:03+0000\n" "PO-Revision-Date: 2022-10-14 23:48+0200\n" "Last-Translator: Álvaro Mondéjar \n" "Language-Team: nLanguage: fr\n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: django_celery_beat/admin.py:60 msgid "Task (registered)" msgstr "Tâche (enregistrée)" #: django_celery_beat/admin.py:64 msgid "Task (custom)" msgstr "Tâche (personalisée)" #: django_celery_beat/admin.py:81 msgid "Need name of task" msgstr "Besoin du nom de la tâche" #: django_celery_beat/admin.py:87 django_celery_beat/models.py:605 msgid "Only one can be set, in expires and expire_seconds" msgstr "Seulement un peu être définie, soit expires ou expire_seconds" #: django_celery_beat/admin.py:97 #, python-format msgid "Unable to parse JSON: %s" msgstr "Incapable d'analyser le JSON: %s" #: django_celery_beat/admin.py:125 #, fuzzy #| msgid "Solar Schedule" msgid "Schedule" msgstr "Planification Solaire" #: django_celery_beat/admin.py:130 #, fuzzy #| msgid "Keyword Arguments" msgid "Arguments" msgstr "Arguments Nommés" #: django_celery_beat/admin.py:134 msgid "Execution Options" msgstr "" #: django_celery_beat/admin.py:177 #, python-brace-format msgid "{0} task{1} {2} successfully {3}" msgstr "{0} tâche{1} {2} avec succès {3}" #: django_celery_beat/admin.py:180 django_celery_beat/admin.py:247 msgid "was,were" msgstr "a été,ont été" #: django_celery_beat/admin.py:189 msgid "Enable selected tasks" msgstr "Active les tâches sélectionnées" #: django_celery_beat/admin.py:195 msgid "Disable selected tasks" msgstr "Désactive les tâches sélectionnées" #: django_celery_beat/admin.py:207 msgid "Toggle activity of selected tasks" msgstr "Bascule l'activité des tâches sélectionnées" #: django_celery_beat/admin.py:228 #, fuzzy, python-brace-format #| msgid "task \"{0}\" not found" msgid "task \"{not_found_task_name}\" not found" msgstr "tâche \"{0}\" introuvable" #: django_celery_beat/admin.py:244 #, python-brace-format msgid "{0} task{1} {2} successfully run" msgstr "{0} tâche{1} {2} a fonctionnée avec succès" #: django_celery_beat/admin.py:250 msgid "Run selected tasks" msgstr "Démarre les tâches sélectionnées" #: django_celery_beat/apps.py:13 msgid "Periodic Tasks" msgstr "Tâches Périodique" #: django_celery_beat/models.py:30 msgid "Days" msgstr "Jours" #: django_celery_beat/models.py:31 msgid "Hours" msgstr "Heures" #: django_celery_beat/models.py:32 msgid "Minutes" msgstr "Minutes" #: django_celery_beat/models.py:33 msgid "Seconds" msgstr "Secondes" #: django_celery_beat/models.py:34 msgid "Microseconds" msgstr "Microsecondes" #: django_celery_beat/models.py:38 msgid "Day" msgstr "Jour" #: django_celery_beat/models.py:39 msgid "Hour" msgstr "Heure" #: django_celery_beat/models.py:40 msgid "Minute" msgstr "Minute" #: django_celery_beat/models.py:41 msgid "Second" msgstr "Seconde" #: django_celery_beat/models.py:42 msgid "Microsecond" msgstr "Microseconde" #: django_celery_beat/models.py:46 msgid "Astronomical dawn" msgstr "Aube astronomique" #: django_celery_beat/models.py:47 msgid "Civil dawn" msgstr "Aube civile" #: django_celery_beat/models.py:48 msgid "Nautical dawn" msgstr "Aube nautique" #: django_celery_beat/models.py:49 msgid "Astronomical dusk" msgstr "Crépuscule astronomique" #: django_celery_beat/models.py:50 msgid "Civil dusk" msgstr "Crépuscule civil" #: django_celery_beat/models.py:51 msgid "Nautical dusk" msgstr "Crépuscule nautique" #: django_celery_beat/models.py:52 msgid "Solar noon" msgstr "Midi solaire" #: django_celery_beat/models.py:53 msgid "Sunrise" msgstr "Lever du soleil" #: django_celery_beat/models.py:54 msgid "Sunset" msgstr "Coucher du soleil" #: django_celery_beat/models.py:88 msgid "Solar Event" msgstr "Évènement Solaire" #: django_celery_beat/models.py:89 msgid "The type of solar event when the job should run" msgstr "Le type d'évènement solaire pour lequel la tâche devrait démarrer" #: django_celery_beat/models.py:93 msgid "Latitude" msgstr "Latitude" #: django_celery_beat/models.py:94 msgid "Run the task when the event happens at this latitude" msgstr "Démarre cette tâche lorsque l'évènement se produit à cette latitude" #: django_celery_beat/models.py:99 msgid "Longitude" msgstr "Longitude" #: django_celery_beat/models.py:100 msgid "Run the task when the event happens at this longitude" msgstr "Démarre cette tâche lorsque cet évènement se produit à cette longitude" #: django_celery_beat/models.py:107 msgid "solar event" msgstr "évènement solaire" #: django_celery_beat/models.py:108 msgid "solar events" msgstr "évènements solaire" #: django_celery_beat/models.py:158 msgid "Number of Periods" msgstr "Nombre de Périodes" #: django_celery_beat/models.py:159 msgid "Number of interval periods to wait before running the task again" msgstr "" "Nombre d'intervale de périodes à attendre avant de démarrer la tâche à " "nouveau" #: django_celery_beat/models.py:165 msgid "Interval Period" msgstr "Période d'Intervale" #: django_celery_beat/models.py:166 msgid "The type of period between task runs (Example: days)" msgstr "Le type de période entre chaque démarrage de tâche (Exemple: jours)" #: django_celery_beat/models.py:172 msgid "interval" msgstr "intervale" #: django_celery_beat/models.py:173 msgid "intervals" msgstr "intervales" #: django_celery_beat/models.py:200 msgid "every {}" msgstr "chaque {}" #: django_celery_beat/models.py:205 msgid "every {} {}" msgstr "chaque {} {}" #: django_celery_beat/models.py:216 msgid "Clock Time" msgstr "Horaire" #: django_celery_beat/models.py:217 msgid "Run the task at clocked time" msgstr "Démarre la tâche à l'horaire définie" #: django_celery_beat/models.py:223 django_celery_beat/models.py:224 msgid "clocked" msgstr "horaire" #: django_celery_beat/models.py:264 msgid "Minute(s)" msgstr "Minute⋅s" #: django_celery_beat/models.py:266 msgid "Cron Minutes to Run. Use \"*\" for \"all\". (Example: \"0,30\")" msgstr "" "Minutes Cron pour démarrer. Utilisez \"*\" pour \"toutes\". (Exemple: " "\"0,30\")" #: django_celery_beat/models.py:271 msgid "Hour(s)" msgstr "Heure⋅s" #: django_celery_beat/models.py:273 msgid "Cron Hours to Run. Use \"*\" for \"all\". (Example: \"8,20\")" msgstr "" "Heures Cron pour démarrer. Utilisez \"*\" pour \"toutes\". (Exemple: " "\"8,20\")" #: django_celery_beat/models.py:278 msgid "Day(s) Of The Week" msgstr "Jour⋅s de la semaine" #: django_celery_beat/models.py:280 #, fuzzy #| msgid "" #| "Cron Days Of The Week to Run. Use \"*\" for \"all\". (Example: \"0,5\")" msgid "" "Cron Days Of The Week to Run. Use \"*\" for \"all\", Sunday is 0 or 7, " "Monday is 1. (Example: \"0,5\")" msgstr "" "Jours De La Semaine Cron pour Démarrer. Utilisez \"*\" pour \"tous\". " "(Exemple: \"0,5\")" #: django_celery_beat/models.py:286 msgid "Day(s) Of The Month" msgstr "Jour⋅s Du mois" #: django_celery_beat/models.py:288 msgid "" "Cron Days Of The Month to Run. Use \"*\" for \"all\". (Example: \"1,15\")" msgstr "" "Jours Du mois Cron pour démarrer. Utilisez \"*\" pour \"tous\". (Exemple: " "\"1,15\")" #: django_celery_beat/models.py:294 msgid "Month(s) Of The Year" msgstr "Mois De L'année" #: django_celery_beat/models.py:296 #, fuzzy #| msgid "" #| "Cron Months Of The Year to Run. Use \"*\" for \"all\". (Example: \"0,6\")" msgid "" "Cron Months (1-12) Of The Year to Run. Use \"*\" for \"all\". (Example: " "\"1,12\")" msgstr "" "Mois De L'année Cron pour démarrer. Utilisez \"*\" pour \"tous\". (Exemple: " ",6\")" #: django_celery_beat/models.py:304 msgid "Cron Timezone" msgstr "Fuseau horaire Cron" #: django_celery_beat/models.py:306 msgid "Timezone to Run the Cron Schedule on. Default is UTC." msgstr "" "Fuseau horaire pour lequel démarrer la planification Cron. UTC par défaut." #: django_celery_beat/models.py:312 msgid "crontab" msgstr "crontab" #: django_celery_beat/models.py:313 msgid "crontabs" msgstr "crontabs" #: django_celery_beat/models.py:404 msgid "Name" msgstr "Nom" #: django_celery_beat/models.py:405 msgid "Short Description For This Task" msgstr "Description courte pour cette tâche" #: django_celery_beat/models.py:410 msgid "" "The Name of the Celery Task that Should be Run. (Example: \"proj.tasks." "import_contacts\")" msgstr "" "Le nom de la tâche Celery qui devrait être démarrée. (Exemple: \"proj.tasks." "import_contacts\")" #: django_celery_beat/models.py:418 msgid "Interval Schedule" msgstr "Planification intervalée" #: django_celery_beat/models.py:419 msgid "" "Interval Schedule to run the task on. Set only one schedule type, leave the " "others null." msgstr "" "Planification intervalée pour démarrer cette tâche. Ne mettez qu'un seul " "type de planification, laissez les autres vides" #: django_celery_beat/models.py:424 msgid "Crontab Schedule" msgstr "Planification Crontab" #: django_celery_beat/models.py:425 msgid "" "Crontab Schedule to run the task on. Set only one schedule type, leave the " "others null." msgstr "" "Planification Crontab pour démarrer cette tâche. Ne mettez qu'un seul type " "de planification, laissez les autres vides" #: django_celery_beat/models.py:430 msgid "Solar Schedule" msgstr "Planification Solaire" #: django_celery_beat/models.py:431 msgid "" "Solar Schedule to run the task on. Set only one schedule type, leave the " "others null." msgstr "" "Planification Solaire pour démarrer cette tâche. Ne mettez qu'un seul type " "de planification, laissez les autres vides" #: django_celery_beat/models.py:436 msgid "Clocked Schedule" msgstr "Planification Horaire" #: django_celery_beat/models.py:437 msgid "" "Clocked Schedule to run the task on. Set only one schedule type, leave the " "others null." msgstr "" "Planification Horaire pour démarrer cette tâche. Ne mettez qu'un seul type " "de planification, laissez les autres vides" #: django_celery_beat/models.py:443 msgid "Positional Arguments" msgstr "Arguments Positionnels" #: django_celery_beat/models.py:445 msgid "JSON encoded positional arguments (Example: [\"arg1\", \"arg2\"])" msgstr "Arguments positionnels encodés en JSON (Exemple: [\"arg1\", \"arg2\"])" #: django_celery_beat/models.py:450 msgid "Keyword Arguments" msgstr "Arguments Nommés" #: django_celery_beat/models.py:452 msgid "JSON encoded keyword arguments (Example: {\"argument\": \"value\"})" msgstr "Arguments Nommés encodés en JSON (Exemple: {\"argument\": \"valeur\"})" #: django_celery_beat/models.py:458 msgid "Queue Override" msgstr "Surcharge de file d'attente" #: django_celery_beat/models.py:460 msgid "Queue defined in CELERY_TASK_QUEUES. Leave None for default queuing." msgstr "" "File d'attente définie dans CELERY_TASK_QEUEUS. Laissez Vide pour la mise en " "file d'attente par défaut." #: django_celery_beat/models.py:469 msgid "Exchange" msgstr "Échange" #: django_celery_beat/models.py:470 msgid "Override Exchange for low-level AMQP routing" msgstr "Surcharge d'échange pour un routage AMQP bas-niveau" #: django_celery_beat/models.py:474 msgid "Routing Key" msgstr "Clé de routage" #: django_celery_beat/models.py:475 msgid "Override Routing Key for low-level AMQP routing" msgstr "Surcharge de clé de routage pour un routage AMQP bas-niveau" #: django_celery_beat/models.py:479 msgid "AMQP Message Headers" msgstr "Message d'en-têtes AMQP" #: django_celery_beat/models.py:480 msgid "JSON encoded message headers for the AMQP message." msgstr "Message d'en-têtes encodés en JSON pour le message AMQP" #: django_celery_beat/models.py:486 msgid "Priority" msgstr "Priorité" #: django_celery_beat/models.py:488 msgid "" "Priority Number between 0 and 255. Supported by: RabbitMQ, Redis (priority " "reversed, 0 is highest)." msgstr "" "Valeur de priorité entre 0 et 255. Supporté par: RabbitMQ, Redis (priorité " "inversé, 0 est plus élevé)." #: django_celery_beat/models.py:493 msgid "Expires Datetime" msgstr "Date et heure d'expiration" #: django_celery_beat/models.py:495 msgid "" "Datetime after which the schedule will no longer trigger the task to run" msgstr "" "Date et heure après laquelle la planification ne déclenchera plus la tâche à " "démarrer" #: django_celery_beat/models.py:500 msgid "Expires timedelta with seconds" msgstr "Différence de temps en secondes d'expiration" #: django_celery_beat/models.py:502 msgid "" "Timedelta with seconds which the schedule will no longer trigger the task to " "run" msgstr "" "Différence de temps en secondes à laquelle la planification ne déclenchera " "plus la tâche à démarrer" #: django_celery_beat/models.py:508 msgid "One-off Task" msgstr "Tâche Ponctuelle" #: django_celery_beat/models.py:510 msgid "If True, the schedule will only run the task a single time" msgstr "Si Vrai, la planification ne démarrera la tâche qu'une seule fois" #: django_celery_beat/models.py:514 msgid "Start Datetime" msgstr "Date et heure de démarrage" #: django_celery_beat/models.py:516 msgid "Datetime when the schedule should begin triggering the task to run" msgstr "" "Date et heure à laquelle la planification devrait commencer à déclencher la " "tâche à démarrer" #: django_celery_beat/models.py:521 msgid "Enabled" msgstr "Activé" #: django_celery_beat/models.py:522 msgid "Set to False to disable the schedule" msgstr "Mettre à Faux pour désactiver la planification" #: django_celery_beat/models.py:527 msgid "Last Run Datetime" msgstr "Date et heure du dernier démarrage" #: django_celery_beat/models.py:529 msgid "" "Datetime that the schedule last triggered the task to run. Reset to None if " "enabled is set to False." msgstr "" "Date et heure à laquelle la planification à dernièrement déclenchée la tâche " "à démarrer. Est remis à Vide si activé est mis à Faux" #: django_celery_beat/models.py:534 msgid "Total Run Count" msgstr "Nombre total de démarrages" #: django_celery_beat/models.py:536 msgid "Running count of how many times the schedule has triggered the task" msgstr "Compte combien de fois la planification a déclenchée la tâche" #: django_celery_beat/models.py:541 msgid "Last Modified" msgstr "Dernière modification" #: django_celery_beat/models.py:542 msgid "Datetime that this PeriodicTask was last modified" msgstr "Date et heure de la dernière modification de cette Tâche Périodique" #: django_celery_beat/models.py:546 msgid "Description" msgstr "Description" #: django_celery_beat/models.py:548 msgid "Detailed description about the details of this Periodic Task" msgstr "Description détaillée à propos des détails de cette Tâche Périodique" #: django_celery_beat/models.py:557 msgid "periodic task" msgstr "tâche périodique" #: django_celery_beat/models.py:558 msgid "periodic tasks" msgstr "tâches périodique" #: django_celery_beat/templates/admin/djcelery/change_list.html:6 msgid "Home" msgstr "" django-celery-beat-2.6.0/django_celery_beat/locale/ko/000077500000000000000000000000001457112420500226245ustar00rootroot00000000000000django-celery-beat-2.6.0/django_celery_beat/locale/ko/LC_MESSAGES/000077500000000000000000000000001457112420500244115ustar00rootroot00000000000000django-celery-beat-2.6.0/django_celery_beat/locale/ko/LC_MESSAGES/django.mo000066400000000000000000000224471457112420500262210ustar00rootroot00000000000000nP Q f x  X C 7Y 9  X HC d 1 B# f j ~  <      . M R W _ :e   Y ?2\=    + 2<DY ^ lz@ 2,/L|c D am45CLS$[ V ,4 ;IX[4/P5j!  " ,: I Ub k 5    # 1<M14 1@ r|BwR-+$(,375>1t. #;*fmIILA"2BFJNR c q%ZSKjN4{=X ! +- 5Y Q Q 3!N!R!1V!1! !!!_" f"t"{"""Y" #-0#P^#$#?# $$"$G$O$W$`$ g$q$ z$ $$ $ $ $8$($-1FkTe.f3N:D>*[db 6HB;m4!]O=i 5%&7G`E8j(PAL/M?\'<9 U+g,C2l$0) @SR^a#QKYhVIWJ"nc_Z XAMQP Message HeadersAstronomical dawnAstronomical duskCivil dawnCivil duskClock TimeClocked ScheduleClocked Schedule to run the task on. Set only one schedule type, leave the others null.Cron Days Of The Month to Run. Use "*" for "all". (Example: "1,15")Cron Hours to Run. Use "*" for "all". (Example: "8,20")Cron Minutes to Run. Use "*" for "all". (Example: "0,30")Cron TimezoneCrontab ScheduleCrontab Schedule to run the task on. Set only one schedule type, leave the others null.Datetime after which the schedule will no longer trigger the task to runDatetime that the schedule last triggered the task to run. Reset to None if enabled is set to False.Datetime that this PeriodicTask was last modifiedDatetime when the schedule should begin triggering the task to runDayDay(s) Of The MonthDay(s) Of The WeekDaysDescriptionDetailed description about the details of this Periodic TaskDisable selected tasksEnable selected tasksEnabledExchangeExpires DatetimeExpires timedelta with secondsHomeHourHour(s)HoursIf True, the schedule will only run the task a single timeInterval PeriodInterval ScheduleInterval Schedule to run the task on. Set only one schedule type, leave the others null.JSON encoded keyword arguments (Example: {"argument": "value"})JSON encoded message headers for the AMQP message.JSON encoded positional arguments (Example: ["arg1", "arg2"])Keyword ArgumentsLast ModifiedLast Run DatetimeLatitudeLongitudeMicrosecondMicrosecondsMinuteMinute(s)MinutesMonth(s) Of The YearNameNautical dawnNautical duskNeed name of taskNumber of PeriodsNumber of interval periods to wait before running the task againOne-off TaskOnly one can be set, in expires and expire_secondsOverride Exchange for low-level AMQP routingOverride Routing Key for low-level AMQP routingPeriodic TasksPositional ArgumentsPriorityPriority Number between 0 and 255. Supported by: RabbitMQ, Redis (priority reversed, 0 is highest).Queue OverrideQueue defined in CELERY_TASK_QUEUES. Leave None for default queuing.Routing KeyRun selected tasksRun the task at clocked timeRun the task when the event happens at this latitudeRun the task when the event happens at this longitudeRunning count of how many times the schedule has triggered the taskSecondSecondsSet to False to disable the scheduleShort Description For This TaskSolar EventSolar ScheduleSolar Schedule to run the task on. Set only one schedule type, leave the others null.Solar noonStart DatetimeSunriseSunsetTask (custom)Task (registered)The Name of the Celery Task that Should be Run. (Example: "proj.tasks.import_contacts")The type of period between task runs (Example: days)The type of solar event when the job should runTimedelta with seconds which the schedule will no longer trigger the task to runTimezone to Run the Cron Schedule on. Default is UTC.Toggle activity of selected tasksTotal Run CountUnable to parse JSON: %sclockedcrontabcrontabsevery {}every {} {}intervalintervalsperiodic taskperiodic taskssolar eventsolar eventswas,were{0} task{1} {2} successfully run{0} task{1} {2} successfully {3}Project-Id-Version: PACKAGE VERSION Report-Msgid-Bugs-To: PO-Revision-Date: 2022-10-14 23:48+0200 Last-Translator: Jaeyoung Heo Language-Team: Language: ko MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=1; plural=0; AMQP 메시지 헤더천문 박명천문 황혼시민 박명시민 황혼Clock TimeClocked Schedule태스크 실행을 위한 Clocked Schedule. 한 종류의 스케줄 타입을 지정하면 나머지는 빈 값으로 두어야 합니다.Cron 의 일. 모두인 경우 "*". (예: "1,15")Cron 의 시간. 모두인 경우 "*". (예: "8,20")Cron 의 분. 모두인 경우 "*". (예: "0,30")타임존Crontab Schedule태스크 실행 Crontab Schedule. 한 종류의 스케줄 타입을 지정하면 나머지는 빈 값으로 두어야 합니다.만료 일시 이후에는 태스크가 작동하지 않습니다.태스크가 최종적으로 작동한 시간. 만약 테스크가 비활성화 된 경우 None 으로 지정됩니다.태스크가 최종적으로 변경된 일시태스크 스케줄의 작동 시작 일시일일요일일설명태스크에 대한 상세 설명을 작성합니다.선택된 태스크들을 비활성화 합니다.선택된 태스크들을 활성화 합니다.활성화 여부Exchange만료 일시초 단위 만료 시간Home시시시간체크된 경우, 태스크는 한 번만 실행 됩니다.간격Interval Schedule태스크 실행 Interval Schedule. 한 종류의 스케줄 타입을 지정하면 나머지는 빈 값으로 두어야 합니다.JSON 형태로 인코딩된 키워드 인자 (예: {"argument": "value"})AMQP 메시지를 위해 JSON 형식으로 인코딩 된 메시지 헤더JSON 형태로 인코딩된 위치 인자 (예: ["arg1", "arg2"])Keyword Arguments최종 변경 일시최종 작동 일시위도경도마이크로초마이크로초분분분월태스크 이름항해 박명항해 황혼태스크 이름이 필요 합니다.매태스크의 다음 동작까지 몇 번의 간격을 기다릴 것인지 입력합니다.One-off 태스크'만료 시각'과 '만료 기준 초' 중에 하나만 지정할 수 있습니다.low-level AMQP 를 원하는 경우 Exchange 를 오버라이드 합니다.low-level AMQP 를 원하는 경우 Routing Key 를 오버라이드 합니다.주기적인 태스크들Positional ArgumentsPriority0과 255사이의 우선 순위 숫자. RabbitMQ, Redis 에서 지원합니다. (0이 높은 우선순위를 가집니다.)Queue OverrideCELERY_TASK_QUEES 에 정의된 큐, 빈 값으로 두면 기본 큐를 사용합니다.Routing Key선택된 태스크들을 실행 합니다.Clock Time 기준으로 태스크를 작동합니다.입력된 위도에서 Solar Event 가 발생하면 태스크를 실행합니다.입력된 경도에서 Solar Event 가 발생하면 태스크를 실행합니다.태스크의 실행 횟수초초체크를 해제하면 비활성화가 됩니다.태스크의 간단한 설명을 작성합니다.Solar EventSolar Schedule태스크 실행을 위한 Solar Schedule. 한 종류의 스케줄 타입을 지정하면 나머지는 빈 값으로 두어야 합니다.정오시작 일시일출일몰사용자 정의 태스크등록 태스크 목록실행 되어야 하는 셀러리 태스크의 이름 (예: "proj.tasks.import_contacts")실행 간격 (예: 일, 시간)태스크가 작동 해야 하는 Solar Event입력된 만료 초가 지난 뒤에는 태스크가 작동하지 않습니다.Cron 의 타임존. 기본값은 UTC선택된 태스크들의 활성화 상태를 토글 합니다.실행 횟수해석할 수 없습니다. JSON: %sclockedcrontabcrontabs매 {}매 {} {}intervalintervalsperiodic taskperiodic taskssolar eventsolar events가,들이{0} 태스크{1} {2} 성공적으로 작동했습니다.{0} 태스크{1} {2} 성공적으로 {3}django-celery-beat-2.6.0/django_celery_beat/locale/ko/LC_MESSAGES/django.po000066400000000000000000000346211457112420500262210ustar00rootroot00000000000000# Korean translation strings for django-celery-beat # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , 2022. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-12-22 19:03+0000\n" "PO-Revision-Date: 2022-10-14 23:48+0200\n" "Last-Translator: Jaeyoung Heo \n" "Language-Team: \n" "Language: ko\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" #: django_celery_beat/admin.py:60 msgid "Task (registered)" msgstr "등록 태스크 목록" #: django_celery_beat/admin.py:64 msgid "Task (custom)" msgstr "사용자 정의 태스크" #: django_celery_beat/admin.py:81 msgid "Need name of task" msgstr "태스크 이름이 필요 합니다." #: django_celery_beat/admin.py:87 django_celery_beat/models.py:605 msgid "Only one can be set, in expires and expire_seconds" msgstr "'만료 시각'과 '만료 기준 초' 중에 하나만 지정할 수 있습니다." #: django_celery_beat/admin.py:97 #, python-format msgid "Unable to parse JSON: %s" msgstr "해석할 수 없습니다. JSON: %s" #: django_celery_beat/admin.py:125 #, fuzzy #| msgid "Solar Schedule" msgid "Schedule" msgstr "Solar Schedule" #: django_celery_beat/admin.py:130 #, fuzzy #| msgid "Keyword Arguments" msgid "Arguments" msgstr "Keyword Arguments" #: django_celery_beat/admin.py:134 msgid "Execution Options" msgstr "" #: django_celery_beat/admin.py:177 #, python-brace-format msgid "{0} task{1} {2} successfully {3}" msgstr "{0} 태스크{1} {2} 성공적으로 {3}" #: django_celery_beat/admin.py:180 django_celery_beat/admin.py:247 msgid "was,were" msgstr "가,들이" #: django_celery_beat/admin.py:189 msgid "Enable selected tasks" msgstr "선택된 태스크들을 활성화 합니다." #: django_celery_beat/admin.py:195 msgid "Disable selected tasks" msgstr "선택된 태스크들을 비활성화 합니다." #: django_celery_beat/admin.py:207 msgid "Toggle activity of selected tasks" msgstr "선택된 태스크들의 활성화 상태를 토글 합니다." #: django_celery_beat/admin.py:228 #, fuzzy, python-brace-format #| msgid "task \"{0}\" not found" msgid "task \"{not_found_task_name}\" not found" msgstr "태스크 \"{0}\" 을 찾을 수 없습니다." #: django_celery_beat/admin.py:244 #, python-brace-format msgid "{0} task{1} {2} successfully run" msgstr "{0} 태스크{1} {2} 성공적으로 작동했습니다." #: django_celery_beat/admin.py:250 msgid "Run selected tasks" msgstr "선택된 태스크들을 실행 합니다." #: django_celery_beat/apps.py:13 msgid "Periodic Tasks" msgstr "주기적인 태스크들" #: django_celery_beat/models.py:30 msgid "Days" msgstr "일" #: django_celery_beat/models.py:31 msgid "Hours" msgstr "시간" #: django_celery_beat/models.py:32 msgid "Minutes" msgstr "분" #: django_celery_beat/models.py:33 msgid "Seconds" msgstr "초" #: django_celery_beat/models.py:34 msgid "Microseconds" msgstr "마이크로초" #: django_celery_beat/models.py:38 msgid "Day" msgstr "일" #: django_celery_beat/models.py:39 msgid "Hour" msgstr "시" #: django_celery_beat/models.py:40 msgid "Minute" msgstr "분" #: django_celery_beat/models.py:41 msgid "Second" msgstr "초" #: django_celery_beat/models.py:42 msgid "Microsecond" msgstr "마이크로초" #: django_celery_beat/models.py:46 msgid "Astronomical dawn" msgstr "천문 박명" #: django_celery_beat/models.py:47 msgid "Civil dawn" msgstr "시민 박명" #: django_celery_beat/models.py:48 msgid "Nautical dawn" msgstr "항해 박명" #: django_celery_beat/models.py:49 msgid "Astronomical dusk" msgstr "천문 황혼" #: django_celery_beat/models.py:50 msgid "Civil dusk" msgstr "시민 황혼" #: django_celery_beat/models.py:51 msgid "Nautical dusk" msgstr "항해 황혼" #: django_celery_beat/models.py:52 msgid "Solar noon" msgstr "정오" #: django_celery_beat/models.py:53 msgid "Sunrise" msgstr "일출" #: django_celery_beat/models.py:54 msgid "Sunset" msgstr "일몰" #: django_celery_beat/models.py:88 msgid "Solar Event" msgstr "Solar Event" #: django_celery_beat/models.py:89 msgid "The type of solar event when the job should run" msgstr "태스크가 작동 해야 하는 Solar Event" #: django_celery_beat/models.py:93 msgid "Latitude" msgstr "위도" #: django_celery_beat/models.py:94 msgid "Run the task when the event happens at this latitude" msgstr "입력된 위도에서 Solar Event 가 발생하면 태스크를 실행합니다." #: django_celery_beat/models.py:99 msgid "Longitude" msgstr "경도" #: django_celery_beat/models.py:100 msgid "Run the task when the event happens at this longitude" msgstr "입력된 경도에서 Solar Event 가 발생하면 태스크를 실행합니다." #: django_celery_beat/models.py:107 msgid "solar event" msgstr "solar event" #: django_celery_beat/models.py:108 msgid "solar events" msgstr "solar events" #: django_celery_beat/models.py:158 msgid "Number of Periods" msgstr "매" #: django_celery_beat/models.py:159 msgid "Number of interval periods to wait before running the task again" msgstr "태스크의 다음 동작까지 몇 번의 간격을 기다릴 것인지 입력합니다." #: django_celery_beat/models.py:165 msgid "Interval Period" msgstr "간격" #: django_celery_beat/models.py:166 msgid "The type of period between task runs (Example: days)" msgstr "실행 간격 (예: 일, 시간)" #: django_celery_beat/models.py:172 msgid "interval" msgstr "interval" #: django_celery_beat/models.py:173 msgid "intervals" msgstr "intervals" #: django_celery_beat/models.py:200 msgid "every {}" msgstr "매 {}" #: django_celery_beat/models.py:205 msgid "every {} {}" msgstr "매 {} {}" #: django_celery_beat/models.py:216 msgid "Clock Time" msgstr "Clock Time" #: django_celery_beat/models.py:217 msgid "Run the task at clocked time" msgstr "Clock Time 기준으로 태스크를 작동합니다." #: django_celery_beat/models.py:223 django_celery_beat/models.py:224 msgid "clocked" msgstr "clocked" #: django_celery_beat/models.py:264 msgid "Minute(s)" msgstr "분" #: django_celery_beat/models.py:266 msgid "Cron Minutes to Run. Use \"*\" for \"all\". (Example: \"0,30\")" msgstr "Cron 의 분. 모두인 경우 \"*\". (예: \"0,30\")" #: django_celery_beat/models.py:271 msgid "Hour(s)" msgstr "시" #: django_celery_beat/models.py:273 msgid "Cron Hours to Run. Use \"*\" for \"all\". (Example: \"8,20\")" msgstr "Cron 의 시간. 모두인 경우 \"*\". (예: \"8,20\")" #: django_celery_beat/models.py:278 msgid "Day(s) Of The Week" msgstr "요일" #: django_celery_beat/models.py:280 #, fuzzy #| msgid "" #| "Cron Days Of The Week to Run. Use \"*\" for \"all\". (Example: \"0,5\")" msgid "" "Cron Days Of The Week to Run. Use \"*\" for \"all\", Sunday is 0 or 7, " "Monday is 1. (Example: \"0,5\")" msgstr "Cron 의 요일. 모두인 경우 \"*\". (예: \"0,5\")" #: django_celery_beat/models.py:286 msgid "Day(s) Of The Month" msgstr "일" #: django_celery_beat/models.py:288 msgid "" "Cron Days Of The Month to Run. Use \"*\" for \"all\". (Example: \"1,15\")" msgstr "Cron 의 일. 모두인 경우 \"*\". (예: \"1,15\")" #: django_celery_beat/models.py:294 msgid "Month(s) Of The Year" msgstr "월" #: django_celery_beat/models.py:296 #, fuzzy #| msgid "" #| "Cron Months Of The Year to Run. Use \"*\" for \"all\". (Example: \"0,6\")" msgid "" "Cron Months (1-12) Of The Year to Run. Use \"*\" for \"all\". (Example: " "\"1,12\")" msgstr "Cron 의 월. 모두인 경우 \"*\"." #: django_celery_beat/models.py:304 msgid "Cron Timezone" msgstr "타임존" #: django_celery_beat/models.py:306 msgid "Timezone to Run the Cron Schedule on. Default is UTC." msgstr "Cron 의 타임존. 기본값은 UTC" #: django_celery_beat/models.py:312 msgid "crontab" msgstr "crontab" #: django_celery_beat/models.py:313 msgid "crontabs" msgstr "crontabs" #: django_celery_beat/models.py:404 msgid "Name" msgstr "태스크 이름" #: django_celery_beat/models.py:405 msgid "Short Description For This Task" msgstr "태스크의 간단한 설명을 작성합니다." #: django_celery_beat/models.py:410 msgid "" "The Name of the Celery Task that Should be Run. (Example: \"proj.tasks." "import_contacts\")" msgstr "" "실행 되어야 하는 셀러리 태스크의 이름 (예: \"proj.tasks.import_contacts\")" #: django_celery_beat/models.py:418 msgid "Interval Schedule" msgstr "Interval Schedule" #: django_celery_beat/models.py:419 msgid "" "Interval Schedule to run the task on. Set only one schedule type, leave the " "others null." msgstr "" "태스크 실행 Interval Schedule. 한 종류의 스케줄 타입을 지정하면 나머지는 빈 " "값으로 두어야 합니다." #: django_celery_beat/models.py:424 msgid "Crontab Schedule" msgstr "Crontab Schedule" #: django_celery_beat/models.py:425 msgid "" "Crontab Schedule to run the task on. Set only one schedule type, leave the " "others null." msgstr "" "태스크 실행 Crontab Schedule. 한 종류의 스케줄 타입을 지정하면 나머지는 빈 값" "으로 두어야 합니다." #: django_celery_beat/models.py:430 msgid "Solar Schedule" msgstr "Solar Schedule" #: django_celery_beat/models.py:431 msgid "" "Solar Schedule to run the task on. Set only one schedule type, leave the " "others null." msgstr "" "태스크 실행을 위한 Solar Schedule. 한 종류의 스케줄 타입을 지정하면 나머지는 " "빈 값으로 두어야 합니다." #: django_celery_beat/models.py:436 msgid "Clocked Schedule" msgstr "Clocked Schedule" #: django_celery_beat/models.py:437 msgid "" "Clocked Schedule to run the task on. Set only one schedule type, leave the " "others null." msgstr "" "태스크 실행을 위한 Clocked Schedule. 한 종류의 스케줄 타입을 지정하면 나머지" "는 빈 값으로 두어야 합니다." #: django_celery_beat/models.py:443 msgid "Positional Arguments" msgstr "Positional Arguments" #: django_celery_beat/models.py:445 msgid "JSON encoded positional arguments (Example: [\"arg1\", \"arg2\"])" msgstr "JSON 형태로 인코딩된 위치 인자 (예: [\"arg1\", \"arg2\"])" #: django_celery_beat/models.py:450 msgid "Keyword Arguments" msgstr "Keyword Arguments" #: django_celery_beat/models.py:452 msgid "JSON encoded keyword arguments (Example: {\"argument\": \"value\"})" msgstr "JSON 형태로 인코딩된 키워드 인자 (예: {\"argument\": \"value\"})" #: django_celery_beat/models.py:458 msgid "Queue Override" msgstr "Queue Override" #: django_celery_beat/models.py:460 msgid "Queue defined in CELERY_TASK_QUEUES. Leave None for default queuing." msgstr "CELERY_TASK_QUEES 에 정의된 큐, 빈 값으로 두면 기본 큐를 사용합니다." #: django_celery_beat/models.py:469 msgid "Exchange" msgstr "Exchange" #: django_celery_beat/models.py:470 msgid "Override Exchange for low-level AMQP routing" msgstr "low-level AMQP 를 원하는 경우 Exchange 를 오버라이드 합니다." #: django_celery_beat/models.py:474 msgid "Routing Key" msgstr "Routing Key" #: django_celery_beat/models.py:475 msgid "Override Routing Key for low-level AMQP routing" msgstr "low-level AMQP 를 원하는 경우 Routing Key 를 오버라이드 합니다." #: django_celery_beat/models.py:479 msgid "AMQP Message Headers" msgstr "AMQP 메시지 헤더" #: django_celery_beat/models.py:480 msgid "JSON encoded message headers for the AMQP message." msgstr "AMQP 메시지를 위해 JSON 형식으로 인코딩 된 메시지 헤더" #: django_celery_beat/models.py:486 msgid "Priority" msgstr "Priority" #: django_celery_beat/models.py:488 msgid "" "Priority Number between 0 and 255. Supported by: RabbitMQ, Redis (priority " "reversed, 0 is highest)." msgstr "" "0과 255사이의 우선 순위 숫자. RabbitMQ, Redis 에서 지원합니다. (0이 높은 우선" "순위를 가집니다.)" #: django_celery_beat/models.py:493 msgid "Expires Datetime" msgstr "만료 일시" #: django_celery_beat/models.py:495 msgid "" "Datetime after which the schedule will no longer trigger the task to run" msgstr "만료 일시 이후에는 태스크가 작동하지 않습니다." #: django_celery_beat/models.py:500 msgid "Expires timedelta with seconds" msgstr "초 단위 만료 시간" #: django_celery_beat/models.py:502 msgid "" "Timedelta with seconds which the schedule will no longer trigger the task to " "run" msgstr "입력된 만료 초가 지난 뒤에는 태스크가 작동하지 않습니다." #: django_celery_beat/models.py:508 msgid "One-off Task" msgstr "One-off 태스크" #: django_celery_beat/models.py:510 msgid "If True, the schedule will only run the task a single time" msgstr "체크된 경우, 태스크는 한 번만 실행 됩니다." #: django_celery_beat/models.py:514 msgid "Start Datetime" msgstr "시작 일시" #: django_celery_beat/models.py:516 msgid "Datetime when the schedule should begin triggering the task to run" msgstr "태스크 스케줄의 작동 시작 일시" #: django_celery_beat/models.py:521 msgid "Enabled" msgstr "활성화 여부" #: django_celery_beat/models.py:522 msgid "Set to False to disable the schedule" msgstr "체크를 해제하면 비활성화가 됩니다." #: django_celery_beat/models.py:527 msgid "Last Run Datetime" msgstr "최종 작동 일시" #: django_celery_beat/models.py:529 msgid "" "Datetime that the schedule last triggered the task to run. Reset to None if " "enabled is set to False." msgstr "" "태스크가 최종적으로 작동한 시간. 만약 테스크가 비활성화 된 경우 None 으로 지" "정됩니다." #: django_celery_beat/models.py:534 msgid "Total Run Count" msgstr "실행 횟수" #: django_celery_beat/models.py:536 msgid "Running count of how many times the schedule has triggered the task" msgstr "태스크의 실행 횟수" #: django_celery_beat/models.py:541 msgid "Last Modified" msgstr "최종 변경 일시" #: django_celery_beat/models.py:542 msgid "Datetime that this PeriodicTask was last modified" msgstr "태스크가 최종적으로 변경된 일시" #: django_celery_beat/models.py:546 msgid "Description" msgstr "설명" #: django_celery_beat/models.py:548 msgid "Detailed description about the details of this Periodic Task" msgstr "태스크에 대한 상세 설명을 작성합니다." #: django_celery_beat/models.py:557 msgid "periodic task" msgstr "periodic task" #: django_celery_beat/models.py:558 msgid "periodic tasks" msgstr "periodic tasks" #: django_celery_beat/templates/admin/djcelery/change_list.html:6 msgid "Home" msgstr "Home" django-celery-beat-2.6.0/django_celery_beat/locale/ru/000077500000000000000000000000001457112420500226415ustar00rootroot00000000000000django-celery-beat-2.6.0/django_celery_beat/locale/ru/LC_MESSAGES/000077500000000000000000000000001457112420500244265ustar00rootroot00000000000000django-celery-beat-2.6.0/django_celery_beat/locale/ru/LC_MESSAGES/django.mo000066400000000000000000000244751457112420500262410ustar00rootroot00000000000000a$,89 NYXjC7 9? y  X H d: 1 B   , ? D <P         : * : YL ? 2 = W i w        @  M,Z/cHDW 45 CC$ VM \jX|4/ 5:!p      %2 ; \}*P { Yy[_/'yxiH\JU,20 #e,%xW sd)%( HUd}    ,l"#,/' )8 b u -!6!#!2!:"hM"j"R!#t##C#<#$2$Q$!%/9%3i%d%[&Y^&Z&I']'>y' ''''''('('B(-j(-((9(+)R=YAN>" @7XL[ <J9CG%_QO&F,\ D`B/P#0(T!14  +S.WI^Z] K:$6*U)H?Ea'8VM;25-3AMQP Message HeadersClock TimeClocked ScheduleClocked Schedule to run the task on. Set only one schedule type, leave the others null.Cron Days Of The Month to Run. Use "*" for "all". (Example: "1,15")Cron Hours to Run. Use "*" for "all". (Example: "8,20")Cron Minutes to Run. Use "*" for "all". (Example: "0,30")Cron TimezoneCrontab ScheduleCrontab Schedule to run the task on. Set only one schedule type, leave the others null.Datetime after which the schedule will no longer trigger the task to runDatetime that the schedule last triggered the task to run. Reset to None if enabled is set to False.Datetime that this PeriodicTask was last modifiedDatetime when the schedule should begin triggering the task to runDayDay(s) Of The MonthDay(s) Of The WeekDaysDescriptionDetailed description about the details of this Periodic TaskDisable selected tasksEnable selected tasksEnabledExchangeExpires DatetimeHourHour(s)HoursIf True, the schedule will only run the task a single timeInterval PeriodInterval ScheduleInterval Schedule to run the task on. Set only one schedule type, leave the others null.JSON encoded keyword arguments (Example: {"argument": "value"})JSON encoded message headers for the AMQP message.JSON encoded positional arguments (Example: ["arg1", "arg2"])Keyword ArgumentsLast ModifiedLast Run DatetimeLatitudeLongitudeMicrosecondMicrosecondsMinuteMinute(s)MinutesMonth(s) Of The YearNameNeed name of taskNumber of PeriodsNumber of interval periods to wait before running the task againOne-off TaskOverride Exchange for low-level AMQP routingOverride Routing Key for low-level AMQP routingPeriodic TasksPositional ArgumentsPriorityPriority Number between 0 and 255. Supported by: RabbitMQ, Redis (priority reversed, 0 is highest).Queue OverrideQueue defined in CELERY_TASK_QUEUES. Leave None for default queuing.Routing KeyRun selected tasksRun the task at clocked timeRun the task when the event happens at this latitudeRun the task when the event happens at this longitudeRunning count of how many times the schedule has triggered the taskSecondSecondsSet to False to disable the scheduleShort Description For This TaskSolar EventSolar ScheduleSolar Schedule to run the task on. Set only one schedule type, leave the others null.Start DatetimeTask (custom)Task (registered)The Name of the Celery Task that Should be Run. (Example: "proj.tasks.import_contacts")The type of period between task runs (Example: days)The type of solar event when the job should runTimezone to Run the Cron Schedule on. Default is UTC.Toggle activity of selected tasksTotal Run CountUnable to parse JSON: %sclockedcrontabcrontabsevery {}every {} {}intervalintervalsperiodic taskperiodic taskssolar eventsolar eventswas,were{0} task{1} {2} successfully run{0} task{1} {2} successfully {3}Project-Id-Version: 1.5.0 Report-Msgid-Bugs-To: PO-Revision-Date: 2022-10-14 23:48+0200 Last-Translator: Daniil Kharkov Language-Team: LANGUAGE Language: ru MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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); Заголовки сообщения AMQPВремяХронометрическоеХронометрическое расписание для запуска задачи. Выберите только один тип расписания, остальные оставьте пустыми.Cron дни. Используйте "*" для "каждый". (Например: "1,15")Cron часы. Используйте "*" для "каждый". (Например: "8,20")Cron минуты. Используйте "*" для "каждую". (Например: "0,30")Временная зона для CronCrontabCrontab расписание для запуска задачи. Выберите только один тип расписания, остальные оставьте пустыми.Время, после которого расписание больше не будет запускать задачуВремя последнего вызова задачи. None если задача выключена.Время последнего изменения этой задачиВремя начала вызовов задачи расписаниемденьДниДни неделиДниОписаниеПодробное описание того, что делает эта задачаВыключить выбранные задачиВключить выбранные задачиАктивнаExchangeИстекаетвремяЧасыЧасыЕсли включено, то задача будет запущена только один разИнтервальный периодИнтервалИнтервальное расписание для запуска задачи. Выберите только один тип расписания, остальные оставьте пустыми.Закодированные в JSON именованные аргументы (Например: {"argument": "value"})Закодированные в JSON заголовки для AMQP сообщения.Закодированные в JSON позиционные аргументы (Например: ["arg1", "arg2"])Именованные аргументыПоследнее изменениеПоследний запускШиротаДолготаМикросекундыМикросекундыминутМинутыМинутыМесяцыНазваниеУкажите название задачиЧисло периодовКоличество периодов интервала перед новым запуском задачиОдноразовая задачаOverride Exchange for low-level AMQP routingOverride Routing Key for low-level AMQP routingПериодические ЗадачиПозиционные аргументыПриоритетЧисло между 0 и 255. Поддерживается в: RabbitMQ, Redis (приоритет по убыванию, 0 наивысший).Переопределение очередиОчередь задана в CELERY_TASK_QUEUES. Оставьте None для стандартного распределения.Ключ маршрутизацииЗапустить выбранные задачиЗапуск задачи в указанное времяЗапуск задачи, когда событие происходит на данной широтеЗапуск задачи, когда событие происходит на данной долготеКоличество запусков задачи этим расписаниемСекундыСекундыВыключите для отключения расписанияКраткое описание для этой задачиАстрономическоеАстрономическоеАстрономическое расписание для запуска задачи. Выберите только один тип расписания, остальные оставьте пустыми.Время началаЗадача (пользовательская)Задача (зарегистрированные)Имя запускаемой Celery задачи. (Например: "proj.tasks.import_contacts")Тип периода между запусками задачи (Например: дни)Тип астрономического события для запуска задачиВременная зона для Cron расписания. UTC по умолчанию.Переключить активность выбранных задачЗапусков всегоНевозможно проанализировать JSON: %sвремяcrontabcrontabкаждые {}каждые {} {}интервалинтервалыпериодическая задачапериодические задачиастрономическое событиеастрономические событиябыл, были{0} задача{1} {2} успешно выполнена{0} задача {1} {2} успешно {3}django-celery-beat-2.6.0/django_celery_beat/locale/ru/LC_MESSAGES/django.po000066400000000000000000000406051457112420500262350ustar00rootroot00000000000000# 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 , YEAR. # msgid "" msgstr "" "Project-Id-Version: 1.5.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-12-22 19:03+0000\n" "PO-Revision-Date: 2022-10-14 23:48+0200\n" "Last-Translator: Daniil Kharkov \n" "Language-Team: LANGUAGE \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_celery_beat/admin.py:60 msgid "Task (registered)" msgstr "Задача (зарегистрированные)" #: django_celery_beat/admin.py:64 msgid "Task (custom)" msgstr "Задача (пользовательская)" #: django_celery_beat/admin.py:81 msgid "Need name of task" msgstr "Укажите название задачи" #: django_celery_beat/admin.py:87 django_celery_beat/models.py:605 msgid "Only one can be set, in expires and expire_seconds" msgstr "" #: django_celery_beat/admin.py:97 #, python-format msgid "Unable to parse JSON: %s" msgstr "Невозможно проанализировать JSON: %s" #: django_celery_beat/admin.py:125 #, fuzzy #| msgid "Solar Schedule" msgid "Schedule" msgstr "Астрономическое" #: django_celery_beat/admin.py:130 #, fuzzy #| msgid "Keyword Arguments" msgid "Arguments" msgstr "Именованные аргументы" #: django_celery_beat/admin.py:134 msgid "Execution Options" msgstr "" #: django_celery_beat/admin.py:177 #, python-brace-format msgid "{0} task{1} {2} successfully {3}" msgstr "{0} задача {1} {2} успешно {3}" #: django_celery_beat/admin.py:180 django_celery_beat/admin.py:247 msgid "was,were" msgstr "был, были" #: django_celery_beat/admin.py:189 msgid "Enable selected tasks" msgstr "Включить выбранные задачи" #: django_celery_beat/admin.py:195 msgid "Disable selected tasks" msgstr "Выключить выбранные задачи" #: django_celery_beat/admin.py:207 msgid "Toggle activity of selected tasks" msgstr "Переключить активность выбранных задач" #: django_celery_beat/admin.py:228 #, fuzzy, python-brace-format #| msgid "task \"{0}\" not found" msgid "task \"{not_found_task_name}\" not found" msgstr "задача \"{0}\" не найдена" #: django_celery_beat/admin.py:244 #, python-brace-format msgid "{0} task{1} {2} successfully run" msgstr "{0} задача{1} {2} успешно выполнена" #: django_celery_beat/admin.py:250 msgid "Run selected tasks" msgstr "Запустить выбранные задачи" #: django_celery_beat/apps.py:13 msgid "Periodic Tasks" msgstr "Периодические Задачи" #: django_celery_beat/models.py:30 msgid "Days" msgstr "Дни" #: django_celery_beat/models.py:31 msgid "Hours" msgstr "Часы" #: django_celery_beat/models.py:32 msgid "Minutes" msgstr "Минуты" #: django_celery_beat/models.py:33 msgid "Seconds" msgstr "Секунды" #: django_celery_beat/models.py:34 msgid "Microseconds" msgstr "Микросекунды" #: django_celery_beat/models.py:38 msgid "Day" msgstr "день" #: django_celery_beat/models.py:39 msgid "Hour" msgstr "время" #: django_celery_beat/models.py:40 msgid "Minute" msgstr "минут" #: django_celery_beat/models.py:41 msgid "Second" msgstr "Секунды" #: django_celery_beat/models.py:42 msgid "Microsecond" msgstr "Микросекунды" #: django_celery_beat/models.py:46 msgid "Astronomical dawn" msgstr "" #: django_celery_beat/models.py:47 msgid "Civil dawn" msgstr "" #: django_celery_beat/models.py:48 msgid "Nautical dawn" msgstr "" #: django_celery_beat/models.py:49 msgid "Astronomical dusk" msgstr "" #: django_celery_beat/models.py:50 msgid "Civil dusk" msgstr "" #: django_celery_beat/models.py:51 msgid "Nautical dusk" msgstr "" #: django_celery_beat/models.py:52 #, fuzzy #| msgid "Solar Event" msgid "Solar noon" msgstr "Астрономическое" #: django_celery_beat/models.py:53 msgid "Sunrise" msgstr "" #: django_celery_beat/models.py:54 msgid "Sunset" msgstr "" #: django_celery_beat/models.py:88 msgid "Solar Event" msgstr "Астрономическое" #: django_celery_beat/models.py:89 msgid "The type of solar event when the job should run" msgstr "Тип астрономического события для запуска задачи" #: django_celery_beat/models.py:93 msgid "Latitude" msgstr "Широта" #: django_celery_beat/models.py:94 msgid "Run the task when the event happens at this latitude" msgstr "Запуск задачи, когда событие происходит на данной широте" #: django_celery_beat/models.py:99 msgid "Longitude" msgstr "Долгота" #: django_celery_beat/models.py:100 msgid "Run the task when the event happens at this longitude" msgstr "Запуск задачи, когда событие происходит на данной долготе" #: django_celery_beat/models.py:107 msgid "solar event" msgstr "астрономическое событие" #: django_celery_beat/models.py:108 msgid "solar events" msgstr "астрономические события" #: django_celery_beat/models.py:158 msgid "Number of Periods" msgstr "Число периодов" #: django_celery_beat/models.py:159 msgid "Number of interval periods to wait before running the task again" msgstr "Количество периодов интервала перед новым запуском задачи" #: django_celery_beat/models.py:165 msgid "Interval Period" msgstr "Интервальный период" #: django_celery_beat/models.py:166 msgid "The type of period between task runs (Example: days)" msgstr "Тип периода между запусками задачи (Например: дни)" #: django_celery_beat/models.py:172 msgid "interval" msgstr "интервал" #: django_celery_beat/models.py:173 msgid "intervals" msgstr "интервалы" #: django_celery_beat/models.py:200 msgid "every {}" msgstr "каждые {}" #: django_celery_beat/models.py:205 msgid "every {} {}" msgstr "каждые {} {}" #: django_celery_beat/models.py:216 msgid "Clock Time" msgstr "Время" #: django_celery_beat/models.py:217 msgid "Run the task at clocked time" msgstr "Запуск задачи в указанное время" #: django_celery_beat/models.py:223 django_celery_beat/models.py:224 msgid "clocked" msgstr "время" #: django_celery_beat/models.py:264 msgid "Minute(s)" msgstr "Минуты" #: django_celery_beat/models.py:266 msgid "Cron Minutes to Run. Use \"*\" for \"all\". (Example: \"0,30\")" msgstr "Cron минуты. Используйте \"*\" для \"каждую\". (Например: \"0,30\")" #: django_celery_beat/models.py:271 msgid "Hour(s)" msgstr "Часы" #: django_celery_beat/models.py:273 msgid "Cron Hours to Run. Use \"*\" for \"all\". (Example: \"8,20\")" msgstr "Cron часы. Используйте \"*\" для \"каждый\". (Например: \"8,20\")" #: django_celery_beat/models.py:278 msgid "Day(s) Of The Week" msgstr "Дни недели" #: django_celery_beat/models.py:280 #, fuzzy #| msgid "" #| "Cron Days Of The Week to Run. Use \"*\" for \"all\". (Example: \"0,5\")" msgid "" "Cron Days Of The Week to Run. Use \"*\" for \"all\", Sunday is 0 or 7, " "Monday is 1. (Example: \"0,5\")" msgstr "Cron дни недели. Используйте \"*\" для \"каждый\". (Например: \"0,5\")" #: django_celery_beat/models.py:286 msgid "Day(s) Of The Month" msgstr "Дни" #: django_celery_beat/models.py:288 msgid "" "Cron Days Of The Month to Run. Use \"*\" for \"all\". (Example: \"1,15\")" msgstr "Cron дни. Используйте \"*\" для \"каждый\". (Например: \"1,15\")" #: django_celery_beat/models.py:294 msgid "Month(s) Of The Year" msgstr "Месяцы" #: django_celery_beat/models.py:296 #, fuzzy #| msgid "" #| "Cron Months Of The Year to Run. Use \"*\" for \"all\". (Example: \"0,6\")" msgid "" "Cron Months (1-12) Of The Year to Run. Use \"*\" for \"all\". (Example: " "\"1,12\")" msgstr "Cron месяцы. Используйте \"*\" для \"каждый\". (Например: \"0,6\")" #: django_celery_beat/models.py:304 msgid "Cron Timezone" msgstr "Временная зона для Cron" #: django_celery_beat/models.py:306 msgid "Timezone to Run the Cron Schedule on. Default is UTC." msgstr "Временная зона для Cron расписания. UTC по умолчанию." #: django_celery_beat/models.py:312 msgid "crontab" msgstr "crontab" #: django_celery_beat/models.py:313 msgid "crontabs" msgstr "crontab" #: django_celery_beat/models.py:404 msgid "Name" msgstr "Название" #: django_celery_beat/models.py:405 msgid "Short Description For This Task" msgstr "Краткое описание для этой задачи" #: django_celery_beat/models.py:410 msgid "" "The Name of the Celery Task that Should be Run. (Example: \"proj.tasks." "import_contacts\")" msgstr "" "Имя запускаемой Celery задачи. (Например: \"proj.tasks.import_contacts\")" #: django_celery_beat/models.py:418 msgid "Interval Schedule" msgstr "Интервал" #: django_celery_beat/models.py:419 msgid "" "Interval Schedule to run the task on. Set only one schedule type, leave the " "others null." msgstr "" "Интервальное расписание для запуска задачи. Выберите только один тип " "расписания, остальные оставьте пустыми." #: django_celery_beat/models.py:424 msgid "Crontab Schedule" msgstr "Crontab" #: django_celery_beat/models.py:425 msgid "" "Crontab Schedule to run the task on. Set only one schedule type, leave the " "others null." msgstr "" "Crontab расписание для запуска задачи. Выберите только один тип расписания, " "остальные оставьте пустыми." #: django_celery_beat/models.py:430 msgid "Solar Schedule" msgstr "Астрономическое" #: django_celery_beat/models.py:431 msgid "" "Solar Schedule to run the task on. Set only one schedule type, leave the " "others null." msgstr "" "Астрономическое расписание для запуска задачи. Выберите только один тип " "расписания, остальные оставьте пустыми." #: django_celery_beat/models.py:436 msgid "Clocked Schedule" msgstr "Хронометрическое" #: django_celery_beat/models.py:437 msgid "" "Clocked Schedule to run the task on. Set only one schedule type, leave the " "others null." msgstr "" "Хронометрическое расписание для запуска задачи. Выберите только один тип " "расписания, остальные оставьте пустыми." #: django_celery_beat/models.py:443 msgid "Positional Arguments" msgstr "Позиционные аргументы" #: django_celery_beat/models.py:445 msgid "JSON encoded positional arguments (Example: [\"arg1\", \"arg2\"])" msgstr "" "Закодированные в JSON позиционные аргументы (Например: [\"arg1\", \"arg2\"])" #: django_celery_beat/models.py:450 msgid "Keyword Arguments" msgstr "Именованные аргументы" #: django_celery_beat/models.py:452 msgid "JSON encoded keyword arguments (Example: {\"argument\": \"value\"})" msgstr "" "Закодированные в JSON именованные аргументы (Например: {\"argument\": " "\"value\"})" #: django_celery_beat/models.py:458 msgid "Queue Override" msgstr "Переопределение очереди" #: django_celery_beat/models.py:460 msgid "Queue defined in CELERY_TASK_QUEUES. Leave None for default queuing." msgstr "" "Очередь задана в CELERY_TASK_QUEUES. Оставьте None для стандартного " "распределения." #: django_celery_beat/models.py:469 msgid "Exchange" msgstr "Exchange" #: django_celery_beat/models.py:470 msgid "Override Exchange for low-level AMQP routing" msgstr "Override Exchange for low-level AMQP routing" #: django_celery_beat/models.py:474 msgid "Routing Key" msgstr "Ключ маршрутизации" #: django_celery_beat/models.py:475 msgid "Override Routing Key for low-level AMQP routing" msgstr "Override Routing Key for low-level AMQP routing" #: django_celery_beat/models.py:479 msgid "AMQP Message Headers" msgstr "Заголовки сообщения AMQP" #: django_celery_beat/models.py:480 msgid "JSON encoded message headers for the AMQP message." msgstr "Закодированные в JSON заголовки для AMQP сообщения." #: django_celery_beat/models.py:486 msgid "Priority" msgstr "Приоритет" #: django_celery_beat/models.py:488 msgid "" "Priority Number between 0 and 255. Supported by: RabbitMQ, Redis (priority " "reversed, 0 is highest)." msgstr "" "Число между 0 и 255. Поддерживается в: RabbitMQ, Redis (приоритет по " "убыванию, 0 наивысший)." #: django_celery_beat/models.py:493 msgid "Expires Datetime" msgstr "Истекает" #: django_celery_beat/models.py:495 msgid "" "Datetime after which the schedule will no longer trigger the task to run" msgstr "Время, после которого расписание больше не будет запускать задачу" #: django_celery_beat/models.py:500 msgid "Expires timedelta with seconds" msgstr "" #: django_celery_beat/models.py:502 #, fuzzy #| msgid "" #| "Datetime after which the schedule will no longer trigger the task to run" msgid "" "Timedelta with seconds which the schedule will no longer trigger the task to " "run" msgstr "Время, после которого расписание больше не будет запускать задачу" #: django_celery_beat/models.py:508 msgid "One-off Task" msgstr "Одноразовая задача" #: django_celery_beat/models.py:510 msgid "If True, the schedule will only run the task a single time" msgstr "Если включено, то задача будет запущена только один раз" #: django_celery_beat/models.py:514 msgid "Start Datetime" msgstr "Время начала" #: django_celery_beat/models.py:516 msgid "Datetime when the schedule should begin triggering the task to run" msgstr "Время начала вызовов задачи расписанием" #: django_celery_beat/models.py:521 msgid "Enabled" msgstr "Активна" #: django_celery_beat/models.py:522 msgid "Set to False to disable the schedule" msgstr "Выключите для отключения расписания" #: django_celery_beat/models.py:527 msgid "Last Run Datetime" msgstr "Последний запуск" #: django_celery_beat/models.py:529 msgid "" "Datetime that the schedule last triggered the task to run. Reset to None if " "enabled is set to False." msgstr "Время последнего вызова задачи. None если задача выключена." #: django_celery_beat/models.py:534 msgid "Total Run Count" msgstr "Запусков всего" #: django_celery_beat/models.py:536 msgid "Running count of how many times the schedule has triggered the task" msgstr "Количество запусков задачи этим расписанием" #: django_celery_beat/models.py:541 msgid "Last Modified" msgstr "Последнее изменение" #: django_celery_beat/models.py:542 msgid "Datetime that this PeriodicTask was last modified" msgstr "Время последнего изменения этой задачи" #: django_celery_beat/models.py:546 msgid "Description" msgstr "Описание" #: django_celery_beat/models.py:548 msgid "Detailed description about the details of this Periodic Task" msgstr "Подробное описание того, что делает эта задача" #: django_celery_beat/models.py:557 msgid "periodic task" msgstr "периодическая задача" #: django_celery_beat/models.py:558 msgid "periodic tasks" msgstr "периодические задачи" #: django_celery_beat/templates/admin/djcelery/change_list.html:6 msgid "Home" msgstr "" django-celery-beat-2.6.0/django_celery_beat/locale/zh_Hans/000077500000000000000000000000001457112420500236055ustar00rootroot00000000000000django-celery-beat-2.6.0/django_celery_beat/locale/zh_Hans/LC_MESSAGES/000077500000000000000000000000001457112420500253725ustar00rootroot00000000000000django-celery-beat-2.6.0/django_celery_beat/locale/zh_Hans/LC_MESSAGES/django.mo000066400000000000000000000211051457112420500271700ustar00rootroot00000000000000m@ A V h z  X C 7I 9  X H3 d| 1 B V Z n  <       = B J :P   Y ?2G=z     '/D I Wew@ 2, /7gvcD LXk45C7>$Fk V  &4XF4/P5U!   % 4 @M V w?      '[7OBB&i[B\.'*'DZ p z $1  [;v#3  ':AHOV]dk    3 7 +A+m   i 'J4 **$6: >_ x[    & G< ? - * 1!O!e!u!! ! !! !!!!! ! !" "(",0EjSd-e2M9C=)Zca 5GA:l3 \N<h f4$%6F_D7i'O@K.L>[&;8 T*+B1k#/( ?RQ]`"PJXgUHVI!mb^Y WAMQP Message HeadersAstronomical dawnAstronomical duskCivil dawnCivil duskClock TimeClocked ScheduleClocked Schedule to run the task on. Set only one schedule type, leave the others null.Cron Days Of The Month to Run. Use "*" for "all". (Example: "1,15")Cron Hours to Run. Use "*" for "all". (Example: "8,20")Cron Minutes to Run. Use "*" for "all". (Example: "0,30")Cron TimezoneCrontab ScheduleCrontab Schedule to run the task on. Set only one schedule type, leave the others null.Datetime after which the schedule will no longer trigger the task to runDatetime that the schedule last triggered the task to run. Reset to None if enabled is set to False.Datetime that this PeriodicTask was last modifiedDatetime when the schedule should begin triggering the task to runDayDay(s) Of The MonthDay(s) Of The WeekDaysDescriptionDetailed description about the details of this Periodic TaskDisable selected tasksEnable selected tasksEnabledExchangeExpires DatetimeExpires timedelta with secondsHourHour(s)HoursIf True, the schedule will only run the task a single timeInterval PeriodInterval ScheduleInterval Schedule to run the task on. Set only one schedule type, leave the others null.JSON encoded keyword arguments (Example: {"argument": "value"})JSON encoded message headers for the AMQP message.JSON encoded positional arguments (Example: ["arg1", "arg2"])Keyword ArgumentsLast ModifiedLast Run DatetimeLatitudeLongitudeMicrosecondMicrosecondsMinuteMinute(s)MinutesMonth(s) Of The YearNameNautical dawnNautical duskNeed name of taskNumber of PeriodsNumber of interval periods to wait before running the task againOne-off TaskOnly one can be set, in expires and expire_secondsOverride Exchange for low-level AMQP routingOverride Routing Key for low-level AMQP routingPeriodic TasksPositional ArgumentsPriorityPriority Number between 0 and 255. Supported by: RabbitMQ, Redis (priority reversed, 0 is highest).Queue OverrideQueue defined in CELERY_TASK_QUEUES. Leave None for default queuing.Routing KeyRun selected tasksRun the task at clocked timeRun the task when the event happens at this latitudeRun the task when the event happens at this longitudeRunning count of how many times the schedule has triggered the taskSecondSecondsSet to False to disable the scheduleShort Description For This TaskSolar EventSolar ScheduleSolar Schedule to run the task on. Set only one schedule type, leave the others null.Solar noonStart DatetimeSunriseSunsetTask (custom)Task (registered)The Name of the Celery Task that Should be Run. (Example: "proj.tasks.import_contacts")The type of period between task runs (Example: days)The type of solar event when the job should runTimedelta with seconds which the schedule will no longer trigger the task to runTimezone to Run the Cron Schedule on. Default is UTC.Toggle activity of selected tasksTotal Run CountUnable to parse JSON: %sclockedcrontabcrontabsevery {}every {} {}intervalintervalsperiodic taskperiodic taskssolar eventsolar eventswas,were{0} task{1} {2} successfully run{0} task{1} {2} successfully {3}Project-Id-Version: PACKAGE VERSION Report-Msgid-Bugs-To: PO-Revision-Date: 2022-10-14 23:48+0200 Last-Translator: Rainshaw Language-Team: x_zhuo Language: zh-Hans MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=1; plural=0; AMQP消息头天文黎明天文黄昏民事黎明民事黄昏定时时间定时时间表执行任务的定时时间表。 仅设置一种时间表类型,将其他保留为空。计划执行的每个月的第几天。将"*"用作"all"。(例如:"0,5")计划执行的小时。 将"*"用作"all"。(例如:"8,20")计划执行的分钟。 将"*"用作"all"。(例如:"0,30")计划任务的时区计划时间表执行任务的计划时间表。 仅设置一种时间表类型,将其他保留为空。过期时刻,计划表将在此时刻后不再触发任务执行最后一次触发任务执行的时刻。 如果enabled设置为False,则重置为None。该周期性任务的最后修改时刻时间表开始触发任务执行的时刻天一个月的第几天一个星期的第几天天描述有关此周期性任务的详细信息禁用选中的任务启用选中的任务已启用交换机过期时刻过期时间间隔,以秒为单位小时小时小时如果为True,则计划将仅运行任务一次间隔周期间隔时间表执行任务的间隔时间表。 仅设置一种时间表类型,将其他保留为空。JSON编码的关键字参数(例如: {"argument": "value"})AMQP消息的JSON编码消息头。JSON编码的位置参数(例如: ["arg1", "arg2"])关键字参数最后修改上次运行时刻纬度经度毫秒毫秒分钟分钟分钟一年的第几个月任务名航海黎明航海黄昏任务需要一个名称周期数再次执行任务之前要等待的间隔周期数一次任务不可以同时设置 expires 和 expire_seconds 字段覆盖交换机以进行低层级AMQP路由覆盖路由键以进行低层级AMQP路由周期任务位置参数优先级优先级数字,介于0和255之间。支持者:RabbitMQ,Redis(优先级颠倒,0是最高)。队列覆盖在 CELERY_TASK_QUEUES 定义的队列。保留空以进行默认排队。路由键运行选中的任务在定时时间执行任务当在此纬度发生事件时执行任务当在此经度发生事件时执行任务任务执行多少次的运行计数秒秒设置为False可禁用时间表该任务的简短说明日程事件日程时间表执行任务的日程时间表。 仅设置一种时间表类型,将其他保留为空。正午开始时间日出日落任务 (自定义)任务 (已注册的)被执行的任务的名称。(例如:"proj.tasks.import_contacts")任务每次执行之间的时间间隔类型(例如:天)当任务应该执行时的日程事件类型再过该秒后,不再触发任务执行执行计划任务表的时区。 默认为UTC。切换选中的任务总运行次数无法解析 JSON: %s定时计划任务计划任务每 {}每 {} {}间隔间隔周期性任务周期性任务日程事件日程事件将{0} 任务{1} {2} 启动成功{0} 任务{1} {2} 成功 {3}django-celery-beat-2.6.0/django_celery_beat/locale/zh_Hans/LC_MESSAGES/django.po000066400000000000000000000332711457112420500272020ustar00rootroot00000000000000# 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 , YEAR. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-12-22 19:03+0000\n" "PO-Revision-Date: 2022-10-14 23:48+0200\n" "Last-Translator: Rainshaw \n" "Language-Team: x_zhuo \n" "Language: zh-Hans \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" #: django_celery_beat/admin.py:60 msgid "Task (registered)" msgstr "任务 (已注册的)" #: django_celery_beat/admin.py:64 msgid "Task (custom)" msgstr "任务 (自定义)" #: django_celery_beat/admin.py:81 msgid "Need name of task" msgstr "任务需要一个名称" #: django_celery_beat/admin.py:87 django_celery_beat/models.py:605 msgid "Only one can be set, in expires and expire_seconds" msgstr "不可以同时设置 expires 和 expire_seconds 字段" #: django_celery_beat/admin.py:97 #, python-format msgid "Unable to parse JSON: %s" msgstr "无法解析 JSON: %s" #: django_celery_beat/admin.py:125 #, fuzzy #| msgid "Solar Schedule" msgid "Schedule" msgstr "日程时间表" #: django_celery_beat/admin.py:130 #, fuzzy #| msgid "Keyword Arguments" msgid "Arguments" msgstr "关键字参数" #: django_celery_beat/admin.py:134 msgid "Execution Options" msgstr "" #: django_celery_beat/admin.py:177 #, python-brace-format msgid "{0} task{1} {2} successfully {3}" msgstr "{0} 任务{1} {2} 成功 {3}" #: django_celery_beat/admin.py:180 django_celery_beat/admin.py:247 msgid "was,were" msgstr "将" #: django_celery_beat/admin.py:189 msgid "Enable selected tasks" msgstr "启用选中的任务" #: django_celery_beat/admin.py:195 msgid "Disable selected tasks" msgstr "禁用选中的任务" #: django_celery_beat/admin.py:207 msgid "Toggle activity of selected tasks" msgstr "切换选中的任务" #: django_celery_beat/admin.py:228 #, fuzzy, python-brace-format #| msgid "task \"{0}\" not found" msgid "task \"{not_found_task_name}\" not found" msgstr "未找到\"{0}\"任务" #: django_celery_beat/admin.py:244 #, python-brace-format msgid "{0} task{1} {2} successfully run" msgstr "{0} 任务{1} {2} 启动成功" #: django_celery_beat/admin.py:250 msgid "Run selected tasks" msgstr "运行选中的任务" #: django_celery_beat/apps.py:13 msgid "Periodic Tasks" msgstr "周期任务" #: django_celery_beat/models.py:30 msgid "Days" msgstr "天" #: django_celery_beat/models.py:31 msgid "Hours" msgstr "小时" #: django_celery_beat/models.py:32 msgid "Minutes" msgstr "分钟" #: django_celery_beat/models.py:33 msgid "Seconds" msgstr "秒" #: django_celery_beat/models.py:34 msgid "Microseconds" msgstr "毫秒" #: django_celery_beat/models.py:38 msgid "Day" msgstr "天" #: django_celery_beat/models.py:39 msgid "Hour" msgstr "小时" #: django_celery_beat/models.py:40 msgid "Minute" msgstr "分钟" #: django_celery_beat/models.py:41 msgid "Second" msgstr "秒" #: django_celery_beat/models.py:42 msgid "Microsecond" msgstr "毫秒" #: django_celery_beat/models.py:46 msgid "Astronomical dawn" msgstr "天文黎明" #: django_celery_beat/models.py:47 msgid "Civil dawn" msgstr "民事黎明" #: django_celery_beat/models.py:48 msgid "Nautical dawn" msgstr "航海黎明" #: django_celery_beat/models.py:49 msgid "Astronomical dusk" msgstr "天文黄昏" #: django_celery_beat/models.py:50 msgid "Civil dusk" msgstr "民事黄昏" #: django_celery_beat/models.py:51 msgid "Nautical dusk" msgstr "航海黄昏" #: django_celery_beat/models.py:52 msgid "Solar noon" msgstr "正午" #: django_celery_beat/models.py:53 msgid "Sunrise" msgstr "日出" #: django_celery_beat/models.py:54 msgid "Sunset" msgstr "日落" #: django_celery_beat/models.py:88 msgid "Solar Event" msgstr "日程事件" #: django_celery_beat/models.py:89 msgid "The type of solar event when the job should run" msgstr "当任务应该执行时的日程事件类型" #: django_celery_beat/models.py:93 msgid "Latitude" msgstr "纬度" #: django_celery_beat/models.py:94 msgid "Run the task when the event happens at this latitude" msgstr "当在此纬度发生事件时执行任务" #: django_celery_beat/models.py:99 msgid "Longitude" msgstr "经度" #: django_celery_beat/models.py:100 msgid "Run the task when the event happens at this longitude" msgstr "当在此经度发生事件时执行任务" #: django_celery_beat/models.py:107 msgid "solar event" msgstr "日程事件" #: django_celery_beat/models.py:108 msgid "solar events" msgstr "日程事件" #: django_celery_beat/models.py:158 msgid "Number of Periods" msgstr "周期数" #: django_celery_beat/models.py:159 msgid "Number of interval periods to wait before running the task again" msgstr "再次执行任务之前要等待的间隔周期数" #: django_celery_beat/models.py:165 msgid "Interval Period" msgstr "间隔周期" #: django_celery_beat/models.py:166 msgid "The type of period between task runs (Example: days)" msgstr "任务每次执行之间的时间间隔类型(例如:天)" #: django_celery_beat/models.py:172 msgid "interval" msgstr "间隔" #: django_celery_beat/models.py:173 msgid "intervals" msgstr "间隔" #: django_celery_beat/models.py:200 msgid "every {}" msgstr "每 {}" #: django_celery_beat/models.py:205 msgid "every {} {}" msgstr "每 {} {}" #: django_celery_beat/models.py:216 msgid "Clock Time" msgstr "定时时间" #: django_celery_beat/models.py:217 msgid "Run the task at clocked time" msgstr "在定时时间执行任务" #: django_celery_beat/models.py:223 django_celery_beat/models.py:224 msgid "clocked" msgstr "定时" #: django_celery_beat/models.py:264 msgid "Minute(s)" msgstr "分钟" #: django_celery_beat/models.py:266 msgid "Cron Minutes to Run. Use \"*\" for \"all\". (Example: \"0,30\")" msgstr "计划执行的分钟。 将\"*\"用作\"all\"。(例如:\"0,30\")" #: django_celery_beat/models.py:271 msgid "Hour(s)" msgstr "小时" #: django_celery_beat/models.py:273 msgid "Cron Hours to Run. Use \"*\" for \"all\". (Example: \"8,20\")" msgstr "计划执行的小时。 将\"*\"用作\"all\"。(例如:\"8,20\")" #: django_celery_beat/models.py:278 msgid "Day(s) Of The Week" msgstr "一个星期的第几天" #: django_celery_beat/models.py:280 #, fuzzy #| msgid "" #| "Cron Days Of The Week to Run. Use \"*\" for \"all\". (Example: \"0,5\")" msgid "" "Cron Days Of The Week to Run. Use \"*\" for \"all\", Sunday is 0 or 7, " "Monday is 1. (Example: \"0,5\")" msgstr "计划执行的每周的第几天。将\"*\"用作\"all\"。(例如:\"0,5\")" #: django_celery_beat/models.py:286 msgid "Day(s) Of The Month" msgstr "一个月的第几天" #: django_celery_beat/models.py:288 msgid "" "Cron Days Of The Month to Run. Use \"*\" for \"all\". (Example: \"1,15\")" msgstr "计划执行的每个月的第几天。将\"*\"用作\"all\"。(例如:\"0,5\")" #: django_celery_beat/models.py:294 msgid "Month(s) Of The Year" msgstr "一年的第几个月" #: django_celery_beat/models.py:296 #, fuzzy #| msgid "" #| "Cron Months Of The Year to Run. Use \"*\" for \"all\". (Example: \"0,6\")" msgid "" "Cron Months (1-12) Of The Year to Run. Use \"*\" for \"all\". (Example: " "\"1,12\")" msgstr "计划执行的每一年的第几个月。将\"*\"用作\"all\"。(例如:\"0,5\")" #: django_celery_beat/models.py:304 msgid "Cron Timezone" msgstr "计划任务的时区" #: django_celery_beat/models.py:306 msgid "Timezone to Run the Cron Schedule on. Default is UTC." msgstr "执行计划任务表的时区。 默认为UTC。" #: django_celery_beat/models.py:312 msgid "crontab" msgstr "计划任务" #: django_celery_beat/models.py:313 msgid "crontabs" msgstr "计划任务" #: django_celery_beat/models.py:404 msgid "Name" msgstr "任务名" #: django_celery_beat/models.py:405 msgid "Short Description For This Task" msgstr "该任务的简短说明" #: django_celery_beat/models.py:410 msgid "" "The Name of the Celery Task that Should be Run. (Example: \"proj.tasks." "import_contacts\")" msgstr "被执行的任务的名称。(例如:\"proj.tasks.import_contacts\")" #: django_celery_beat/models.py:418 msgid "Interval Schedule" msgstr "间隔时间表" #: django_celery_beat/models.py:419 msgid "" "Interval Schedule to run the task on. Set only one schedule type, leave the " "others null." msgstr "执行任务的间隔时间表。 仅设置一种时间表类型,将其他保留为空。" #: django_celery_beat/models.py:424 msgid "Crontab Schedule" msgstr "计划时间表" #: django_celery_beat/models.py:425 msgid "" "Crontab Schedule to run the task on. Set only one schedule type, leave the " "others null." msgstr "执行任务的计划时间表。 仅设置一种时间表类型,将其他保留为空。" #: django_celery_beat/models.py:430 msgid "Solar Schedule" msgstr "日程时间表" #: django_celery_beat/models.py:431 msgid "" "Solar Schedule to run the task on. Set only one schedule type, leave the " "others null." msgstr "执行任务的日程时间表。 仅设置一种时间表类型,将其他保留为空。" #: django_celery_beat/models.py:436 msgid "Clocked Schedule" msgstr "定时时间表" #: django_celery_beat/models.py:437 msgid "" "Clocked Schedule to run the task on. Set only one schedule type, leave the " "others null." msgstr "执行任务的定时时间表。 仅设置一种时间表类型,将其他保留为空。" #: django_celery_beat/models.py:443 msgid "Positional Arguments" msgstr "位置参数" #: django_celery_beat/models.py:445 msgid "JSON encoded positional arguments (Example: [\"arg1\", \"arg2\"])" msgstr "JSON编码的位置参数(例如: [\"arg1\", \"arg2\"])" #: django_celery_beat/models.py:450 msgid "Keyword Arguments" msgstr "关键字参数" #: django_celery_beat/models.py:452 msgid "JSON encoded keyword arguments (Example: {\"argument\": \"value\"})" msgstr "JSON编码的关键字参数(例如: {\"argument\": \"value\"})" #: django_celery_beat/models.py:458 msgid "Queue Override" msgstr "队列覆盖" #: django_celery_beat/models.py:460 msgid "Queue defined in CELERY_TASK_QUEUES. Leave None for default queuing." msgstr "在 CELERY_TASK_QUEUES 定义的队列。保留空以进行默认排队。" #: django_celery_beat/models.py:469 msgid "Exchange" msgstr "交换机" #: django_celery_beat/models.py:470 msgid "Override Exchange for low-level AMQP routing" msgstr "覆盖交换机以进行低层级AMQP路由" #: django_celery_beat/models.py:474 msgid "Routing Key" msgstr "路由键" #: django_celery_beat/models.py:475 msgid "Override Routing Key for low-level AMQP routing" msgstr "覆盖路由键以进行低层级AMQP路由" #: django_celery_beat/models.py:479 msgid "AMQP Message Headers" msgstr "AMQP消息头" #: django_celery_beat/models.py:480 msgid "JSON encoded message headers for the AMQP message." msgstr "AMQP消息的JSON编码消息头。" #: django_celery_beat/models.py:486 msgid "Priority" msgstr "优先级" #: django_celery_beat/models.py:488 msgid "" "Priority Number between 0 and 255. Supported by: RabbitMQ, Redis (priority " "reversed, 0 is highest)." msgstr "" "优先级数字,介于0和255之间。支持者:RabbitMQ,Redis(优先级颠倒,0是最高)。" #: django_celery_beat/models.py:493 msgid "Expires Datetime" msgstr "过期时刻" #: django_celery_beat/models.py:495 msgid "" "Datetime after which the schedule will no longer trigger the task to run" msgstr "过期时刻,计划表将在此时刻后不再触发任务执行" #: django_celery_beat/models.py:500 msgid "Expires timedelta with seconds" msgstr "过期时间间隔,以秒为单位" #: django_celery_beat/models.py:502 msgid "" "Timedelta with seconds which the schedule will no longer trigger the task to " "run" msgstr "再过该秒后,不再触发任务执行" #: django_celery_beat/models.py:508 msgid "One-off Task" msgstr "一次任务" #: django_celery_beat/models.py:510 msgid "If True, the schedule will only run the task a single time" msgstr "如果为True,则计划将仅运行任务一次" #: django_celery_beat/models.py:514 msgid "Start Datetime" msgstr "开始时间" #: django_celery_beat/models.py:516 msgid "Datetime when the schedule should begin triggering the task to run" msgstr "时间表开始触发任务执行的时刻" #: django_celery_beat/models.py:521 msgid "Enabled" msgstr "已启用" #: django_celery_beat/models.py:522 msgid "Set to False to disable the schedule" msgstr "设置为False可禁用时间表" #: django_celery_beat/models.py:527 msgid "Last Run Datetime" msgstr "上次运行时刻" #: django_celery_beat/models.py:529 msgid "" "Datetime that the schedule last triggered the task to run. Reset to None if " "enabled is set to False." msgstr "最后一次触发任务执行的时刻。 如果enabled设置为False,则重置为None。" #: django_celery_beat/models.py:534 msgid "Total Run Count" msgstr "总运行次数" #: django_celery_beat/models.py:536 msgid "Running count of how many times the schedule has triggered the task" msgstr "任务执行多少次的运行计数" #: django_celery_beat/models.py:541 msgid "Last Modified" msgstr "最后修改" #: django_celery_beat/models.py:542 msgid "Datetime that this PeriodicTask was last modified" msgstr "该周期性任务的最后修改时刻" #: django_celery_beat/models.py:546 msgid "Description" msgstr "描述" #: django_celery_beat/models.py:548 msgid "Detailed description about the details of this Periodic Task" msgstr "有关此周期性任务的详细信息" #: django_celery_beat/models.py:557 msgid "periodic task" msgstr "周期性任务" #: django_celery_beat/models.py:558 msgid "periodic tasks" msgstr "周期性任务" #: django_celery_beat/templates/admin/djcelery/change_list.html:6 msgid "Home" msgstr "" django-celery-beat-2.6.0/django_celery_beat/migrations/000077500000000000000000000000001457112420500231305ustar00rootroot00000000000000django-celery-beat-2.6.0/django_celery_beat/migrations/0001_initial.py000066400000000000000000000126671457112420500256070ustar00rootroot00000000000000# Generated by Django 1.9.5 on 2016-08-04 02:13 from django.db import migrations, models import django.db.models.deletion class Migration(migrations.Migration): initial = True dependencies = [ ] operations = [ migrations.CreateModel( name='CrontabSchedule', fields=[ ('id', models.AutoField( auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('minute', models.CharField( default='*', max_length=64, verbose_name='minute')), ('hour', models.CharField( default='*', max_length=64, verbose_name='hour')), ('day_of_week', models.CharField( default='*', max_length=64, verbose_name='day of week')), ('day_of_month', models.CharField( default='*', max_length=64, verbose_name='day of month')), ('month_of_year', models.CharField( default='*', max_length=64, verbose_name='month of year')), ], options={ 'ordering': [ 'month_of_year', 'day_of_month', 'day_of_week', 'hour', 'minute', ], 'verbose_name': 'crontab', 'verbose_name_plural': 'crontabs', }, ), migrations.CreateModel( name='IntervalSchedule', fields=[ ('id', models.AutoField( auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('every', models.IntegerField(verbose_name='every')), ('period', models.CharField( choices=[ ('days', 'Days'), ('hours', 'Hours'), ('minutes', 'Minutes'), ('seconds', 'Seconds'), ('microseconds', 'Microseconds'), ], max_length=24, verbose_name='period')), ], options={ 'ordering': ['period', 'every'], 'verbose_name': 'interval', 'verbose_name_plural': 'intervals', }, ), migrations.CreateModel( name='PeriodicTask', fields=[ ('id', models.AutoField( auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField( help_text='Useful description', max_length=200, unique=True, verbose_name='name')), ('task', models.CharField( max_length=200, verbose_name='task name')), ('args', models.TextField( blank=True, default='[]', help_text='JSON encoded positional arguments', verbose_name='Arguments')), ('kwargs', models.TextField( blank=True, default='{}', help_text='JSON encoded keyword arguments', verbose_name='Keyword arguments')), ('queue', models.CharField( blank=True, default=None, help_text='Queue defined in CELERY_TASK_QUEUES', max_length=200, null=True, verbose_name='queue')), ('exchange', models.CharField( blank=True, default=None, max_length=200, null=True, verbose_name='exchange')), ('routing_key', models.CharField( blank=True, default=None, max_length=200, null=True, verbose_name='routing key')), ('expires', models.DateTimeField( blank=True, null=True, verbose_name='expires')), ('enabled', models.BooleanField( default=True, verbose_name='enabled')), ('last_run_at', models.DateTimeField( blank=True, editable=False, null=True)), ('total_run_count', models.PositiveIntegerField( default=0, editable=False)), ('date_changed', models.DateTimeField(auto_now=True)), ('description', models.TextField( blank=True, verbose_name='description')), ('crontab', models.ForeignKey( blank=True, help_text='Use one of interval/crontab', null=True, on_delete=django.db.models.deletion.CASCADE, to='django_celery_beat.CrontabSchedule', verbose_name='crontab')), ('interval', models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='django_celery_beat.IntervalSchedule', verbose_name='interval')), ], options={ 'verbose_name': 'periodic task', 'verbose_name_plural': 'periodic tasks', }, ), migrations.CreateModel( name='PeriodicTasks', fields=[ ('ident', models.SmallIntegerField( default=1, primary_key=True, serialize=False, unique=True)), ('last_update', models.DateTimeField()), ], ), ] django-celery-beat-2.6.0/django_celery_beat/migrations/0002_auto_20161118_0346.py000066400000000000000000000037201457112420500265540ustar00rootroot00000000000000# Generated by Django 1.10.3 on 2016-11-18 03:46 from django.db import migrations, models import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ ('django_celery_beat', '0001_initial'), ] operations = [ migrations.CreateModel( name='SolarSchedule', fields=[ ('id', models.AutoField( auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('event', models.CharField( choices=[('dusk_nautical', 'dusk_nautical'), ('dawn_astronomical', 'dawn_astronomical'), ('dawn_nautical', 'dawn_nautical'), ('dawn_civil', 'dawn_civil'), ('sunset', 'sunset'), ('solar_noon', 'solar_noon'), ('dusk_astronomical', 'dusk_astronomical'), ('sunrise', 'sunrise'), ('dusk_civil', 'dusk_civil')], max_length=24, verbose_name='event')), ('latitude', models.DecimalField( decimal_places=6, max_digits=9, verbose_name='latitude')), ('longitude', models.DecimalField( decimal_places=6, max_digits=9, verbose_name='latitude')), ], options={ 'ordering': ['event', 'latitude', 'longitude'], 'verbose_name': 'solar', 'verbose_name_plural': 'solars', }, ), migrations.AddField( model_name='periodictask', name='solar', field=models.ForeignKey( blank=True, help_text='Use a solar schedule', null=True, on_delete=django.db.models.deletion.CASCADE, to='django_celery_beat.SolarSchedule', verbose_name='solar'), ), ] django-celery-beat-2.6.0/django_celery_beat/migrations/0003_auto_20161209_0049.py000066400000000000000000000012301457112420500265500ustar00rootroot00000000000000# Generated by Django 1.9.11 on 2016-12-09 00:49 from django.db import migrations class Migration(migrations.Migration): dependencies = [ ('django_celery_beat', '0002_auto_20161118_0346'), ] operations = [ migrations.AlterModelOptions( name='solarschedule', options={ 'ordering': ('event', 'latitude', 'longitude'), 'verbose_name': 'solar event', 'verbose_name_plural': 'solar events'}, ), migrations.AlterUniqueTogether( name='solarschedule', unique_together=set([('event', 'latitude', 'longitude')]), ), ] django-celery-beat-2.6.0/django_celery_beat/migrations/0004_auto_20170221_0000.py000066400000000000000000000007051457112420500265340ustar00rootroot00000000000000from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ ('django_celery_beat', '0003_auto_20161209_0049'), ] operations = [ migrations.AlterField( model_name='solarschedule', name='longitude', field=models.DecimalField( verbose_name='longitude', max_digits=9, decimal_places=6), ), ] django-celery-beat-2.6.0/django_celery_beat/migrations/0005_add_solarschedule_events_choices.py000066400000000000000000000016101457112420500326720ustar00rootroot00000000000000# Generated by Django 1.9.1 on 2017-11-01 15:53 from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ ('django_celery_beat', '0004_auto_20170221_0000'), ] operations = [ migrations.AlterField( model_name='solarschedule', name='event', field=models.CharField(choices=[ ('dawn_astronomical', 'dawn_astronomical'), ('dawn_civil', 'dawn_civil'), ('dawn_nautical', 'dawn_nautical'), ('dusk_astronomical', 'dusk_astronomical'), ('dusk_civil', 'dusk_civil'), ('dusk_nautical', 'dusk_nautical'), ('solar_noon', 'solar_noon'), ('sunrise', 'sunrise'), ('sunset', 'sunset') ], max_length=24, verbose_name='event'), ), ] django-celery-beat-2.6.0/django_celery_beat/migrations/0006_auto_20180210_1226.py000066400000000000000000000017061457112420500265520ustar00rootroot00000000000000# Generated by Django 2.0.1 on 2018-02-10 12:26 from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ ('django_celery_beat', '0005_add_solarschedule_events_choices'), ] operations = [ migrations.AlterField( model_name='crontabschedule', name='day_of_month', field=models.CharField(default='*', max_length=124, verbose_name='day of month'), ), migrations.AlterField( model_name='crontabschedule', name='hour', field=models.CharField(default='*', max_length=96, verbose_name='hour'), ), migrations.AlterField( model_name='crontabschedule', name='minute', field=models.CharField(default='*', max_length=240, verbose_name='minute'), ), ] django-celery-beat-2.6.0/django_celery_beat/migrations/0006_auto_20180322_0932.py000066400000000000000000000031041457112420500265530ustar00rootroot00000000000000# Generated by Django 1.11.7 on 2018-03-22 16:32 from django.db import migrations, models import timezone_field.fields class Migration(migrations.Migration): dependencies = [ ('django_celery_beat', '0005_add_solarschedule_events_choices'), # ('django_celery_beat', '0006_auto_20180210_1226'), ] operations = [ migrations.AlterModelOptions( name='crontabschedule', options={ 'ordering': [ 'month_of_year', 'day_of_month', 'day_of_week', 'hour', 'minute', 'timezone' ], 'verbose_name': 'crontab', 'verbose_name_plural': 'crontabs' }, ), migrations.AddField( model_name='crontabschedule', name='timezone', field=timezone_field.fields.TimeZoneField(default='UTC'), ), migrations.AlterField( model_name='crontabschedule', name='day_of_month', field=models.CharField( default='*', max_length=124, verbose_name='day of month' ), ), migrations.AlterField( model_name='crontabschedule', name='hour', field=models.CharField( default='*', max_length=96, verbose_name='hour' ), ), migrations.AlterField( model_name='crontabschedule', name='minute', field=models.CharField( default='*', max_length=240, verbose_name='minute' ), ), ] django-celery-beat-2.6.0/django_celery_beat/migrations/0006_periodictask_priority.py000066400000000000000000000017631457112420500306000ustar00rootroot00000000000000# Generated by Django 2.0.6 on 2018-10-22 05:20 import django.core.validators from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ # depends on higher numbers due to a squashed migration # that was later removed due to migration issues it caused ('django_celery_beat', '0005_add_solarschedule_events_choices'), ('django_celery_beat', '0006_auto_20180210_1226'), ('django_celery_beat', '0006_auto_20180322_0932'), ('django_celery_beat', '0007_auto_20180521_0826'), ('django_celery_beat', '0008_auto_20180914_1922'), ] operations = [ migrations.AddField( model_name='periodictask', name='priority', field=models.PositiveIntegerField( blank=True, default=None, null=True, validators=[django.core.validators.MaxValueValidator(255)], verbose_name='priority'), ), ] django-celery-beat-2.6.0/django_celery_beat/migrations/0007_auto_20180521_0826.py000066400000000000000000000013561457112420500265660ustar00rootroot00000000000000# Generated by Django 1.10.7 on 2018-05-21 08:26 from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ ('django_celery_beat', '0006_auto_20180322_0932'), ] operations = [ migrations.AddField( model_name='periodictask', name='one_off', field=models.BooleanField(default=False, verbose_name='one-off task'), ), migrations.AddField( model_name='periodictask', name='start_time', field=models.DateTimeField(blank=True, null=True, verbose_name='start_time'), ), ] django-celery-beat-2.6.0/django_celery_beat/migrations/0008_auto_20180914_1922.py000066400000000000000000000034641457112420500265750ustar00rootroot00000000000000# Generated by Django 2.0.3 on 2018-09-14 19:22 from django.db import migrations, models from django_celery_beat import validators class Migration(migrations.Migration): dependencies = [ ('django_celery_beat', '0007_auto_20180521_0826'), ] operations = [ migrations.AlterField( model_name='crontabschedule', name='day_of_month', field=models.CharField( default='*', max_length=124, validators=[validators.day_of_month_validator], verbose_name='day of month' ), ), migrations.AlterField( model_name='crontabschedule', name='day_of_week', field=models.CharField( default='*', max_length=64, validators=[validators.day_of_week_validator], verbose_name='day of week' ), ), migrations.AlterField( model_name='crontabschedule', name='hour', field=models.CharField( default='*', max_length=96, validators=[validators.hour_validator], verbose_name='hour' ), ), migrations.AlterField( model_name='crontabschedule', name='minute', field=models.CharField( default='*', max_length=240, validators=[validators.minute_validator], verbose_name='minute' ), ), migrations.AlterField( model_name='crontabschedule', name='month_of_year', field=models.CharField( default='*', max_length=64, validators=[validators.month_of_year_validator], verbose_name='month of year' ), ), ] django-celery-beat-2.6.0/django_celery_beat/migrations/0009_periodictask_headers.py000066400000000000000000000010671457112420500303320ustar00rootroot00000000000000# Generated by Django 2.1.5 on 2019-02-09 19:33 from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ ('django_celery_beat', '0006_periodictask_priority'), ] operations = [ migrations.AddField( model_name='periodictask', name='headers', field=models.TextField( blank=True, default='{}', help_text='JSON encoded message headers', verbose_name='Message headers' ), ), ] django-celery-beat-2.6.0/django_celery_beat/migrations/0010_auto_20190429_0326.py000066400000000000000000000244671457112420500265730ustar00rootroot00000000000000# Generated by Django 1.11.20 on 2019-04-29 03:26 # this file is auto-generated so don't do flake8 on it # flake8: noqa import django.core.validators from django.db import migrations, models import django.db.models.deletion import django_celery_beat.validators import timezone_field.fields class Migration(migrations.Migration): dependencies = [ ('django_celery_beat', '0009_periodictask_headers'), ] operations = [ migrations.AlterField( model_name='crontabschedule', name='day_of_month', field=models.CharField(default='*', help_text='Cron Days Of The Month to Run. Use "*" for "all". (Example: "1,15")', max_length=124, validators=[django_celery_beat.validators.day_of_month_validator], verbose_name='Day(s) Of The Month'), ), migrations.AlterField( model_name='crontabschedule', name='day_of_week', field=models.CharField(default='*', help_text='Cron Days Of The Week to Run. Use "*" for "all". (Example: "0,5")', max_length=64, validators=[django_celery_beat.validators.day_of_week_validator], verbose_name='Day(s) Of The Week'), ), migrations.AlterField( model_name='crontabschedule', name='hour', field=models.CharField(default='*', help_text='Cron Hours to Run. Use "*" for "all". (Example: "8,20")', max_length=96, validators=[django_celery_beat.validators.hour_validator], verbose_name='Hour(s)'), ), migrations.AlterField( model_name='crontabschedule', name='minute', field=models.CharField(default='*', help_text='Cron Minutes to Run. Use "*" for "all". (Example: "0,30")', max_length=240, validators=[django_celery_beat.validators.minute_validator], verbose_name='Minute(s)'), ), migrations.AlterField( model_name='crontabschedule', name='month_of_year', field=models.CharField(default='*', help_text='Cron Months Of The Year to Run. Use "*" for "all". (Example: "0,6")', max_length=64, validators=[django_celery_beat.validators.month_of_year_validator], verbose_name='Month(s) Of The Year'), ), migrations.AlterField( model_name='crontabschedule', name='timezone', field=timezone_field.fields.TimeZoneField(default='UTC', help_text='Timezone to Run the Cron Schedule on. Default is UTC.', verbose_name='Cron Timezone'), ), migrations.AlterField( model_name='intervalschedule', name='every', field=models.IntegerField(help_text='Number of interval periods to wait before running the task again', validators=[django.core.validators.MinValueValidator(1)], verbose_name='Number of Periods'), ), migrations.AlterField( model_name='intervalschedule', name='period', field=models.CharField(choices=[('days', 'Days'), ('hours', 'Hours'), ('minutes', 'Minutes'), ('seconds', 'Seconds'), ('microseconds', 'Microseconds')], help_text='The type of period between task runs (Example: days)', max_length=24, verbose_name='Interval Period'), ), migrations.AlterField( model_name='periodictask', name='args', field=models.TextField(blank=True, default='[]', help_text='JSON encoded positional arguments (Example: ["arg1", "arg2"])', verbose_name='Positional Arguments'), ), migrations.AlterField( model_name='periodictask', name='crontab', field=models.ForeignKey(blank=True, help_text='Crontab Schedule to run the task on. Set only one schedule type, leave the others null.', null=True, on_delete=django.db.models.deletion.CASCADE, to='django_celery_beat.CrontabSchedule', verbose_name='Crontab Schedule'), ), migrations.AlterField( model_name='periodictask', name='date_changed', field=models.DateTimeField(auto_now=True, help_text='Datetime that this PeriodicTask was last modified', verbose_name='Last Modified'), ), migrations.AlterField( model_name='periodictask', name='description', field=models.TextField(blank=True, help_text='Detailed description about the details of this Periodic Task', verbose_name='Description'), ), migrations.AlterField( model_name='periodictask', name='enabled', field=models.BooleanField(default=True, help_text='Set to False to disable the schedule', verbose_name='Enabled'), ), migrations.AlterField( model_name='periodictask', name='exchange', field=models.CharField(blank=True, default=None, help_text='Override Exchange for low-level AMQP routing', max_length=200, null=True, verbose_name='Exchange'), ), migrations.AlterField( model_name='periodictask', name='expires', field=models.DateTimeField(blank=True, help_text='Datetime after which the schedule will no longer trigger the task to run', null=True, verbose_name='Expires Datetime'), ), migrations.AlterField( model_name='periodictask', name='headers', field=models.TextField(blank=True, default='{}', help_text='JSON encoded message headers for the AMQP message.', verbose_name='AMQP Message Headers'), ), migrations.AlterField( model_name='periodictask', name='interval', field=models.ForeignKey(blank=True, help_text='Interval Schedule to run the task on. Set only one schedule type, leave the others null.', null=True, on_delete=django.db.models.deletion.CASCADE, to='django_celery_beat.IntervalSchedule', verbose_name='Interval Schedule'), ), migrations.AlterField( model_name='periodictask', name='kwargs', field=models.TextField(blank=True, default='{}', help_text='JSON encoded keyword arguments (Example: {"argument": "value"})', verbose_name='Keyword Arguments'), ), migrations.AlterField( model_name='periodictask', name='last_run_at', field=models.DateTimeField(blank=True, editable=False, help_text='Datetime that the schedule last triggered the task to run. Reset to None if enabled is set to False.', null=True, verbose_name='Last Run Datetime'), ), migrations.AlterField( model_name='periodictask', name='name', field=models.CharField(help_text='Short Description For This Task', max_length=200, unique=True, verbose_name='Name'), ), migrations.AlterField( model_name='periodictask', name='one_off', field=models.BooleanField(default=False, help_text='If True, the schedule will only run the task a single time', verbose_name='One-off Task'), ), migrations.AlterField( model_name='periodictask', name='priority', field=models.PositiveIntegerField(blank=True, default=None, help_text='Priority Number between 0 and 255. Supported by: RabbitMQ, Redis (priority reversed, 0 is highest).', null=True, validators=[django.core.validators.MaxValueValidator(255)], verbose_name='Priority'), ), migrations.AlterField( model_name='periodictask', name='queue', field=models.CharField(blank=True, default=None, help_text='Queue defined in CELERY_TASK_QUEUES. Leave None for default queuing.', max_length=200, null=True, verbose_name='Queue Override'), ), migrations.AlterField( model_name='periodictask', name='routing_key', field=models.CharField(blank=True, default=None, help_text='Override Routing Key for low-level AMQP routing', max_length=200, null=True, verbose_name='Routing Key'), ), migrations.AlterField( model_name='periodictask', name='solar', field=models.ForeignKey(blank=True, help_text='Solar Schedule to run the task on. Set only one schedule type, leave the others null.', null=True, on_delete=django.db.models.deletion.CASCADE, to='django_celery_beat.SolarSchedule', verbose_name='Solar Schedule'), ), migrations.AlterField( model_name='periodictask', name='start_time', field=models.DateTimeField(blank=True, help_text='Datetime when the schedule should begin triggering the task to run', null=True, verbose_name='Start Datetime'), ), migrations.AlterField( model_name='periodictask', name='task', field=models.CharField(help_text='The Name of the Celery Task that Should be Run. (Example: "proj.tasks.import_contacts")', max_length=200, verbose_name='Task Name'), ), migrations.AlterField( model_name='periodictask', name='total_run_count', field=models.PositiveIntegerField(default=0, editable=False, help_text='Running count of how many times the schedule has triggered the task', verbose_name='Total Run Count'), ), migrations.AlterField( model_name='solarschedule', name='event', field=models.CharField(choices=[('dawn_astronomical', 'dawn_astronomical'), ('dawn_civil', 'dawn_civil'), ('dawn_nautical', 'dawn_nautical'), ('dusk_astronomical', 'dusk_astronomical'), ('dusk_civil', 'dusk_civil'), ('dusk_nautical', 'dusk_nautical'), ('solar_noon', 'solar_noon'), ('sunrise', 'sunrise'), ('sunset', 'sunset')], help_text='The type of solar event when the job should run', max_length=24, verbose_name='Solar Event'), ), migrations.AlterField( model_name='solarschedule', name='latitude', field=models.DecimalField(decimal_places=6, help_text='Run the task when the event happens at this latitude', max_digits=9, validators=[django.core.validators.MinValueValidator(-90), django.core.validators.MaxValueValidator(90)], verbose_name='Latitude'), ), migrations.AlterField( model_name='solarschedule', name='longitude', field=models.DecimalField(decimal_places=6, help_text='Run the task when the event happens at this longitude', max_digits=9, validators=[django.core.validators.MinValueValidator(-180), django.core.validators.MaxValueValidator(180)], verbose_name='Longitude'), ), ] django-celery-beat-2.6.0/django_celery_beat/migrations/0011_auto_20190508_0153.py000066400000000000000000000025221457112420500265540ustar00rootroot00000000000000# Generated by Django 2.2 on 2019-05-08 01:53 # flake8: noqa from django.db import migrations, models import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ ('django_celery_beat', '0010_auto_20190429_0326'), ] operations = [ migrations.CreateModel( name='ClockedSchedule', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('clocked_time', models.DateTimeField(help_text='Run the task at clocked time', verbose_name='Clock Time')), ('enabled', models.BooleanField(default=True, editable=False, help_text='Set to False to disable the schedule', verbose_name='Enabled')), ], options={ 'verbose_name': 'clocked', 'verbose_name_plural': 'clocked', 'ordering': ['clocked_time'], }, ), migrations.AddField( model_name='periodictask', name='clocked', field=models.ForeignKey(blank=True, help_text='Clocked Schedule to run the task on. Set only one schedule type, leave the others null.', null=True, on_delete=django.db.models.deletion.CASCADE, to='django_celery_beat.ClockedSchedule', verbose_name='Clocked Schedule'), ), ] django-celery-beat-2.6.0/django_celery_beat/migrations/0012_periodictask_expire_seconds.py000066400000000000000000000011071457112420500317160ustar00rootroot00000000000000# Generated by Django 2.2.4 on 2019-08-30 00:46 # flake8: noqa from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ ('django_celery_beat', '0011_auto_20190508_0153'), ] operations = [ migrations.AddField( model_name='periodictask', name='expire_seconds', field=models.PositiveIntegerField(blank=True, help_text='Timedelta with seconds which the schedule will no longer trigger the task to run', null=True, verbose_name='Expires timedelta with seconds'), ), ] django-celery-beat-2.6.0/django_celery_beat/migrations/0013_auto_20200609_0727.py000066400000000000000000000012161457112420500265560ustar00rootroot00000000000000# Generated by Django 3.0.6 on 2020-06-09 07:27 # flake8: noqa from django.db import migrations import django_celery_beat.models import timezone_field.fields class Migration(migrations.Migration): dependencies = [ ('django_celery_beat', '0012_periodictask_expire_seconds'), ] operations = [ migrations.AlterField( model_name='crontabschedule', name='timezone', field=timezone_field.fields.TimeZoneField(default=django_celery_beat.models.crontab_schedule_celery_timezone, help_text='Timezone to Run the Cron Schedule on. Default is UTC.', verbose_name='Cron Timezone'), ), ] django-celery-beat-2.6.0/django_celery_beat/migrations/0014_remove_clockedschedule_enabled.py000066400000000000000000000005531457112420500323210ustar00rootroot00000000000000# Generated by Django 2.2.4 on 2019-08-30 00:46 # flake8: noqa from django.db import migrations class Migration(migrations.Migration): dependencies = [ ('django_celery_beat', '0013_auto_20200609_0727'), ] operations = [ migrations.RemoveField( model_name='clockedschedule', name='enabled', ), ] django-celery-beat-2.6.0/django_celery_beat/migrations/0015_edit_solarschedule_events_choices.py000066400000000000000000000014701457112420500330740ustar00rootroot00000000000000# Generated by Django 3.0.6 on 2020-12-13 15:00 # flake8: noqa from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ ('django_celery_beat', '0014_remove_clockedschedule_enabled'), ] operations = [ migrations.AlterField( model_name='solarschedule', name='event', field=models.CharField(choices=[('dawn_astronomical', 'Astronomical dawn'), ('dawn_civil', 'Civil dawn'), ('dawn_nautical', 'Nautical dawn'), ('dusk_astronomical', 'Astronomical dusk'), ('dusk_civil', 'Civil dusk'), ('dusk_nautical', 'Nautical dusk'), ('solar_noon', 'Solar noon'), ('sunrise', 'Sunrise'), ('sunset', 'Sunset')], help_text='The type of solar event when the job should run', max_length=24, verbose_name='Solar Event'), ), ] django-celery-beat-2.6.0/django_celery_beat/migrations/0016_alter_crontabschedule_timezone.py000066400000000000000000000013671457112420500324250ustar00rootroot00000000000000# Generated by Django 4.0.3 on 2022-03-21 20:20 # flake8: noqa from django.db import migrations import django_celery_beat.models import timezone_field.fields class Migration(migrations.Migration): dependencies = [ ('django_celery_beat', '0015_edit_solarschedule_events_choices'), ] operations = [ migrations.AlterField( model_name='crontabschedule', name='timezone', field=timezone_field.fields.TimeZoneField( default= django_celery_beat.models.crontab_schedule_celery_timezone, help_text= 'Timezone to Run the Cron Schedule on. Default is UTC.', use_pytz=False, verbose_name='Cron Timezone'), ), ] django-celery-beat-2.6.0/django_celery_beat/migrations/0017_alter_crontabschedule_month_of_year.py000066400000000000000000000012351457112420500334170ustar00rootroot00000000000000# Generated by Django 4.1.4 on 2022-12-17 09:21 from django.db import migrations, models import django_celery_beat.validators class Migration(migrations.Migration): dependencies = [ ('django_celery_beat', '0016_alter_crontabschedule_timezone'), ] operations = [ migrations.AlterField( model_name='crontabschedule', name='month_of_year', field=models.CharField(default='*', help_text='Cron Months (1-12) Of The Year to Run. Use "*" for "all". (Example: "1,12")', max_length=64, validators=[django_celery_beat.validators.month_of_year_validator], verbose_name='Month(s) Of The Year'), ), ] django-celery-beat-2.6.0/django_celery_beat/migrations/0018_improve_crontab_helptext.py000066400000000000000000000012621457112420500312610ustar00rootroot00000000000000# Generated by Django 3.2.16 on 2022-12-23 22:30 from django.db import migrations, models import django_celery_beat.validators class Migration(migrations.Migration): dependencies = [ ('django_celery_beat', '0017_alter_crontabschedule_month_of_year'), ] operations = [ migrations.AlterField( model_name='crontabschedule', name='day_of_week', field=models.CharField(default='*', help_text='Cron Days Of The Week to Run. Use "*" for "all", Sunday is 0 or 7, Monday is 1. (Example: "0,5")', max_length=64, validators=[django_celery_beat.validators.day_of_week_validator], verbose_name='Day(s) Of The Week'), ), ] django-celery-beat-2.6.0/django_celery_beat/migrations/__init__.py000066400000000000000000000000001457112420500252270ustar00rootroot00000000000000django-celery-beat-2.6.0/django_celery_beat/models.py000066400000000000000000000520341457112420500226150ustar00rootroot00000000000000"""Database models.""" try: from zoneinfo import available_timezones except ImportError: from backports.zoneinfo import available_timezones from datetime import timedelta import timezone_field from celery import current_app, schedules from cron_descriptor import (FormatException, MissingFieldException, WrongArgumentException, get_description) from django.conf import settings from django.core.exceptions import MultipleObjectsReturned, ValidationError from django.core.validators import MaxValueValidator, MinValueValidator from django.db import models from django.utils.translation import gettext_lazy as _ from . import querysets, validators from .clockedschedule import clocked from .tzcrontab import TzAwareCrontab from .utils import make_aware, now DAYS = 'days' HOURS = 'hours' MINUTES = 'minutes' SECONDS = 'seconds' MICROSECONDS = 'microseconds' PERIOD_CHOICES = ( (DAYS, _('Days')), (HOURS, _('Hours')), (MINUTES, _('Minutes')), (SECONDS, _('Seconds')), (MICROSECONDS, _('Microseconds')), ) SINGULAR_PERIODS = ( (DAYS, _('Day')), (HOURS, _('Hour')), (MINUTES, _('Minute')), (SECONDS, _('Second')), (MICROSECONDS, _('Microsecond')), ) SOLAR_SCHEDULES = [ ("dawn_astronomical", _("Astronomical dawn")), ("dawn_civil", _("Civil dawn")), ("dawn_nautical", _("Nautical dawn")), ("dusk_astronomical", _("Astronomical dusk")), ("dusk_civil", _("Civil dusk")), ("dusk_nautical", _("Nautical dusk")), ("solar_noon", _("Solar noon")), ("sunrise", _("Sunrise")), ("sunset", _("Sunset")), ] def cronexp(field): """Representation of cron expression.""" return field and str(field).replace(' ', '') or '*' def crontab_schedule_celery_timezone(): """Return timezone string from Django settings ``CELERY_TIMEZONE`` variable. If is not defined or is not a valid timezone, return ``"UTC"`` instead. """ # noqa: E501 try: CELERY_TIMEZONE = getattr( settings, '%s_TIMEZONE' % current_app.namespace) except AttributeError: return 'UTC' if CELERY_TIMEZONE in available_timezones(): return CELERY_TIMEZONE return 'UTC' class SolarSchedule(models.Model): """Schedule following astronomical patterns. Example: to run every sunrise in New York City: >>> event='sunrise', latitude=40.7128, longitude=74.0060 """ event = models.CharField( max_length=24, choices=SOLAR_SCHEDULES, verbose_name=_('Solar Event'), help_text=_('The type of solar event when the job should run'), ) latitude = models.DecimalField( max_digits=9, decimal_places=6, verbose_name=_('Latitude'), help_text=_('Run the task when the event happens at this latitude'), validators=[MinValueValidator(-90), MaxValueValidator(90)], ) longitude = models.DecimalField( max_digits=9, decimal_places=6, verbose_name=_('Longitude'), help_text=_('Run the task when the event happens at this longitude'), validators=[MinValueValidator(-180), MaxValueValidator(180)], ) class Meta: """Table information.""" verbose_name = _('solar event') verbose_name_plural = _('solar events') ordering = ('event', 'latitude', 'longitude') unique_together = ('event', 'latitude', 'longitude') @property def schedule(self): return schedules.solar(self.event, self.latitude, self.longitude, nowfun=lambda: make_aware(now())) @classmethod def from_schedule(cls, schedule): spec = {'event': schedule.event, 'latitude': schedule.lat, 'longitude': schedule.lon} # we do not check for MultipleObjectsReturned exception here because # the unique_together constraint safely prevents from duplicates try: return cls.objects.get(**spec) except cls.DoesNotExist: return cls(**spec) def __str__(self): return '{} ({}, {})'.format( self.get_event_display(), self.latitude, self.longitude ) class IntervalSchedule(models.Model): """Schedule executing on a regular interval. Example: execute every 2 days: >>> every=2, period=DAYS """ DAYS = DAYS HOURS = HOURS MINUTES = MINUTES SECONDS = SECONDS MICROSECONDS = MICROSECONDS PERIOD_CHOICES = PERIOD_CHOICES every = models.IntegerField( null=False, verbose_name=_('Number of Periods'), help_text=_('Number of interval periods to wait before ' 'running the task again'), validators=[MinValueValidator(1)], ) period = models.CharField( max_length=24, choices=PERIOD_CHOICES, verbose_name=_('Interval Period'), help_text=_('The type of period between task runs (Example: days)'), ) class Meta: """Table information.""" verbose_name = _('interval') verbose_name_plural = _('intervals') ordering = ['period', 'every'] @property def schedule(self): return schedules.schedule( timedelta(**{self.period: self.every}), nowfun=lambda: make_aware(now()) ) @classmethod def from_schedule(cls, schedule, period=SECONDS): every = max(schedule.run_every.total_seconds(), 0) try: return cls.objects.get(every=every, period=period) except cls.DoesNotExist: return cls(every=every, period=period) except MultipleObjectsReturned: return cls.objects.filter(every=every, period=period).first() def __str__(self): readable_period = None if self.every == 1: for period, _readable_period in SINGULAR_PERIODS: if period == self.period: readable_period = _readable_period.lower() break return _('every {}').format(readable_period) for period, _readable_period in PERIOD_CHOICES: if period == self.period: readable_period = _readable_period.lower() break return _('every {} {}').format(self.every, readable_period) @property def period_singular(self): return self.period[:-1] class ClockedSchedule(models.Model): """clocked schedule.""" clocked_time = models.DateTimeField( verbose_name=_('Clock Time'), help_text=_('Run the task at clocked time'), ) class Meta: """Table information.""" verbose_name = _('clocked') verbose_name_plural = _('clocked') ordering = ['clocked_time'] def __str__(self): return f'{make_aware(self.clocked_time)}' @property def schedule(self): c = clocked(clocked_time=self.clocked_time) return c @classmethod def from_schedule(cls, schedule): spec = {'clocked_time': schedule.clocked_time} try: return cls.objects.get(**spec) except cls.DoesNotExist: return cls(**spec) except MultipleObjectsReturned: return cls.objects.filter(**spec).first() class CrontabSchedule(models.Model): """Timezone Aware Crontab-like schedule. Example: Run every hour at 0 minutes for days of month 10-15: >>> minute="0", hour="*", day_of_week="*", ... day_of_month="10-15", month_of_year="*" """ # # The worst case scenario for day of month is a list of all 31 day numbers # '[1, 2, ..., 31]' which has a length of 115. Likewise, minute can be # 0..59 and hour can be 0..23. Ensure we can accomodate these by allowing # 4 chars for each value (what we save on 0-9 accomodates the []). # We leave the other fields at their historical length. # minute = models.CharField( max_length=60 * 4, default='*', verbose_name=_('Minute(s)'), help_text=_( 'Cron Minutes to Run. Use "*" for "all". (Example: "0,30")'), validators=[validators.minute_validator], ) hour = models.CharField( max_length=24 * 4, default='*', verbose_name=_('Hour(s)'), help_text=_( 'Cron Hours to Run. Use "*" for "all". (Example: "8,20")'), validators=[validators.hour_validator], ) day_of_month = models.CharField( max_length=31 * 4, default='*', verbose_name=_('Day(s) Of The Month'), help_text=_( 'Cron Days Of The Month to Run. Use "*" for "all". ' '(Example: "1,15")'), validators=[validators.day_of_month_validator], ) month_of_year = models.CharField( max_length=64, default='*', verbose_name=_('Month(s) Of The Year'), help_text=_( 'Cron Months (1-12) Of The Year to Run. Use "*" for "all". ' '(Example: "1,12")'), validators=[validators.month_of_year_validator], ) day_of_week = models.CharField( max_length=64, default='*', verbose_name=_('Day(s) Of The Week'), help_text=_( 'Cron Days Of The Week to Run. Use "*" for "all", Sunday ' 'is 0 or 7, Monday is 1. (Example: "0,5")'), validators=[validators.day_of_week_validator], ) timezone = timezone_field.TimeZoneField( default=crontab_schedule_celery_timezone, use_pytz=False, verbose_name=_('Cron Timezone'), help_text=_( 'Timezone to Run the Cron Schedule on. Default is UTC.'), ) class Meta: """Table information.""" verbose_name = _('crontab') verbose_name_plural = _('crontabs') ordering = ['month_of_year', 'day_of_month', 'day_of_week', 'hour', 'minute', 'timezone'] @property def human_readable(self): cron_expression = '{} {} {} {} {}'.format( cronexp(self.minute), cronexp(self.hour), cronexp(self.day_of_month), cronexp(self.month_of_year), cronexp(self.day_of_week) ) try: human_readable = get_description(cron_expression) except ( MissingFieldException, FormatException, WrongArgumentException ): return f'{cron_expression} {str(self.timezone)}' return f'{human_readable} {str(self.timezone)}' def __str__(self): return '{} {} {} {} {} (m/h/dM/MY/d) {}'.format( cronexp(self.minute), cronexp(self.hour), cronexp(self.day_of_month), cronexp(self.month_of_year), cronexp(self.day_of_week), str(self.timezone) ) @property def schedule(self): crontab = schedules.crontab( minute=self.minute, hour=self.hour, day_of_week=self.day_of_week, day_of_month=self.day_of_month, month_of_year=self.month_of_year, ) if getattr(settings, 'DJANGO_CELERY_BEAT_TZ_AWARE', True): crontab = TzAwareCrontab( minute=self.minute, hour=self.hour, day_of_week=self.day_of_week, day_of_month=self.day_of_month, month_of_year=self.month_of_year, tz=self.timezone ) return crontab @classmethod def from_schedule(cls, schedule): spec = {'minute': schedule._orig_minute, 'hour': schedule._orig_hour, 'day_of_week': schedule._orig_day_of_week, 'day_of_month': schedule._orig_day_of_month, 'month_of_year': schedule._orig_month_of_year, 'timezone': schedule.tz } try: return cls.objects.get(**spec) except cls.DoesNotExist: return cls(**spec) except MultipleObjectsReturned: return cls.objects.filter(**spec).first() class PeriodicTasks(models.Model): """Helper table for tracking updates to periodic tasks. This stores a single row with ``ident=1``. ``last_update`` is updated via signals whenever anything changes in the :class:`~.PeriodicTask` model. Basically this acts like a DB data audit trigger. Doing this so we also track deletions, and not just insert/update. """ ident = models.SmallIntegerField(default=1, primary_key=True, unique=True) last_update = models.DateTimeField(null=False) @classmethod def changed(cls, instance, **kwargs): if not instance.no_changes: cls.update_changed() @classmethod def update_changed(cls, **kwargs): cls.objects.update_or_create(ident=1, defaults={'last_update': now()}) @classmethod def last_change(cls): try: return cls.objects.get(ident=1).last_update except cls.DoesNotExist: pass class PeriodicTask(models.Model): """Model representing a periodic task.""" name = models.CharField( max_length=200, unique=True, verbose_name=_('Name'), help_text=_('Short Description For This Task'), ) task = models.CharField( max_length=200, verbose_name='Task Name', help_text=_('The Name of the Celery Task that Should be Run. ' '(Example: "proj.tasks.import_contacts")'), ) # You can only set ONE of the following schedule FK's # TODO: Redo this as a GenericForeignKey interval = models.ForeignKey( IntervalSchedule, on_delete=models.CASCADE, null=True, blank=True, verbose_name=_('Interval Schedule'), help_text=_('Interval Schedule to run the task on. ' 'Set only one schedule type, leave the others null.'), ) crontab = models.ForeignKey( CrontabSchedule, on_delete=models.CASCADE, null=True, blank=True, verbose_name=_('Crontab Schedule'), help_text=_('Crontab Schedule to run the task on. ' 'Set only one schedule type, leave the others null.'), ) solar = models.ForeignKey( SolarSchedule, on_delete=models.CASCADE, null=True, blank=True, verbose_name=_('Solar Schedule'), help_text=_('Solar Schedule to run the task on. ' 'Set only one schedule type, leave the others null.'), ) clocked = models.ForeignKey( ClockedSchedule, on_delete=models.CASCADE, null=True, blank=True, verbose_name=_('Clocked Schedule'), help_text=_('Clocked Schedule to run the task on. ' 'Set only one schedule type, leave the others null.'), ) # TODO: use django's JsonField args = models.TextField( blank=True, default='[]', verbose_name=_('Positional Arguments'), help_text=_( 'JSON encoded positional arguments ' '(Example: ["arg1", "arg2"])'), ) kwargs = models.TextField( blank=True, default='{}', verbose_name=_('Keyword Arguments'), help_text=_( 'JSON encoded keyword arguments ' '(Example: {"argument": "value"})'), ) queue = models.CharField( max_length=200, blank=True, null=True, default=None, verbose_name=_('Queue Override'), help_text=_( 'Queue defined in CELERY_TASK_QUEUES. ' 'Leave None for default queuing.'), ) # you can use low-level AMQP routing options here, # but you almost certaily want to leave these as None # http://docs.celeryproject.org/en/latest/userguide/routing.html#exchanges-queues-and-routing-keys exchange = models.CharField( max_length=200, blank=True, null=True, default=None, verbose_name=_('Exchange'), help_text=_('Override Exchange for low-level AMQP routing'), ) routing_key = models.CharField( max_length=200, blank=True, null=True, default=None, verbose_name=_('Routing Key'), help_text=_('Override Routing Key for low-level AMQP routing'), ) headers = models.TextField( blank=True, default='{}', verbose_name=_('AMQP Message Headers'), help_text=_('JSON encoded message headers for the AMQP message.'), ) priority = models.PositiveIntegerField( default=None, validators=[MaxValueValidator(255)], blank=True, null=True, verbose_name=_('Priority'), help_text=_( 'Priority Number between 0 and 255. ' 'Supported by: RabbitMQ, Redis (priority reversed, 0 is highest).') ) expires = models.DateTimeField( blank=True, null=True, verbose_name=_('Expires Datetime'), help_text=_( 'Datetime after which the schedule will no longer ' 'trigger the task to run'), ) expire_seconds = models.PositiveIntegerField( blank=True, null=True, verbose_name=_('Expires timedelta with seconds'), help_text=_( 'Timedelta with seconds which the schedule will no longer ' 'trigger the task to run'), ) one_off = models.BooleanField( default=False, verbose_name=_('One-off Task'), help_text=_( 'If True, the schedule will only run the task a single time'), ) start_time = models.DateTimeField( blank=True, null=True, verbose_name=_('Start Datetime'), help_text=_( 'Datetime when the schedule should begin ' 'triggering the task to run'), ) enabled = models.BooleanField( default=True, verbose_name=_('Enabled'), help_text=_('Set to False to disable the schedule'), ) last_run_at = models.DateTimeField( auto_now=False, auto_now_add=False, editable=False, blank=True, null=True, verbose_name=_('Last Run Datetime'), help_text=_( 'Datetime that the schedule last triggered the task to run. ' 'Reset to None if enabled is set to False.'), ) total_run_count = models.PositiveIntegerField( default=0, editable=False, verbose_name=_('Total Run Count'), help_text=_( 'Running count of how many times the schedule ' 'has triggered the task'), ) date_changed = models.DateTimeField( auto_now=True, verbose_name=_('Last Modified'), help_text=_('Datetime that this PeriodicTask was last modified'), ) description = models.TextField( blank=True, verbose_name=_('Description'), help_text=_( 'Detailed description about the details of this Periodic Task'), ) objects = querysets.PeriodicTaskQuerySet.as_manager() no_changes = False class Meta: """Table information.""" verbose_name = _('periodic task') verbose_name_plural = _('periodic tasks') def validate_unique(self, *args, **kwargs): super().validate_unique(*args, **kwargs) schedule_types = ['interval', 'crontab', 'solar', 'clocked'] selected_schedule_types = [s for s in schedule_types if getattr(self, s)] if len(selected_schedule_types) == 0: raise ValidationError( 'One of clocked, interval, crontab, or solar ' 'must be set.' ) err_msg = 'Only one of clocked, interval, crontab, '\ 'or solar must be set' if len(selected_schedule_types) > 1: error_info = {} for selected_schedule_type in selected_schedule_types: error_info[selected_schedule_type] = [err_msg] raise ValidationError(error_info) # clocked must be one off task if self.clocked and not self.one_off: err_msg = 'clocked must be one off, one_off must set True' raise ValidationError(err_msg) def save(self, *args, **kwargs): self.exchange = self.exchange or None self.routing_key = self.routing_key or None self.queue = self.queue or None self.headers = self.headers or None if not self.enabled: self.last_run_at = None self._clean_expires() self.validate_unique() super().save(*args, **kwargs) PeriodicTasks.changed(self) def delete(self, *args, **kwargs): super().delete(*args, **kwargs) PeriodicTasks.changed(self) def _clean_expires(self): if self.expire_seconds is not None and self.expires: raise ValidationError( _('Only one can be set, in expires and expire_seconds') ) @property def expires_(self): return self.expires or self.expire_seconds def __str__(self): fmt = '{0.name}: {{no schedule}}' if self.interval: fmt = '{0.name}: {0.interval}' if self.crontab: fmt = '{0.name}: {0.crontab}' if self.solar: fmt = '{0.name}: {0.solar}' if self.clocked: fmt = '{0.name}: {0.clocked}' return fmt.format(self) @property def scheduler(self): if self.interval: return self.interval if self.crontab: return self.crontab if self.solar: return self.solar if self.clocked: return self.clocked @property def schedule(self): return self.scheduler.schedule django-celery-beat-2.6.0/django_celery_beat/querysets.py000066400000000000000000000004331457112420500233720ustar00rootroot00000000000000"""Model querysets.""" from django.db import models class PeriodicTaskQuerySet(models.QuerySet): """QuerySet for PeriodicTask.""" def enabled(self): return self.filter(enabled=True).prefetch_related( "interval", "crontab", "solar", "clocked" ) django-celery-beat-2.6.0/django_celery_beat/schedulers.py000066400000000000000000000320331457112420500234700ustar00rootroot00000000000000"""Beat Scheduler Implementation.""" import datetime import logging import math from multiprocessing.util import Finalize from celery import current_app, schedules from celery.beat import ScheduleEntry, Scheduler from celery.utils.log import get_logger from celery.utils.time import maybe_make_aware from django.conf import settings from django.core.exceptions import ObjectDoesNotExist from django.db import close_old_connections, transaction from django.db.utils import DatabaseError, InterfaceError from kombu.utils.encoding import safe_repr, safe_str from kombu.utils.json import dumps, loads from .clockedschedule import clocked from .models import (ClockedSchedule, CrontabSchedule, IntervalSchedule, PeriodicTask, PeriodicTasks, SolarSchedule) from .utils import NEVER_CHECK_TIMEOUT # This scheduler must wake up more frequently than the # regular of 5 minutes because it needs to take external # changes to the schedule into account. DEFAULT_MAX_INTERVAL = 5 # seconds ADD_ENTRY_ERROR = """\ Cannot add entry %r to database schedule: %r. Contents: %r """ logger = get_logger(__name__) debug, info, warning = logger.debug, logger.info, logger.warning class ModelEntry(ScheduleEntry): """Scheduler entry taken from database row.""" model_schedules = ( (schedules.crontab, CrontabSchedule, 'crontab'), (schedules.schedule, IntervalSchedule, 'interval'), (schedules.solar, SolarSchedule, 'solar'), (clocked, ClockedSchedule, 'clocked') ) save_fields = ['last_run_at', 'total_run_count', 'no_changes'] def __init__(self, model, app=None): """Initialize the model entry.""" self.app = app or current_app._get_current_object() self.name = model.name self.task = model.task try: self.schedule = model.schedule except model.DoesNotExist: logger.error( 'Disabling schedule %s that was removed from database', self.name, ) self._disable(model) try: self.args = loads(model.args or '[]') self.kwargs = loads(model.kwargs or '{}') except ValueError as exc: logger.exception( 'Removing schedule %s for argument deseralization error: %r', self.name, exc, ) self._disable(model) self.options = {} for option in ['queue', 'exchange', 'routing_key', 'priority']: value = getattr(model, option) if value is None: continue self.options[option] = value if getattr(model, 'expires_', None): self.options['expires'] = getattr(model, 'expires_') self.options['headers'] = loads(model.headers or '{}') self.options['periodic_task_name'] = model.name self.total_run_count = model.total_run_count self.model = model if not model.last_run_at: model.last_run_at = self._default_now() # if last_run_at is not set and # model.start_time last_run_at should be in way past. # This will trigger the job to run at start_time # and avoid the heap block. if self.model.start_time: model.last_run_at = model.last_run_at \ - datetime.timedelta(days=365 * 30) self.last_run_at = model.last_run_at def _disable(self, model): model.no_changes = True model.enabled = False model.save() def is_due(self): if not self.model.enabled: # 5 second delay for re-enable. return schedules.schedstate(False, 5.0) # START DATE: only run after the `start_time`, if one exists. if self.model.start_time is not None: now = self._default_now() if getattr(settings, 'DJANGO_CELERY_BEAT_TZ_AWARE', True): now = maybe_make_aware(self._default_now()) if now < self.model.start_time: # The datetime is before the start date - don't run. # send a delay to retry on start_time delay = math.ceil( (self.model.start_time - now).total_seconds() ) return schedules.schedstate(False, delay) # ONE OFF TASK: Disable one off tasks after they've ran once if self.model.one_off and self.model.enabled \ and self.model.total_run_count > 0: self.model.enabled = False self.model.total_run_count = 0 # Reset self.model.no_changes = False # Mark the model entry as changed self.model.save() # Don't recheck return schedules.schedstate(False, NEVER_CHECK_TIMEOUT) # CAUTION: make_aware assumes settings.TIME_ZONE for naive datetimes, # while maybe_make_aware assumes utc for naive datetimes tz = self.app.timezone last_run_at_in_tz = maybe_make_aware(self.last_run_at).astimezone(tz) return self.schedule.is_due(last_run_at_in_tz) def _default_now(self): if getattr(settings, 'DJANGO_CELERY_BEAT_TZ_AWARE', True): now = datetime.datetime.now(self.app.timezone) else: # this ends up getting passed to maybe_make_aware, which expects # all naive datetime objects to be in utc time. now = datetime.datetime.utcnow() return now def __next__(self): self.model.last_run_at = self._default_now() self.model.total_run_count += 1 self.model.no_changes = True return self.__class__(self.model) next = __next__ # for 2to3 def save(self): # Object may not be synchronized, so only # change the fields we care about. obj = type(self.model)._default_manager.get(pk=self.model.pk) for field in self.save_fields: setattr(obj, field, getattr(self.model, field)) obj.save() @classmethod def to_model_schedule(cls, schedule): for schedule_type, model_type, model_field in cls.model_schedules: schedule = schedules.maybe_schedule(schedule) if isinstance(schedule, schedule_type): model_schedule = model_type.from_schedule(schedule) model_schedule.save() return model_schedule, model_field raise ValueError( f'Cannot convert schedule type {schedule!r} to model') @classmethod def from_entry(cls, name, app=None, **entry): obj, created = PeriodicTask._default_manager.update_or_create( name=name, defaults=cls._unpack_fields(**entry), ) return cls(obj, app=app) @classmethod def _unpack_fields(cls, schedule, args=None, kwargs=None, relative=None, options=None, **entry): entry_schedules = { model_field: None for _, _, model_field in cls.model_schedules } model_schedule, model_field = cls.to_model_schedule(schedule) entry_schedules[model_field] = model_schedule entry.update( entry_schedules, args=dumps(args or []), kwargs=dumps(kwargs or {}), **cls._unpack_options(**options or {}) ) return entry @classmethod def _unpack_options(cls, queue=None, exchange=None, routing_key=None, priority=None, headers=None, expire_seconds=None, **kwargs): return { 'queue': queue, 'exchange': exchange, 'routing_key': routing_key, 'priority': priority, 'headers': dumps(headers or {}), 'expire_seconds': expire_seconds, } def __repr__(self): return ''.format( safe_str(self.name), self.task, safe_repr(self.args), safe_repr(self.kwargs), self.schedule, ) class DatabaseScheduler(Scheduler): """Database-backed Beat Scheduler.""" Entry = ModelEntry Model = PeriodicTask Changes = PeriodicTasks _schedule = None _last_timestamp = None _initial_read = True _heap_invalidated = False def __init__(self, *args, **kwargs): """Initialize the database scheduler.""" self._dirty = set() Scheduler.__init__(self, *args, **kwargs) self._finalize = Finalize(self, self.sync, exitpriority=5) self.max_interval = ( kwargs.get('max_interval') or self.app.conf.beat_max_loop_interval or DEFAULT_MAX_INTERVAL) def setup_schedule(self): self.install_default_entries(self.schedule) self.update_from_dict(self.app.conf.beat_schedule) def all_as_schedule(self): debug('DatabaseScheduler: Fetching database schedule') s = {} for model in self.Model.objects.enabled(): try: s[model.name] = self.Entry(model, app=self.app) except ValueError: pass return s def schedule_changed(self): try: close_old_connections() # If MySQL is running with transaction isolation level # REPEATABLE-READ (default), then we won't see changes done by # other transactions until the current transaction is # committed (Issue #41). try: transaction.commit() except transaction.TransactionManagementError: pass # not in transaction management. last, ts = self._last_timestamp, self.Changes.last_change() except DatabaseError as exc: logger.exception('Database gave error: %r', exc) return False except InterfaceError: warning( 'DatabaseScheduler: InterfaceError in schedule_changed(), ' 'waiting to retry in next call...' ) return False try: if ts and ts > (last if last else ts): return True finally: self._last_timestamp = ts return False def reserve(self, entry): new_entry = next(entry) # Need to store entry by name, because the entry may change # in the mean time. self._dirty.add(new_entry.name) return new_entry def sync(self): if logger.isEnabledFor(logging.DEBUG): debug('Writing entries...') _tried = set() _failed = set() try: close_old_connections() while self._dirty: name = self._dirty.pop() try: self._schedule[name].save() _tried.add(name) except (KeyError, TypeError, ObjectDoesNotExist): _failed.add(name) except DatabaseError as exc: logger.exception('Database error while sync: %r', exc) except InterfaceError: warning( 'DatabaseScheduler: InterfaceError in sync(), ' 'waiting to retry in next call...' ) finally: # retry later, only for the failed ones self._dirty |= _failed def update_from_dict(self, mapping): s = {} for name, entry_fields in mapping.items(): try: entry = self.Entry.from_entry(name, app=self.app, **entry_fields) if entry.model.enabled: s[name] = entry except Exception as exc: logger.exception(ADD_ENTRY_ERROR, name, exc, entry_fields) self.schedule.update(s) def install_default_entries(self, data): entries = {} if self.app.conf.result_expires: entries.setdefault( 'celery.backend_cleanup', { 'task': 'celery.backend_cleanup', 'schedule': schedules.crontab('0', '4', '*'), 'options': {'expire_seconds': 12 * 3600}, }, ) self.update_from_dict(entries) def schedules_equal(self, *args, **kwargs): if self._heap_invalidated: self._heap_invalidated = False return False return super().schedules_equal(*args, **kwargs) @property def schedule(self): initial = update = False if self._initial_read: debug('DatabaseScheduler: initial read') initial = update = True self._initial_read = False elif self.schedule_changed(): info('DatabaseScheduler: Schedule changed.') update = True if update: self.sync() self._schedule = self.all_as_schedule() # the schedule changed, invalidate the heap in Scheduler.tick if not initial: self._heap = [] self._heap_invalidated = True if logger.isEnabledFor(logging.DEBUG): debug('Current schedule:\n%s', '\n'.join( repr(entry) for entry in self._schedule.values()), ) return self._schedule django-celery-beat-2.6.0/django_celery_beat/signals.py000066400000000000000000000023371457112420500227730ustar00rootroot00000000000000"""Django Application signals.""" def signals_connect(): """Connect to signals.""" from django.db.models import signals from .models import (ClockedSchedule, CrontabSchedule, IntervalSchedule, PeriodicTask, PeriodicTasks, SolarSchedule) signals.pre_save.connect( PeriodicTasks.changed, sender=PeriodicTask ) signals.pre_delete.connect( PeriodicTasks.changed, sender=PeriodicTask ) signals.post_save.connect( PeriodicTasks.update_changed, sender=IntervalSchedule ) signals.pre_delete.connect( PeriodicTasks.update_changed, sender=IntervalSchedule ) signals.post_save.connect( PeriodicTasks.update_changed, sender=CrontabSchedule ) signals.post_delete.connect( PeriodicTasks.update_changed, sender=CrontabSchedule ) signals.post_save.connect( PeriodicTasks.update_changed, sender=SolarSchedule ) signals.post_delete.connect( PeriodicTasks.update_changed, sender=SolarSchedule ) signals.post_save.connect( PeriodicTasks.update_changed, sender=ClockedSchedule ) signals.post_delete.connect( PeriodicTasks.update_changed, sender=ClockedSchedule ) django-celery-beat-2.6.0/django_celery_beat/templates/000077500000000000000000000000001457112420500227525ustar00rootroot00000000000000django-celery-beat-2.6.0/django_celery_beat/templates/admin/000077500000000000000000000000001457112420500240425ustar00rootroot00000000000000django-celery-beat-2.6.0/django_celery_beat/templates/admin/djcelery/000077500000000000000000000000001457112420500256435ustar00rootroot00000000000000django-celery-beat-2.6.0/django_celery_beat/templates/admin/djcelery/change_list.html000066400000000000000000000013251457112420500310120ustar00rootroot00000000000000{% extends "admin/change_list.html" %} {% load i18n %} {% block breadcrumbs %} {% if wrong_scheduler %}
  • Periodic tasks won't be dispatched unless you set the CELERY_BEAT_SCHEDULER setting to djcelery.schedulers.DatabaseScheduler, or specify it using the -S option to celerybeat
{% endif %} {% endblock %} django-celery-beat-2.6.0/django_celery_beat/templates/admin/djcelery/change_periodictask_form.html000066400000000000000000000014721457112420500335460ustar00rootroot00000000000000{% extends 'admin/change_form.html' %} {% block admin_change_form_document_ready %} {{ block.super }} {{ readable_crontabs|json_script:"readable-crontabs" }} {% endblock %} django-celery-beat-2.6.0/django_celery_beat/tzcrontab.py000066400000000000000000000047311457112420500233410ustar00rootroot00000000000000"""Timezone aware Cron schedule Implementation.""" from collections import namedtuple from datetime import datetime, timezone from celery import schedules schedstate = namedtuple('schedstate', ('is_due', 'next')) class TzAwareCrontab(schedules.crontab): """Timezone Aware Crontab.""" def __init__( self, minute='*', hour='*', day_of_week='*', day_of_month='*', month_of_year='*', tz=timezone.utc, app=None ): """Overwrite Crontab constructor to include a timezone argument.""" self.tz = tz nowfun = self.nowfunc super().__init__( minute=minute, hour=hour, day_of_week=day_of_week, day_of_month=day_of_month, month_of_year=month_of_year, nowfun=nowfun, app=app ) def nowfunc(self): return datetime.now(self.tz) def is_due(self, last_run_at): """Calculate when the next run will take place. Return tuple of ``(is_due, next_time_to_check)``. The ``last_run_at`` argument needs to be timezone aware. """ # convert last_run_at to the schedule timezone last_run_at = last_run_at.astimezone(self.tz) rem_delta = self.remaining_estimate(last_run_at) rem = max(rem_delta.total_seconds(), 0) due = rem == 0 if due: rem_delta = self.remaining_estimate(self.now()) rem = max(rem_delta.total_seconds(), 0) return schedstate(due, rem) # Needed to support pickling def __repr__(self): return """ """.format(self) def __reduce__(self): return (self.__class__, (self._orig_minute, self._orig_hour, self._orig_day_of_week, self._orig_day_of_month, self._orig_month_of_year, self.tz), None) def __eq__(self, other): if isinstance(other, schedules.crontab): return (other.month_of_year == self.month_of_year and other.day_of_month == self.day_of_month and other.day_of_week == self.day_of_week and other.hour == self.hour and other.minute == self.minute and other.tz == self.tz) return NotImplemented django-celery-beat-2.6.0/django_celery_beat/utils.py000066400000000000000000000031471457112420500224730ustar00rootroot00000000000000"""Utilities.""" # -- XXX This module must not use translation as that causes # -- a recursive loader import! from datetime import timezone as datetime_timezone from django.conf import settings from django.utils import timezone is_aware = timezone.is_aware # celery schedstate return None will make it not work NEVER_CHECK_TIMEOUT = 100000000 # see Issue #222 now_localtime = getattr(timezone, 'template_localtime', timezone.localtime) def make_aware(value): """Force datatime to have timezone information.""" if getattr(settings, 'USE_TZ', False): # naive datetimes are assumed to be in UTC. if timezone.is_naive(value): value = timezone.make_aware(value, datetime_timezone.utc) # then convert to the Django configured timezone. default_tz = timezone.get_default_timezone() value = timezone.localtime(value, default_tz) else: # naive datetimes are assumed to be in local timezone. if timezone.is_naive(value): value = timezone.make_aware(value, timezone.get_default_timezone()) return value def now(): """Return the current date and time.""" if getattr(settings, 'USE_TZ', False): return now_localtime(timezone.now()) else: return timezone.now() def is_database_scheduler(scheduler): """Return true if Celery is configured to use the db scheduler.""" if not scheduler: return False from kombu.utils import symbol_by_name from .schedulers import DatabaseScheduler return ( scheduler == 'django' or issubclass(symbol_by_name(scheduler), DatabaseScheduler) ) django-celery-beat-2.6.0/django_celery_beat/validators.py000066400000000000000000000055441457112420500235060ustar00rootroot00000000000000"""Validators.""" import crontab from django.core.exceptions import ValidationError class _CronSlices(crontab.CronSlices): """Cron slices with customized validation.""" def __init__(self, *args): super(crontab.CronSlices, self).__init__( [_CronSlice(info) for info in crontab.S_INFO] ) self.special = None self.setall(*args) self.is_valid = self.is_self_valid @classmethod def validate(cls, *args): try: cls(*args) except Exception as e: raise ValueError(e) class _CronSlice(crontab.CronSlice): """Cron slice with custom range parser.""" def get_range(self, *vrange): ret = _CronRange(self, *vrange) if ret.dangling is not None: return [ret.dangling, ret] return [ret] class _CronRange(crontab.CronRange): """Cron range parser class.""" # rewrite whole method to raise error on bad range def parse(self, value): if value.count('/') == 1: value, seq = value.split('/') try: self.seq = self.slice.parse_value(seq) except crontab.SundayError: self.seq = 1 value = "0-0" if self.seq < 1 or self.seq > self.slice.max: raise ValueError("Sequence can not be divided by zero or max") if value.count('-') == 1: vfrom, vto = value.split('-') self.vfrom = self.slice.parse_value(vfrom, sunday=0) try: self.vto = self.slice.parse_value(vto) except crontab.SundayError: if self.vfrom == 1: self.vfrom = 0 else: self.dangling = 0 self.vto = self.slice.parse_value(vto, sunday=6) if self.vto < self.vfrom: raise ValueError("Bad range '{0.vfrom}-{0.vto}'".format(self)) elif value == '*': self.all() else: raise ValueError('Unknown cron range value "%s"' % value) def crontab_validator(value): """Validate crontab.""" try: _CronSlices.validate(value) except ValueError as e: raise ValidationError(e) def minute_validator(value): """Validate minutes crontab value.""" _validate_crontab(value, 0) def hour_validator(value): """Validate hours crontab value.""" _validate_crontab(value, 1) def day_of_month_validator(value): """Validate day of month crontab value.""" _validate_crontab(value, 2) def month_of_year_validator(value): """Validate month crontab value.""" _validate_crontab(value, 3) def day_of_week_validator(value): """Validate day of week crontab value.""" _validate_crontab(value, 4) def _validate_crontab(value, index): tab = ['*'] * 5 tab[index] = value tab = ' '.join(tab) crontab_validator(tab) django-celery-beat-2.6.0/docker-compose.yml000066400000000000000000000026751457112420500206230ustar00rootroot00000000000000# Copyright (C) 2019 Sebastian Pipping # Licensed under the BSD License (3 clause, also known as the new BSD license) version: '3' services: base: build: context: . dockerfile: docker/base/Dockerfile command: ["sleep", "inf"] django: depends_on: - base - postgres - rabbit build: context: . dockerfile: docker/django/Dockerfile ports: - "${DJANGO_HOST:-127.0.0.1}:${DJANGO_PORT:-58000}:8000" entrypoint: ["/app/docker/django/entrypoint.sh"] command: ["python3", "manage.py", "runserver", "0.0.0.0:${DJANGO_PORT:-8000}"] tty: true volumes: - './django_celery_beat/:/app/django_celery_beat/' celery-beat: depends_on: - base - postgres - rabbit build: context: . dockerfile: docker/celery-beat/Dockerfile entrypoint: ["/app/docker/celery-beat/entrypoint.sh"] environment: CELERY_BROKER_URL: 'amqp://${RABBITMQ_USER:-guest}:${RABBITMQ_PASSWORD:-guest}@${RABBITMQ_HOST:-rabbit}:${RABBITMQ_PORT:-5672}' command: ["python3", '-m', "celery", "-A", "mysite", "beat", "-l", "info", "--scheduler", "django_celery_beat.schedulers:DatabaseScheduler"] tty: true volumes: - './django_celery_beat/:/app/django_celery_beat/' rabbit: image: rabbitmq ports: - "${RABBITMQ_PORT:-5672}:5672" postgres: image: postgres environment: POSTGRES_PASSWORD: s3cr3t django-celery-beat-2.6.0/docker/000077500000000000000000000000001457112420500164235ustar00rootroot00000000000000django-celery-beat-2.6.0/docker/base/000077500000000000000000000000001457112420500173355ustar00rootroot00000000000000django-celery-beat-2.6.0/docker/base/Dockerfile000066400000000000000000000021161457112420500213270ustar00rootroot00000000000000# Copyright (C) 2019 Sebastian Pipping # Licensed under the BSD License (3 clause, also known as the new BSD license) FROM python:3.9-slim ENV PATH=${PATH}:/root/.local/bin RUN apt-get update && apt-get install --yes --no-install-recommends \ wait-for-it RUN pip3 install --user \ django-createsuperuserwithpassword \ psycopg2-binary COPY setup.cfg setup.py /app/ COPY django_celery_beat/ /app/django_celery_beat/ COPY requirements/ /app/requirements/ WORKDIR /app RUN python3 setup.py develop --user WORKDIR / RUN django-admin startproject mysite WORKDIR /mysite/ RUN echo 'DATABASES = {"default": {"ENGINE": "django.db.backends.postgresql", "NAME": "postgres", "USER": "postgres","PASSWORD": "s3cr3t", "HOST": "postgres", "PORT": 5432}}' >> mysite/settings.py RUN echo 'ALLOWED_HOSTS = ["*"]' >> mysite/settings.py RUN echo 'INSTALLED_APPS += ("django_celery_beat", )' >> mysite/settings.py RUN echo 'INSTALLED_APPS += ("django_createsuperuserwithpassword", )' >> mysite/settings.py COPY docker/base/celery.py mysite/celery.py django-celery-beat-2.6.0/docker/base/celery.py000066400000000000000000000004201457112420500211660ustar00rootroot00000000000000# Copyright (C) 2019 Sebastian Pipping # Licensed under the BSD License (3 clause, also known as the new BSD license) import os from celery import Celery os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings') app = Celery('mysite') django-celery-beat-2.6.0/docker/celery-beat/000077500000000000000000000000001457112420500206175ustar00rootroot00000000000000django-celery-beat-2.6.0/docker/celery-beat/Dockerfile000066400000000000000000000004361457112420500226140ustar00rootroot00000000000000# Copyright (C) 2019 Sebastian Pipping # Licensed under the BSD License (3 clause, also known as the new BSD license) ARG COMPOSE_PROJECT_NAME=django-celery-beat FROM ${COMPOSE_PROJECT_NAME}_base COPY docker/celery-beat/entrypoint.sh /app/docker/celery-beat/ django-celery-beat-2.6.0/docker/celery-beat/entrypoint.sh000077500000000000000000000003651457112420500233750ustar00rootroot00000000000000#! /usr/bin/env bash # Copyright (C) 2019 Sebastian Pipping # Licensed under the BSD License (3 clause, also known as the new BSD license) set -e PS4='# ' set -x wait-for-it django:8000 # due to migrations exec "$@" django-celery-beat-2.6.0/docker/django/000077500000000000000000000000001457112420500176655ustar00rootroot00000000000000django-celery-beat-2.6.0/docker/django/Dockerfile000066400000000000000000000004241457112420500216570ustar00rootroot00000000000000# Copyright (C) 2019 Sebastian Pipping # Licensed under the BSD License (3 clause, also known as the new BSD license) ARG COMPOSE_PROJECT_NAME=django-celery-beat FROM ${COMPOSE_PROJECT_NAME}_base COPY docker/django/entrypoint.sh /app/docker/django/ django-celery-beat-2.6.0/docker/django/entrypoint.sh000077500000000000000000000006331457112420500224410ustar00rootroot00000000000000#! /usr/bin/env bash # Copyright (C) 2019 Sebastian Pipping # Licensed under the BSD License (3 clause, also known as the new BSD license) set -e PS4='# ' set -x wait-for-it postgres:5432 python3 manage.py migrate python3 manage.py createsuperuserwithpassword \ --username admin \ --password admin \ --email admin@example.org \ --preserve exec "$@" django-celery-beat-2.6.0/docs/000077500000000000000000000000001457112420500161045ustar00rootroot00000000000000django-celery-beat-2.6.0/docs/Makefile000066400000000000000000000203171457112420500175470ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don\'t have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " applehelp to make an Apple Help Book" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " epub3 to make an epub3" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" @echo " coverage to run coverage check of the documentation (if enabled)" @echo " apicheck to verify that all modules are present in autodoc" @echo " configcheck to verify that all modules are present in autodoc" @echo " spelling to run a spell checker on the documentation" .PHONY: clean clean: rm -rf $(BUILDDIR)/* .PHONY: html html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." .PHONY: dirhtml dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." .PHONY: singlehtml singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." .PHONY: pickle pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." .PHONY: json json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." .PHONY: htmlhelp htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." .PHONY: qthelp qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PROJ.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PROJ.qhc" .PHONY: applehelp applehelp: $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp @echo @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." @echo "N.B. You won't be able to view it unless you put it in" \ "~/Library/Documentation/Help or install it in your application" \ "bundle." .PHONY: devhelp devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/PROJ" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PROJ" @echo "# devhelp" .PHONY: epub epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." .PHONY: epub3 epub3: $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 @echo @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." .PHONY: latex latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." .PHONY: latexpdf latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." .PHONY: latexpdfja latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." .PHONY: text text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." .PHONY: man man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." .PHONY: texinfo texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." .PHONY: info info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." .PHONY: gettext gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/django_celery_beat/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/django_celery_beat/locale." .PHONY: changes changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." .PHONY: linkcheck linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." .PHONY: doctest doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." .PHONY: coverage coverage: $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage @echo "Testing of coverage in the sources finished, look at the " \ "results in $(BUILDDIR)/coverage/python.txt." .PHONY: apicheck apicheck: $(SPHINXBUILD) -b apicheck $(ALLSPHINXOPTS) $(BUILDDIR)/apicheck .PHONY: configcheck configcheck: $(SPHINXBUILD) -b configcheck $(ALLSPHINXOPTS) $(BUILDDIR)/configcheck .PHONY: spelling spelling: SPELLCHECK=1 $(SPHINXBUILD) -b spelling $(ALLSPHINXOPTS) $(BUILDDIR)/spelling .PHONY: xml xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." .PHONY: pseudoxml pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." django-celery-beat-2.6.0/docs/_static/000077500000000000000000000000001457112420500175325ustar00rootroot00000000000000django-celery-beat-2.6.0/docs/_static/.keep000066400000000000000000000000001457112420500204450ustar00rootroot00000000000000django-celery-beat-2.6.0/docs/_templates/000077500000000000000000000000001457112420500202415ustar00rootroot00000000000000django-celery-beat-2.6.0/docs/_templates/.keep000066400000000000000000000000001457112420500211540ustar00rootroot00000000000000django-celery-beat-2.6.0/docs/changelog.rst000066400000000000000000000000321457112420500205600ustar00rootroot00000000000000.. include:: ../Changelog django-celery-beat-2.6.0/docs/conf.py000066400000000000000000000026071457112420500174100ustar00rootroot00000000000000import os from sphinx_celery import conf globals().update(conf.build_config( 'django_celery_beat', __file__, project='django_celery_beat', # version_dev='2.0', # version_stable='1.4', canonical_url='http://django-celery-beat.readthedocs.io', webdomain='', github_project='celery/django-celery-beat', copyright='2016', django_settings='proj.settings', include_intersphinx={'python', 'sphinx', 'django', 'celery'}, path_additions=[os.path.join(os.pardir, 't')], html_logo='images/logo.png', html_favicon='images/favicon.ico', html_prepend_sidebars=[], apicheck_ignore_modules=[ 'django_celery_beat.apps', r'django_celery_beat.migrations.*', ], extlinks={ 'github_project': ( 'https://github.com/%s', 'GitHub project %s', ), 'github_pr': ( 'https://github.com/celery/django-celery-beat/pull/%s', 'GitHub PR #%s', ), }, extra_intersphinx_mapping={ 'django-celery-results': ( 'https://django-celery-results.readthedocs.io/en/latest/', None ), }, extensions=['sphinxcontrib_django'] )) intersphinx_mapping = globals().get('intersphinx_mapping', {}) intersphinx_mapping['celery'] = ( 'https://celery.readthedocs.io/en/main/', None) globals().update({'intersphinx_mapping': intersphinx_mapping}) django-celery-beat-2.6.0/docs/copyright.rst000066400000000000000000000017001457112420500206440ustar00rootroot00000000000000Copyright ========= *django-celery-beat User Manual* by Ask Solem .. |copy| unicode:: U+000A9 .. COPYRIGHT SIGN Copyright |copy| 2016, Ask Solem All rights reserved. This material may be copied or distributed only subject to the terms and conditions set forth in the `Creative Commons Attribution-ShareAlike 4.0 International `_ license. You may share and adapt the material, even for commercial purposes, but you must give the original author credit. If you alter, transform, or build upon this work, you may distribute the resulting work only under the same license or a license compatible to this one. .. note:: While the django-celery-beat *documentation* is offered under the Creative Commons *Attribution-ShareAlike 4.0 International* license the django-celery-beat *software* is offered under the `BSD License (3 Clause) `_ django-celery-beat-2.6.0/docs/glossary.rst000066400000000000000000000001431457112420500204770ustar00rootroot00000000000000.. _glossary: Glossary ======== .. glossary:: :sorted: term Description of term django-celery-beat-2.6.0/docs/images/000077500000000000000000000000001457112420500173515ustar00rootroot00000000000000django-celery-beat-2.6.0/docs/images/favicon.ico000066400000000000000000003025361457112420500215030ustar00rootroot00000000000000 (V@@ (B~00 %J  Np h(   @@ @ + 3"(&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&(3"+ @ @@++3"'! 8 L _gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg _ L 8'!3"++@+ "%Z#2!?*E,D*D+D+D,D,D+D+E,D,D,D,D,D,D,D,D,D,D,D+D+D+D,D+D,D,D,D,D,D,E.D,D,D+D,D,E.D,D,E,E.E.E.E,E,E,E.E,D,E,E,E,E,D,D,D,E.D+D,D+D+D,E.D,D,D,D,D+E,E,D,D,D,D,D,D+D,D,D,D,D,D,D,D,D,D,D+D+D+D+D,D+D*D+E,E,?(2 #Z"%+ @3"! >'B+\9mD tG vH tG vH vH vH vI vH vI yK vH xJ zL yK yK zL yKxJyK yK {M {M |NyK {M |N zL |N{M{L {M }O ~P |N {M }O |N }O }O |M |N ~P |N }P~Q }O }O~Q }P |N }O }P}P}P ~P |M |N }O{M }O |N |M {M}O }O |N {M {M{M {M zLzL zLyLyK zL {M yK yK zLzK wI xJ yKxJ yK yK vH vH wI uH vH uG tF tG vH uG rFlB\:B+'! >3";' )K6"\: tGsE oC kA j? mA j? l@ j? i> k@ mA l@ mA k? nA mA mA nB nBnBpD oCqEpD pD nAqE pDqE qD pDqE oC qE rErFsHrGsHrFrFrGsHsH rG rEsGrF rFrF rFsGsHrGsHsGsG rEsHrFsG rF rErF pC rFqErFsHrFsGpD nC pDqF pD nB nB pD nB nA oB nA mA nB mA nB mA l@ i? l@ j? k@ i? i? i?f=h> i? k? qDuF vH]:6" )K;  &D9%kCwH kAd<d<f=i?j?k@lAk@i?j@oCoCoCmBmAnBnCnBoCpEoDpDoDqEoCoCsHpErGrHpFqGpEqFrGsHsItItIrHrGrHuJuJtJsIrHtIsIrHtItJsItIsHtJrHqGuJrHsHsIqGrHpEqFrGrHrHrGrHpEoDpEsHqFpEpDnCoCoCnCoCpDnCnBmAnBlAj?nBk@lAlAi?j?g>g>h>g=e=e< k?wHjA:%&D U#$4#mDxIg=g=j?lAmAqEqErEpDqEsGsGsGtIuJsHsGvJvJsGuIxLvJuJuJuJwKwKwLvKzNxLwLxMyMyMxL{NzNzNyMyM{OzN{N|O|PzNzN|O|OyM{N}P{O{NyMyM{NzNzMyM|OyMxLxMyMyMxLzNyMxMwKwLxMxLwLxLxMvKuIwKwLsHuIwLuItHsGrFrGrFsFqEtGrEpDqDpDpDoCoClA i?e=f=xHlC4!#$UU+*^<|Li>l@mBqDsGtHuItHtHxLzMyMzMyM{N{NyMzN{N{OzN{O|O|OzN}P{N~QR~Q~QR~QSRS SRSR~Q T!U U!U T"V!US U!U US!T U TS UR!U"U SS TR!TS S SRR~Q}PRSRR}PR~Q{O|P|O|OzN{N|OzNxLzNwL{N{NxLxLxLvJxLwKvJvJtHsGqDnBnBl@i?{K];,+U$E, yK oCi>pDrFuIvK|OxLxL{N}O}P}P|O|O}P}P}O}PRR~Q!U!T S S TR!U!U!U T T U"V#W#W"W$Y"V!U#X$Y$Z#Y#X#X#X#Y"X#X#Y#Y"X%[$Z#Y#Y$Y"W$Z#Y#Y#W"W"V$X#X#X"W%Y"V T"V#W#W"V!T T T TRS S S~Q!T S~Q~Q~P|O~Q}P}P|O{N{N|O|O{OzM{OwKtHsHrFoCk@ oC wJD,$U!^_=yJk?oCrFuIzN|O|O}P R~Q~Q~QR R!S R S!T"U S!U"U"V#V"V$W$X"V$Y$Y%Y"V$X$Y$Y$Z&\&\%[%[&]%[$[$[%\%\%]%\%]%]&]$\%\%\%]%]%\&^'^$[&^&]&^#Z%[%\$[%[&\&\%[%Z%[$Y$Y$X$X$X$X#W#W#W#W!U"V"V"U"U T"U"UR!T!S!S}O~QQ~P}P~Q~P}O{O{NxKuIqEnBk@zK^;#^U3 sI vHl@sGwKzM|O~P~Q S#V"T!TR!T"V"U#V$X$X$X#W$X%Y%Z$X%Z&[%Z$Y%Z&[%[%Z$Y&]']&]&]&]&]'_)a(`'_%]&^(`'_'_(`(a(`'_'`(a)b&_(`(a(`&^'_'_'_&^%\'_'_&^&]&]&]&](`'^&\$Y%Z&\&[%[&[&[&Z$X$X%Y%Y#V$X$X#W"U"U"U"U!SR"T!T SRR~Q~Q R}PzNtGqEnC wIsH3" A+|NtInBuI{O}P~P"T#U!S"U#V"T S!T#V#W$W$X%Z$X#W$Y'['\%Z%Z&[&\%Y&\%\&]'^%['^(`(_'_)b)b'_(a)a'`&^'_(a(a(a)b*d(a'_)a+e+e)a(a(a(a'_(`(`(`(a&^(`)a(`'_)b)a&^(`(`&]%[%\&]&\&\'](]%Z$X%Z'\'[$Y$X$X$X"U#V#V#V#V!S"U#V"U S#U"UR!SQ{NvJsGpDsH{NC+ I0QwKrEvJ}O~Q!T!T!T#V!T"U!T#U!T#V$X$X$X#W$X%Y$X&[&[&['\&]&]']&\&]'^)`&^%](`(`(a(a(`)c(`(a(`(a'_(a)c)b)b(`(b)c(`*c)b)c*c)b)c)b(a(a)b*c(`'_)a)a)b(a(`)a'_(_&^'^%\&]'^'^&]%[%[&\$Y&[%Z%Z%Z%Y%Y%Y#V#V#W$X"U!T#U"U#V"T!S"TRR|O{NuHrFuI~QI1K1TuItIvK|O R#U!T!U"U"U!T"U$X"U"V#W%Y$X$X&Z&[%Y$Y&[&\'^%\'^(_'^(`'_'_(_&^'_(`)b)a(a)b(a'`(a*d(`(a(b)c)c(b*d*d)b(b)c)c*d(b*d*e)c*e)c)b)b'`(a(a*d)a(a(a'_&_'_)a&]&^'^'^']&\'^']&[$Y%Z%Z&[$X%Y%Z$X%Y#W#W#V T"T"U#V!U!T!S R~Q~Q~QwKsFuISK1K1VyMuI{N}P S"U#V"U"U"U#V$W#V$X"U%Y'[&[&Z$Y'\']%[%['^&]'^(`&](`(`)a)a'_(`'_(a)c+e)b)b(b*c*d)c*e)c,f.i,h,g+e-h-h+e+e,g*e*f+f)b*e*e+e+e(b)c(a)b)d+e)b(a(`)a)b'_(`%](`)a(`'^%\'_'^%[%['\%Z%Z&[#W%Y%Z%Z%Y#V#V"U"U#V#V"U!T S!S R}P{NsGxKVK1J1XzNwK~Q~Q"T"U"U!T"V#V$X%Y$X$X$X%Z'\&Z']&[%Z&]&\&\'_&^'^'_(`&^(`*c)b(`*d)b)c)c*c)c*e+f.h/j0i/i/i1l4n1l2n1l0k1l1j/j0k0j/j.i.i,g-h-i,g*d,g*d*d)d)d(a)b)b)d*d)b(`'`(a)b(`)a'_&]'^&\%\&]&[%[%Z&[$X%Y&[%Y#V%Y#V#W#V"U T!T!T#U"TR{OvJyMVK1K1VyM{N}P~Q"U#V"V!U"U"U#V$W%Y$X%Z%Z%Z']&\%['^(_'^'^&^'^'^(`*c(a(`)a(a*e)c(b+f,g+f-g.h/i2l2n3p5r8u:v{?{=z;x9w7t6r2o4p5r3n1l1l/j1m.i+f-i,g)e)c(b'a(b)b)c(b)b(a(`)b(`&^(`(`'^']%\%[%Z&\(^%Z$Y$Y$X&[$X"U$X$X"V!T!T S!T S S|OxLyMVK1K1W|O|O~Q R"U#V$X#W$X$X#W#W$X%Z&[(]&[%[%[']'^'^'_'^(a(a(`'_)b*c(a(b*d+e*e*d+f.i2l3m6q;wFT`jšq̩yϯxήxЯyϯxήyаyϯyήr̪nʧkţfZTJA|9v6t3r3p1l0k0k/k-h-h+f*d)c(b*c)c+e(a(`'_(a(`(`'_&](_(_&\%Z&\&\$Y%Y%Z&[%Y#W#W$W$X#V$W#U!T S~Q}PzM}PWK1J1X~Q|O~P R$X#W$W#W&[%Y&Z%Y$Y'\'\&\']&\&\&\'^&]'^'`)c)b*c)b'`)b)c)c,g,g+f-h2m5p8tGcvέ~ϲ~ǭwsdaZyNxjOwiQoTs[wabfsv{©}ɮϲ|Ѳtͫkǣ_NA}HteeyгwϮfM=z7u4p0j.h-g*d*c)b)b(a(`(a'_'^(`(_'_'^']'\'\$X%Y&Z$X$Y$X$X#W"UR|OQZJ1K1Y~Q}P T!U$X&Z%Y%Y'\&[&]'^'^'](`(`'_'`)b)b(a(a)c*d+f)d+g+g*e+f.k1o7uMwϮc =,1#=*;)7&7%<)<*1!=*;)7&7%=*=*1!<*=*:'5$=*?+1 <)<)8&6%>+@-4%@.=*& *7UK^yβwέcH8u4p3m0i,f*e*d*d(`*c)b'_&^'_'^'^'^&]%Z%['\%Y$X&[$X$X$X#VQ|O~QYJ1K2\R|OS"V$Y%Z&[%Y&['\&\'^'^&](`(`'_'_(a*d)c*c+e*e+f(d*e,i-k.j1o8wKxͭUr6%3$:(:(9'3"=*<)3";(<):(2"=*<)4#<)<)<)3"?+;)3"=*>*:(2!>+<)2!:(:(:(2!@-?,4%6$& 7[N]x}ϱmȥO+?+2 >+>+9&7%=*=*3"?+@+8&7%>*>+4">*=*9&7%?+=*1 >+=*7%6%=*<*1"?-;))BfYk}̰pʨO:t3n0j*d*c)b(b*d(a'_(`'_(`']&\']'\%Y&[%Y$X$W#V#V!T{O}PYK1K1YS~R!U$X$Y$Y&['^'^&\&\%](_)a(a)b)b*d*c+e)d+f+g)e*g+i,i-k/m5u+<)5$?*>*=*7$@,=*7%=*<)>*5$?+?+7$?+<)<*5#>+>*6$=*<);)5#?+=*4#:(:'9'2"A.?--2PEdzǫcŞ>x0i,g+f*d*d(a(a'`'_(`(`'_'^&\%[&\'\&[$X#W#V#V"U}PQZK2K2[Q~Q"V#W'\%Z&\(_'^'^(_%]'`(`'_(a+e*d+e+f+g*e*e*g,j-k-k.m3s:w^k6&=+6%:'>+>+4"?+?+:'7%>+@,4#?+?+;':&=*>+3"<)<):'<'>*?+5#@,>+:'8&>+A,3"A,>+9':&>+>+2!<)=)7%5$=*?-/!! *>7LtA|3n1k-i+f)d)c)c)b(`'_'_(`&^(`&\&]'^&[%Z%Z#V#V S{NQ]K2J1\T}P!T$Y&\&\&\(`'^'^(_&^'_(a(b)b)c*e,h+f*f*g*g,j+i,j-l0r6wJrĥ,H=%:)2"?+>*5$<)>*=*6$@,>*6$>*<(;(6$<);'5#8&5#7%5#:'8&4#;(9&;(7$>*>*6$=)=*?+7$?+>*6$<)<);(4"=*<)3#9'6%5%,!,@|5u/k+g*e+f)c)c*d(a)b'_'^(`(`'^&\'_&\%Z%Z#W"U T}PQ[J1K2]UR"V$X'^'_%['^)`&^'_'_(`)b*c)c+f*e*e+f,j,k+i*h,j-k/o4x;xdžRu4%<)>*:';(A,@,5#B->+<)9&=*>+5#;(6$5$2!1!3#/3"/ 1!3"4"8%1 8&6%8&:&;(<*4#@,?+:(:'@,>+4">+<)9'9&<);).1!*>iF4p/m+h+f,g*d(c)c*d*d(a(`'_)a)a&\&]'^%Z%Y$X#V!U~RR\K2K2]S S$Y%Y%[(_'^%]'^(a(`(a'`(a)d*d,g+g+g+i+h,j,j+i,j/n/q8wJj)$ /:(<)7$A->*8$@+>*>)8$B->*5#:'5$3#/0!* ), )* (++ )0!,1!/4#3"1!;(7%8&6$>*;(4#?+=)<)3"?+<(3"9'3#. ,0 ?,A,=(:&A,D/5#A-B,<(:&:'8& -/ *, ( "   ')(+'+ ) ,-.2"/6%6$7%5$:'=*4"@+=*:'6%=):( +0"AjP?z1r-k+h+i+h*e,h+f)c(c)b)c)b(a(`)b&]&\&\&[&[#W!U}PT^K2J0^ WR#W&\(_&](`'`'`(`)b(a)d+e)d+f,i+i+i,j-l-l,k,k.m.p6w@|f7YL =+?+=*7%D.B,8%A,@,A,9%A,:(4"2"+,   ')*'+ (..3"3"2!8&8%9'6$=*:(5#7%. 7+TH9w/p.l+h+i*g+h+g*f*e,g(b(b)c*c'_(`'^&]&\&]%Y$Y#W~QT!`K2K3bW#W#X$Z'^(`'`'`)b)b,f*d)c*f*e*g,j,j*h+i,j,j,j-l/o1t;yKa#3"@,6#E.B.;(=)D.D/7$D/B-=)6$1!.  ;0:v_IyONRQNJ|An8t^*\H?0 "',( *,-3"07&6$6%5#6%4#,z1t/n-m,k,k*h,j*h*f+g+f,g)c(a)b)a(`'_'_'_)a&]$X#W RT_K2K2aW#V$Z%[&](`)b)b)b*d*e+f)d)e*f*h+i+i-k-l+i-l/o-l0q3w?zTS3#>*@+B,:'B-B-<'F.D-B-:&>*5#/! Hu][ĞWTPPQQTVYÜWUSJ}?h/`N;, %)(, )/ /3"1!./ 0&SG;z2u.m.m.l-l,j+i+h*f+g+f+g*e(b(a)b*d(a(`(`(_'_$Y"VSU^J1J2]W!T#Y$[&^(`)b)c*d)d+f*f*f*e*h*g,k-l-k-l-l.m/p.m/q5y@{YGm<*?+7$D.C->)>)E/G0<&E/?*9'1!,!U\ǡPJGECADADGGHLPSUXTODq0eP1' !)+ ( ++ (, >|eUB}6x0t.m-m.n-l,j,j,k+h)e*f)d)d(b(a)b)b)b(a(`(`'^%["W SU`K2J2a X T$Z%]&^(`)c*d)c(c*e*e+f*g*g+i-k,j-l/o.n.n0q/q.q7yB~_=lZ4#@+B,A+:&F/C-;'F/E.B,6#;),Q\ƠKG@==:8::8;>?BCBEILQUVVL<{c$K< ") # #  RL>|2v1s/p-l-l-m-l-l-k*g+h+h*e*e)d(c(b*d)b(`'_'_&]&\#XSUaK3K2 dW"W$[%](`'_)b)b*d,h+f,h+h*h+i.l,j-k,k.n.n.n/p/p1u:|D_2XJ=+D.8$F0E/@*@*F/H1;&F.A,;)96754~55777:9:9>=BBDHKSWWQ?j%L<'8r[RD9z0t0q/o/p/p-l/o-l,k*h,j+h+h*e)d)d'a)c(a)b*c(`)`&]#X!T!Y`K2L5!f!X#X%]%^(`'`(a)c+f+f+g+h*g*h,j.n.m.n.m.m/o/q/q0s2w;|G]'G;(4#C-D.E.>(G0G/=(G/F.D-9%5$ $[TG?:8656666777675598:;;?>BFLQXœWN8s]3'KJ<}5y1u/q/q0r/p/o.m.n,j+i.l+i+i+h)e*e(b(b)b)b)a(a(`%\#X!T#Z dL3K3cX$Z%\&^(a)c)c)c,g+g+h*g+h-k,k-l/n0p.n.n0r0r.q0s4y9~F_$>4(?+E/;&J2H1C,C+J2J2>&H1B- 2[LbǣME<8876887787766667676679:6|4y2v/q/r0s/p/o-m-l-l,k,j+i-j+h)f*f*e*d(b*d)b(a'^%]%["VXdL5K3d Z#Z$\)a)c*d+e*e*f*f*f,j-l-l-m-m0p0p.n/q0r0s/r1t4y4.9&D.F/H/@*K2I1B*I1H0E.<(I}jdʧJC988788877876868877768677789:ADEHJG?6}5{3x1u/s0s0r/q.o/p-l/o/o-l,j,j*h,j+g+g+f*d)c(a'`)b(`%\#X Z eL3L3!f Y"Y%](b*c+e*e,h*f)f+i-k-l-m-l-m/n/o.o/p0r0t0s3w4z;Ha#:1,A,H0='J2I1F.E-K2M4B)H0C.SxdʧI?887788879988878887767776865}7:;<;986~5z3x3w2v0s2v1t/r/q0q-m/o.n.m,j+i*h,i+i+h*e-h)c(a)b)b(`%]"WWbK3L5gX#Y%^(a)c,g+f+f+h,j+i+j,j-l.m/o.n/p/q0s/r0t0t2v4z;Ib$<208%F.F/G/A)L3J2B*K2J1F.=( QyaɦG>:888988899899798867777877675~5~5~66~6~5|5{4z3y2v2v1u0t0t/r0r0r.n0p/o.n+i,j,j+i+h,i+g+f*e*d)b(`&^$\#WZbL5L3 f!["X&_(b)d)d*f*g+h.l-k-k,j-k/o/o/p0r0s1t0s1u3w3x4z>Ja$;1+C-H0='I2L3G/E-M4M4A(I2G1Px_ɥG@:99999999899988987788777679754}4}6~5}5|5|3|3z2w3w3x2w0s1t1t0r.p/o/o.m-k+i-k,j+i*g*f*e*f,g+d)b%^$[#ZZ dL5K3 f"]"Y&^)d*e)e,i,k*h,k-l,j+j-l.o/p/q0s1u0s/r1u4y4z5{>Ia$=21:&H0J1I0B+N5M4C+O5M3H0?*Py_ɦG@:9::989<;999989889789879977753|4}5~4}4}5|5}2y2v2x4y4y1u0t0s0r.o/p.o.n.m+j,j-k,j*h,j,h)e+f*e(b%^#\"Y YdL3K3 f!_"Z$])c*f+g+h+i-k+j,k,j-m-k.o0q0r0s/r0s1u1t3x3x5}?Kb#;1.D.J2A)L4K3H0G/O6Q7C*M4G1 Qxa˨G?;;;99:9;:;;:;;999:9899988877653}5~65~5}3z3y3z1w2x2w2v2v1t0s0s.p.o/o0p-l+j-k,k,j+i+g+g)d)d(a'`$\"Y!] eL3L5 g"]#[%](b)e,h+h+i,j,j+j-l/p-m.n/q/r0s0s1v2w2v1v3x5}?Jb$>32>(I0J1K2C+N5M4H.O4M3J2?+QxcͪI@;:::;;:9::;:;<:<:::8889888767754~55~4}4{5|4{3y2w2w2v2w0t1t1t/r0r/p.n.m,j,j,j-k+i*h+g)d(c(c)b$\#Y[eL5L3i!`#[&`'b*f+h-k,j,j,j-m.n.n/p-o0s1u1u1u1t3x3y2x3y7>Kc#;12E/L4C+N5O4I0I0Q6T9F,M4H1Pxb̪K?;=;;:<<::;:;<9;;<;9:999998787774}6755~3{6|4|2x2w3x2v2v1v/r0s0s0r0q.m.m,j,k-k-k+i*g*e*e*e(a&^"W!] iL3L3 j!_#\(c(d*g+h+i+h,j-k.n/p/p/p/p0s2v1t3w3w1v3x2y3z7@Lb$>33 <'K3M4K2G-R8P5G-R7N4K2B+R{dϭKB;<;<;:;;:<;;;;:;<;:<:;:98989987678565~4{4{3z2x3y2w2v1u1u/r0s0r/q.n0p-l-l,k,j*g*g*f+f+f)b%^#Z"^ iL3L3 h"_&_'b(d+i,j+i+i,i,j.m.n0q/q0s0s0t2w2w2v3y3z4{4{7?Lc#;11F0M4B)R8Q7J1M2U9T:E,N5J2QydϭLC<;;;;<<<;<;;<<::;:<;9<;:9888887866754}55}4{2z2x2w1v2w2w0t/r0r/p0r/o-k/n.m+j*h*f)e*e*e)c&_$\!] fL3L3 i"a&_(c(d*g+i-l,k.m.n.n.n.o0r0s2v1t1u1u3x3y3z4{4|9BLb$>35!>(K3P5Q6I/S8S7J0T9Q7O5E-QybάMB><<;<<<<<==<;<<;;<<;::;;:;:887889665~55~5}5|3y3{3y2w1u2v1u/r/r0r0r/p-l-l-l-l,j,j+h*f)d'b'`$\"` gL3L3j"b'_'b)e,j,j,k,k0p/o0q/q/p1t1u1u2v2v2v2w3y2y4{4}:CNd#:02H0P6H-T9R8N3O4U:V;I.T:M6Q{cЮOD==<<<=<==?>>=;<<<<<;:<;;:=;:989988654~5~4|4|4{5}3z3y2x0t1t0t/s1u0r.o.m/o.m-k,j.l+i,i*f(c(b%]!^ iL5L3j!a$]'b*f+h,j,k-k.n.m/p/p/q0s0t0t0t1u3y2x2x4{5~5~9BNb$>38#A*O4R5P5J/T9T8N2U:S8Q7E.Q{dЮNC<<<==<=>=>>><=>==<;;;;;;:;:;9998876754}5~55}5|3{3z2w2v3w1u0t0s/q/p.n.n.m-l,j,k*h+h*f)d'`$\"] fL3K3l"a'`(b+i*h+h,j,k.n0q/p0s/r/r0t2v2w2w2w2y4|4|5}5~8ALc$>24J2S8H-W:T9R7O4U9W<J/S9O7R{eѰLA>>=<=>=>==><<>>>>=><<;:::;<:<9888877665~5~4}4{4{2x2w3x3w2v1u0s1t/p0r.n-k,k+i,k-j+h,i)d&`#\"_ hL3K3k!c'a)e+i*h,k.m.m/o/q0r0r0t1t2v4y4y2w2y3z4z5}5}59BNd$>39$B*Q7T8S8L1[>U9M1X<W;S8G/ Q|gҰOD@?=>>=>>>>>?>=>>>>>>=;;<;<;;;<99:9777655~5}4|4{4{2x2w3x3w2v1u1t0r0r.n.n.n-l-k,j,j+h+f'b&^"ajL3L3j"b'a)e)f,j-m-m.m0q/p0r1t0t0t3w3x3w3y4{5|4|4}5~6:AOgĤ#>23L3R8I.W<W<Q6Q7[>[?M1W<Q8S{hӱOF?>?@??>?@@>@?>=>=>>=<==<;<;;<;::98888665564{5}3{2w2v2w1u0t1t0s.p/p0p.n-l.m,j,j+i*f'a%^!` hL3K3l"c%_(d*g,k.m/n-l/o/q0r0s0t0t3w2w2w2x3z6}5~4669@Ngƥ$D69#C+R7T9T9M2X=Y=Q4Z=W<U:J2T|hӱND?>>?@@@@@@>?@A>>?>====>=;;;;;;:;98889776553{4z4}3{2x2v2w1u0s/q/q/q/p/o,k-k-k+i+i)f'a%^"` hL3K3l"c'a(d*h-k.m-l/p/p/p/q/r1u3w2v2w3y3{4z4{4}5688COfĤ$@36 M4V;K0Z>Y>T9U9]@\?P4Y=Q8R{hԲOD??@???@@A>@@?@?>???==>=<=<;::;<::997767674}5~4|3{3{3x2v2w1u1u/r/q0q/p.m.n-l,j+i*g*g)d$]!`jK3L3k"c'a)f+i,j-l.n0q0q/q.q/r1t3x3w3x3z4|5|64}6769CPgŦ$B5 ;%D,R7V:X<R5[?Z>Q5\>\?W<J2!R|hԳPE@@@@A?AA?@A@A???>?@?>===>=<::;<;;:9997775~5~65~5|2y2y2v1u2v1u0t0r/p.o/o/o.m,j+i)g*f)e%^!`kL3L3k a&`)f*h.n-l.n0r0q0r0t/r1t1u1v2x4}5{6}55557:EPgť$A47!N5U;L1Z>[>V:Y;]@`BT7[?S: R{hԳOC@AAAAA@@@AAA@@@@?>??>?=>>=<<:;:9:<9998766665~5|4{3z3x2v0t1t1t/r0s/o/o0p.m-k,k)f)f'b$\!`lK3K3l"d%_(d,j.m.m.m0r/q/q0s/s0s2v3x2x4{5|655668:CPgť$C5 :%F-U:X<V:P3`A^@T6]?^@X<J2% R|fԳNF@AABAAAABAAAA@@A@@???@>=?=<<;::;:;:998778654}5}4z3y3y3w3w0t0s0t0s/q.n0p.m,k,k*g)e(c%^!`kL3L3!n"f&`)f+i/o0p-m/p0s/q/r0s1t2w3x2y5{5|4}57877;DQhƧ#A38!P6Y=P3[?^@X:Z<aDaBS5]AU;Q{fյPGABBBBCCBABBBCA@@AA?@?AA=>><<;:;;:;:99998675564{2y2x3y4y1u0t/s1t0s.n.n/o,j,j*h)e(d&`!akL3K3l!b'b+i+j-k/p/o.o/p0s0s1t0t2v2x3z5|5}5~567779FPgƦ$D6 ='G.U:X<[>X9`C]@X:_A]?Y>N5$WhֶNFBCBBBBCBBBCABABA@@AB@?@>===<<:;;;<;:99977664~5~4{4{3y2w1v2v2w0s/r0s/p-l-l-m,k+j)e'b%_!akK3K3k!c&a*g,j-l.n1s.p.q/r0s1v1u2w2w4|6}5~5~58787:BQiǧ#A3;$S9X=O3^A_AZ=Y<bDeGU7]AV=Xh׹OECCBBBDDDBBBBBACBA@@A@??A>==<=;;:<<;9999976555~4{6}3{3w2v1u1v0t/r0q1s.n-l-l,j,j)f(d$^"dlK3K2m$g%`)f,k.n.m/p/p/q/r0t0t2w3y2x4{7}5}5~67778;CPhƦ$E6 >(H/X<^@Z>U8bCbCW:bD`B\?N5( T~hغQ¤GCCCBCDDCBCBCBCBBBC?@@@??>>==<<<:;<;:99977755~4}5~5|3z3x4z1u1t1u1t/q0q.n-m-k-l*h*h)e%^!clK3L3!n$f)d)g+h.m/o/p/q0r0t2x2v1v3y2y4{5}54}56768cDeGW9aCX>%YhغP¤HCDDBBCCBBCDDBDBBBBCA?@@?>?>?=<<;;<;9998777764}64|3z3z3y4y2v0s0t0r/q.o.n.m0p,k)f)e%_ bkK3K3!m"f(d*g+i-l/o0r0q0s1u1v3x2v2w2y4{5}4}675787=GRhǦ$F6 >(H.Z>^@`AV9bDaBY:eGbD]@S7)XhغP¤IDCCDEBDDCEDDCCCBCBCA??@A???>><<;;;:;<89968775~4~4|3y3z3y4y2v/s/r0r0s/p/o/n.n-l*g(c%` blK3K3l!d&a)f+i-k/o/q0r0t0t2v2w2x2w3y3z5~6666788S5`CaC[=\=dFfGX:bE[?"XjڼP¤J£CDEDEDDEDDEDDDECABAA@?@A@??>==<<:;<;:98977765~4~6~3z1w3x2v1u0s/r0r/r/q/p.m.n,k+h(c%_!bkK3K2m e&a*g+j,k.n0q0r/s0s1u2v3x3x2y4{5~4}677799:FQhǧ%F7 A*I0[>^@^?X:cDaCY;eFcE_AR6( VhٻP¥FBBACCCBCCBBCBCC@AA@@?>>??>=====<;<:;<:998666565~2y2y3y1v1v0t/r/r0r/q.o-l-l,j*h(d$^!bkL3K2m!e'c)f+i.m-l/q/q0s2w1u4x3x2x3z7}5}5~5~77778;GPfȧ#C4 <&S9_AT5cEcD]?]>dEgIY:cD^C#_qܿUǪRƨOŧM¤NĦMåNħNĦNĦNĦNĦOŨOƨMåOŧNĦMåJK£JIGFECEAAB??<;::98898787786655}3y4{3x3x1u0t0s.p/q.p/o0q.m.m+i(d%_#ekK3K2!n!e(c*h+i.m.m.o/r1t1u3w3x2w2x3y6}4~4~3~4678;AKWsʭ*G:>'K0^A_AbCZ<cEdF[<dEdEbCU:(q_ϱ\Ͱ[̯[̮ZˮYʭYʭ[ˮZˮZˮ[̯[ͰZ˯ZˮYɭZˮXȫWǫZ˭XȫWǫWǩVĥVĦTäUãS¢S£SSQMLLIGFD@?<:97653}4~2{2y3}2y3x3w1t1t/q/p/p/p.n.n-l*h(d&_#fnK2L3 m"d)e*h,j.n/p/p.p0t/t/u0t1v4{5|9=?ACGIIMSYŸeɦҹ1F=<#U:^AU7fGcE^@_@fHhJZ<fH^A#mcѴ\αYʭYˮY̰YʭY˭Y̰Y̰YˮY̯Y̱YˮYˮXɬWȫXɬWȫWɫVȫXɬVǪUŦVŧUŧUŦUãUãU¢U¢TTTSRTSQOQPLKJFDA>;8~5|2x3y0u.s/s/r.q.o0r/o.m,j*h)f&a!dmK3M5#n"d'c(e,l-n.p0r3t6w8z<|BFGIKMMMMNNNORZŸbɦԺ2H>A)N2]@aBaBY;hJeF\>gHfGbCT8%odҵ^гYˮZ̰ZͱYˮZ̰ZͰZͰZ̰[ͰZͰZ̯Y˭Z̯XʬZ̯Z̯YʭWɫXɬVǪXɬWǪVƨVƨVĥUäU¢TUãU¢U¡SRTROPPPNNNNMMMMLIGD@?9{7x4u0q.o,l*i,k+j)f'b!e nK2K2l"e+e0m8t=zA~DHHGJLLKKKKKKLMMNQS[ŸeʧԻ1E<=$V<aCV7cEcE`B`AhJiJ^?dF\A ofҵ^гZ̯Y̯Y̯Z̯Z̰[α\β[ͱ_ѳ]ϲ[ͱZͰ[ͱY˭Z̰Y˯YˮXɬWɫWȫXɫWȫWǪUŧVǫVĥUãUäUäUãU¢SRRRPPQPNQNLLLKLKLIJJKJIFF@|;w8u4r0m*g$_ahK2!S?<1uB)N3_A_@bCZ<gHfG_@gHeGbDW;&odҴ_Ѵ\ͰZ̯[Ͱ[ͱ\β[ͱ\ϲ]ϲ]ϲ]ϲ[α]ϲ\ϲZ̮\α[Ͱ[ͰWȫXɬXʬXɫWȫYʬWǪUŧVťWŦVãUãU¢UTTRRRRPPPONLMMLLLLGHJIHJHHGGF~D}A{=y8r0p.xP8%WBC:z>{C|EFFGHJMKKHKLLLLNONPQRS]ġhͫԻ1E<=$W<`BU6cDeGaC_AgIhJ[<eG`D"oeѴ`ҵ\α\α]ϲ^ϲ^ϲ\β]ϲ_ҵ`ҵ\β^г^г]ϲ[Ͱ\Ͱ\ͰZ̯YʭWɫYˮYʭWɫVǪWȫWƨVƧVȫWŦVãU¡U¡U¢UTTSSQPRRNOOLLLLLJGKKIHGGGHFFA{?{@|:zE%WC$VAB>{?zC}GGFKLJLKKJLLLLOPOMPQRT]ġg̪ռ1G>@(M3]@aB`A[<hIfH]>hJhIbDW;(ofҵbӶ]ϲ]ϲ^г_ѳ^ϳ\β^гaԷaԶ^г^г^г]ϲZͱ\β[Ͱ[ͱ[ͰYʬY˭Z̯YʭWȫY˭YʬWƧVƩWŧVĤUãUãU¢UUVVRQQQRPPONLMLLLKLLLJLKGHGEB{?{>z9yD%VB%VBF>{?zB|GGJJKLKLKMLMNNNMOQPRRU_ƣiάվ1E<=$V;`CX:dEcDbDaChJjK]>gI]A"peҵaӶ_г^г^г]ϲ^г_Ѵ]ϲ`ҵ_Ѵ_Ѵ`ҵ_ѳ_г^г\β\ͱ\α]гZ̯YʬZˮYˮYˮYʬXȫXɬXƦWťWĤWĤU¢UâVãUUSRSRQRRQPPNMMMMLKLLLKIJFGFE~@{?z={D%VB%WBG={@{B{FGKJKLLKLMMMNPOORRRRSU`Ƥjͫ־1H>A)N3_AaBbBX9gHfG^?gIgIcEU9(rgҵ`ӵ^г^г^г^г`Ҵ`ҵ_Ѵ^г_Ѵ_Ҵ`ӵ^г`ҵ`Ҵ]ϲ_ѳ]β\α[αYʭY˭ZˮZ̯XʬXɬXɫXǨXťYŤZƥVĤUãVãVâTTVTSRRRRPQQOPNMMLKLLKJIFFFGB|?{=zF%VB%VBI?}A{EFIKMLLLMLNNLORRRQSSSTYà_ƤlϮ׿/C:>%Y<bDW8dEdF_@_AhJkM\=fH_C%qkշaҵ`ҵaԶ`ҵ`ҵ_гaӶaԶ_Ѵ_ѴaӶ`Ҵ`ҵaӶ]ϲ_Ѵ_Ҵ_Ѵ_ѳ[ͱ[ͰYˮZ̯[Ͱ[ͰY˭XɬXǩXȪYȩZƥYťVãYŤZƥWģW TWUSSSRRSPQPQPMLLLMMKIHIHFD}?z?{J%WB%VBJ?}B{GHKKLLMMNOONORSRSSSSSTYġ`ǥkЯ׿2I>?&N3_AaCbC]>fHfH]?gHfGdFZ=3ujԶdԷ`ӶaԷ`ҵaԷ`ӵ_Ѵ`Ӷ`ҵ`ҵ`Ӷ`ҵ`ҵ_Ѵ`ҵ^г_Ѵ`ӵ_Ѵ\α_Ѵ\ΰ\α[ͰZ̯YʬYʬYʬYʭYʬZɩ\Ǧ\ǥ^ǥ^ǥYĤYƥXàUUTSSSRRRQPQPNOMLLLJKJKJGD}A{>|J%WB&WCIA}FGHLMLMLLMNPPRRRSSSTTUUXá_ȥkЯֿ0F<=#U:`BU7gIfG_@aCiKiJ[<fHcF.vmշhոaӶ`ҵcԷaӵ_ҴbԷbԷbԷaӶaӵ`ҵ`ҴaӶcո`Ѵ_ѳ_Ѵ^г`Ӷ^г[Ͱ^г]ϲZ̮ZˮY˭Yʭ[ˬ]˩aͫcͨ`̨]ʧ_˧`ʧ[ƤXáXàWUTTSSSSRRQOQOMONLLJJKIHEC|?{I%WB&WBJDFHJLMNMOONOPRSSRRSSTUWU[Ƥc˧kѰ־2G>?&L1\@aBcE[=fGeF^@gIfHgH\?;qpعkոeոbӶaӵ`ҵcԷcԷcԷbԷaԶdոdշbԷ`ҵbԷbԷ_Ѵ_Ѵ`ҵaӶ_Ѵ]ϲ]α]ϲ^в]α^г_вcϮfάeϭkаkϭ]Ǥ]ƤYġWWTVUSRSSQQRRPNNNOMNMKJHFC{D}J%WB%WBLFGHKPOONSPQQRTSSSSSSUTVW]ǥc˧mѱ2F>:"T9^AX9gHdE_AaChIjK\>lNhJG$]vlv޾qۼgָdոbԶbԶaӶcԷaԷcԷcԷeոdոeոcԷ_ҵaӶaӶaҵeոcԷ_Ѵ_ѴbԷbӶbӶcҵhոgӴjԴ|ھb˨`ȥ[ŤXŸVVXžWVTRRRRUSPOQPOMRONLJIED~M%WC&XCMEFILNOOOPOQRRSTTSSUTTWYàYá\Ƥc˨mѱؽ5QF8 K1[>_AaBX:gIeG\>fHgHfH[=aDG1rڻkֹcԷbԷeոbԷaԶdոdոcոdոdոeոbԷcԷcԷdԸdԷeոcԷcԷfԷfոfԶhԶlշ}ھEhX"yٻb˧]ǥZĢYġXßWVWTTUUTSRQQPPPNPMNLKHFD~K%WB'XEPFHJONMOOPSSTSSUWWVUUXžXžYáXá\Ƥd̨iϮFg[) S9]@S6fHdFaC^?fGgIZ;jKiKdF2~vݽsۼmٺfոeԸdոeոeոeոdԸeոfոdԸdԸgֹhֹk׹lֹkֹmٺiַnعtٻfw K2#@ (aH)ydͪdͩ]ƤYĢXßWXžUVWVWWTTRSQOONPQOPKHFDL&WC(YFQGJNRPRRRSSTTWWWYXXWWXžYàYġZĢ\ƥc̨jϯQwj J2Y=^@cD[=hIdE]>hIfHhI^@kLbF3 {t޾pڻnٺkغiֹj׹k׹k׹k׹k׹mٺl׹mٹnܻnۺqܼyiu!K7;DO2"fIcEU7H--K=yغeΪ`ɦ[ţXàXŸXžXžXXWXWWVTTRRQRSRRQNJFGO&WC'XEQGKNOQSRSTSVXWWXYXXYß[ÞZÞXžZġ]ƥ_ʦb̧iϯcL5V;R5eEeF_@^@hJhJ[<kMiKdEaD]?(WB~u߾q޼pܻoܻoۻpݼs޽qܼyǿOte; (N,`AX; iKfG\>[=aB\Afͫç]ȥ\ƣ\ŢXžYžXžWXYWWXVSSTSRRRRRPJIGO&WC'XESJJNQRSTRSUVXWWZYYWZÞ^Ơ\Š[Ģ]ƥ]Ǥ_ɦa̧hάtA,R8X<^@Y;eFeF]>fGeFeG^@jKiJ^AQ1S:¹Oh[K4?= D eH#jL]?dFcEbDW:bCaBU7Y<D'9UIy׹hάb̨^Ǥ]ŢXžZž\ğ[ÞZYYYVUTUUTRRRRROKJGO&WC&XCSKLNRTURUTUUVYZZZ[œ\Ğ[Þ[ß[ß]Ƥ]ǥ`ʧ^ǥcͨiέxڻ˲)7#P6M3`BbC^@`AfGgH[<hJfHbDbDjK lN P1@>kXtSl_/[GJ-2:Y9dFY<#lOkM`B`AfGfHV9cDcD_@Z;`A^@M4gͭfΩ`˧]Ġ]š\ğ\Þ]Þ[ZZYZWUVVSTSRRRQOIHR'XC'XESLMPSTTUXWVUWZ]›[\œ]Ğ^ş^Š_ƣ^š_ȥ_ʦ^ǥ_ɦeϩjЯpշ;_RJ3O4X<X9eFcDX:eFgHeG[=hJfG^?iKjK"hKL*M'C3C'V<H,/F"D0I#X7\=X;$mP#mP`BhJhIdEZ<iIgHZ<bDaB^?V8eF`AT6\>X<;CYOuָiϭaʦ^Ǥ_Ǥ^ơ]Ơ[Þ\ZZ[[ZXVUUWVSRRRQKJT(XE'XETKMRSWVVXXWYXY[[\œ^Ǡ^ş^Ƣ^Ǥ_ɦ^Ǥ^ǥ_ɦaͧgЪiЭlѲfC/B*U:]?[=_@eFgH[<hJgHcD^@iJiK[<jL oQ!hJ dG!nPkMU7hI!nO fH!hI%qS#oQ^@lNlMcD`AiJjKY;iKgGaA`AfGeGV7aBaB[=V9]?^?J0R: f̬fΩą`˧^Ƣ^ş]ğ]Ğ\Ý[ZZ[X[WWXWVVRRNKJV'XE(XCWMMQVXXWZYXZXY[]ž]Þ^ş^Ơ_Ȧ_Ȥ_Ȥ_Ȧ_ɦa̧a̧cͨgЫmҳxܽӸ1' 1@*K2N4^@aCY;bDfFeE[<iJeF[=fGgHfH`AlMlLaAiJjKhJaAlMjK_AhJgIgH^@jKiJ[=dEfFfG[<fGeF[<aC`A^?T6^@Y<O4U9L2K4Oh_pҲiϬa̧_ȥ^Ƣ^ǣ^ş]Ğ]Ş]]œZY[[YWYXWVSRPLKV(XE*XCYNOSU[[XY\Y[Z[^Þ^ş^ğ`Ɵ_Ǡ_Ȣ_ɥ`˧`˧`˧`˧cΨdͩgѬlճoն^<+E.N5R7\>cDcEX9hIeF`A_@gHiJ[=iJjKdEbDjKmN^?kMiKdEcDjLkL\=iJhIcEcEhIiJY;iJhH^?^?eFaCS5\?W;T9P5N4L3@)?*7'd̩dΨ`ʦ_ɥ`ɤ_Ɵ^ğ]ğ^ş^ğ\[Z]Ù\™XXZWUTRRNLY*XC*XEYMQVWX[YXY\[]›[]Ý^ş_Ɵaȟ`ȡ_ɤ`˧_ʦa̧b̧a̧bͨfϫfϪiԮmմyܾ0OC=+E-N4V:V9`B_@bC[=fHeFZ<eFfFfG`AjJgI`BhHhIgI^?iJiJ^?gHeFgH^>hIeF]?gHcEbD[=bD]?V9\?U8T9J1N4G.B+A,5"5%6)=RKھhϭeΨbͨ_ȣ_ɣ_Ɵ_Ǡ_Ɵ^Ğ]œ]Ý_ş\Z]™ZXYYXVSROMZ+XE*XEZOQUYZZ]ÚYZ\\›^ĝ]Û_Ş^ğaǟaɡ`ʤ`ɣaʥdΨdΨfϩbͨdΩdΨgѬiӮkԱtٹx/ ;'D,L3S8_AT7aCaB_A`BdFhIZ;jKiKdEaBgIkM^?lMgHdEaBiJjKZ;kLhIaC^@dDfGY:aC]?\?R8T8T9H/M4C+C,;'6#6%3%.&LqoԱjѯdΨaʦaʦ`ʤ_ǠaȠ`ǟ^ş^Ğ]Ý^ĝ]›\\^ÚZZYXYTSNO[ *XE*WC\áRQTY\[]\\]™^Ĝ]š^Ş_Ơ_Ɵ`ǟaɢaʣaʤçeϩdΨdΨdΨfϪeϩgϫhѭkְpڶuڸh6';&D-D,T9T7X<T7cE`AY:dFbCdE]?iIfG]=gIgGdEZ=iJdE[=cEcDcCY;cEaBU8]@X;X;N3T8K1E-G1@)=)7$8'2$. (C8]}ϳnճgϬfϪa˦a˦aɢaʣaȠ_Ɵ_ƟaȠ]Ü]Û^ĝ^Ĝ\]˜\[ZZWWTOO\Ġ*WC*YE^ƢRUWX\]\]˜^Ú_Ĝbɠ`Ɵ^ŞaǠ`ǟaɡeˣe̥bˤb̦cͨcͨcͨeϩgϫhЬiҭhѭkׯlرrٷzܾ]2$9(<&G/F-S8U9Z<W;\>aCV8cDcD`B^>cCdEW9cD`B^?^>aC`BW9^BY<X;U8W:S8G/N5H/D-@*=(;'8&8)- 9`Ri׾zݻnӱkϮgЬfϪdΨdͧbʤfͥcʡaȠbɡbȠaȠ_ŝ]Ú^ě^Ú]™\]\]š[WUQP\à*XE+YE^ƢRUXY[]˜^Ù^Ù_Ŝ`ƞaǟaȠ_Ɵ`ǟaǟcʢd̤d̤eΧeϨb̧eϩgЫeϩhѬhҭjկhҮiԮkװnشuں}ݿZ $7(=)<'F/H0P6Q7M3V:T7X<T9Z>[=V9Y>W;[>S7Z?W;T8V;P5R8K2P5I0H0I0='?*;':(6&8(0" )E;VywƬ~ݾuڷnԱmԱiԮfϪgЪeϨeϨb̧cˤcʢaȠcɡbȠaȟ_Ɵ^Ě^Ù^ě_ě]Ù]˜]˜]˜]XTRR\Ġ*XC*XC]ġSTXY\]™_Ù`Ś`Ɲ`ƞaǟaǟbȠaǟbɡbɡf̤fΦeΧfϧfϨfϨhѫfϩgѬiԮiԮiԮjծlٱlذnٳvݻ~ݿj 1#6':';&A+E.F.J2G/M4M4O5O5P5O7I0R7J1K3L3H1I2C,H1A*?*=(8%:'7'7(,!.MBVyt{ܾuںrڷoٳlկiӮiӭfϩfϨfϨeΧeͦdͥgΥcʢ`ǟbɠ`ǟ_Ş^Ü^Ú^ě`ě_Ù^Ù]˜]—\ZURQ_ơ,YE+YE_ǣTTZ[]^ÙaŚaƜ`ƞ`ƞbȠbȟcɠdʡbɠdʢeͥeͦeϨgѩgѩfЩgѫhѭgϬhҭiԮjկkװkװj֯nڴrݸuݹ|߿ӸErc *6'6&6$9'=)8$@*A+@+A+A,C.='B,?*=(;&<(>*6$;*9)7(1# )!:0Cl^d{ɰwۺt۸sܷoٴmٲmٱiԮiҭiӮgЫeϨfϨfϨeΧeΧfΦcɡcɠeˡaǟbȠ`Ǡ_Ŝ_ěaƜ`Ś_ę]˜]\[XRR`Ƣ,YE,YEcɤSWZ\^Ù^Ù`śaśbǜeʠcɟfˡdʡcɠdˢgΥeͥgϧfΦgЩgЩfϩgЫhѫiԮjկiӮkׯkװkװj֯nڳo۵rݸvݺzݽxªGrd  &0"4%9)4&9)9)6&8)8)9)3$7(3%+&2ODMxjfyĬ{wܻtܹrܷqݷnڳlرjծjկiӭhѬhѫgЪgѩhҪfϨgѩgϧgΦcɠgͤcɡdʡbȠbȠbǞ`ę`Ŝ_Ě`ęcƚ_Ø`ę\XUV`ơ+YE,XFeʦVY\\_ę_Ù`ŚbƜcȞdɟeˠeˡcɠdʠf̢fϨgЧgЩgШfШgѩhҪiӫiԭjկjծk֯k֯mٲkװkװoܵo۴pܷr޺u޺y߾|ҹeGna+D:-$*E;?gYStixֽ{x߾wuߺqܷoܵo۴pܵnڳmٲj֯iӮjԮjծiԬiԬiӪhҩhѩgШgѩfͤeˢgϧeˢeˡeˠbȟbȟaśaśaśbƛaŚař_Ø[YVXcɤ,YE,YEcɤV[\]—aścǜcǛcǛeʞdʟeʠdʟeʠgͤgͤgϦhѩhҪgШgШjӪkլiӫiծlׯl֮k֯k֯k֯lرlرmٲnڳqܷpܶpܷsߺxz}иǰrif[|Yz^^fijrƯ̵ؿ~|zxv߼wsq޸oܶo۵pܵnڳmڲn۳n۳kׯj֮lװk֯iӫiԬlլhҩgѩfΧgΦgϦgΥfͣfˡfͤeˠcɟcɟdɞcǜbƚeɞbǜ`ę^—\\WVdȥ,YF-YFdɥX[]bŚdǛdɝeʞdɞeʟdʠdɠgͣhΥhΤiϥgϦhҩiҪgЩiӪjԫjԬiӬkծl֯lׯkׯmٱlװo۳pܶo۴o۴pܶoܵr߸r޹swyz|~}|y{wvurq߹qݷo۵pܷpܷpܷp۶nڳo۴n۳kװlׯlׯlׯjԭjԬjԬiӪfЩiҩfΦhѩiѨhΤgͣgͣfˡg̢fˠeʟeʞdȝcǜaŚ_ębŚař\ZWeʥ,YF,YEf˧XZ]cƛdȜeɞeɞh͢eʟdʟg̡gͤhΥiϤhΥgϦgЧgѩgЩhҪjԬjխjԭnذmׯlׯmذnٱlװoڳo۴pܵoܵpܶoܵq޸r߹rr߹uuty{}}|~~~y}{zwuttssr߹sqݷp۶qܷqܷqܷpܷo۴nٱnٲmٱlװlװmׯlׯjծmװk֯iӫjӪiӪgϧhѩhЧhϥgͤgͣf̡g̢f̡fˡfʟf̠cǜařdƚdƚař]YVcɤ,YE-[FfͨWZ^ØaĚdǜfˠfˠfˠf̡gͣg̢g͢gͤhΥhϦhЧhϦhѩiӪlԪiҪkլk֮l֮mׯmװnٱo۳mذo۴p۵pܶnڲpܶpܷqݷq޸rrrststuwwyxz{|xz{yywxxtwvurߺrssrrrr߹r޸r߸pܶpܶpܶo۵o۴oڴnٱnٱmرnٰkׯlׯk֮lխl֭jӪkԪlԫgϧiҨhЧiЦgͣgͣgͣf̢fˠg͢fˡfʟeɞdɝcƚbƚ_Ø\ZYcɤ,[F.[Ff̧XY`ęcƛdȜeɝfʟfˠg̡iϦhΥhΤg͢gΥiЦiЧjҨkԪlիlլkԫl֭nׯnذlׯoٱoڱnڲnٱnڲp۴pܵo۴o۴qݸr޸q޸qݸr߹r߹rsttrߺsttuuvvtvvusuutsrtsrr߹ssrr߹r߹r߹r߹srqݸo۴o۴pܶp۴o۳o۳oڳoٱmׯmװnذnׯkԫmիlԫkԪhЧiЦiЧhϦgΤg̡hΤhͣg̡fˠfˠeʞeʟfˠeȝdƛ^˜\[Yg̦/[G .XDjΨ\—Z`Øfǝeʟfʟh͢i΢fˠiϤjϤiΣg̢hΤjХjѧjҨkԪm֬kԫjӪmլoٰpڱmدnذnٱoڱnذpڲo۳pܵqܶn۴qݷr߹r߹q޸ssrߺrsrr߻ssstuvsssvvtsttrssssrߺrssr߹srq޸rr߹qݶn۳o۴pܵp۳pڲq۳oܴnٰlׯmدpڱoذlլlԫkԫjөjХjѧjЦiϥjХg͢iΣjϥhΣfˠi͢h͢eɟeʟfȞcƛ_Ø\[Yjͧ/YE  H5kͨ`Ȟ[^×dǜfʠg̡g̡g̡iΣg͢iΣiΣjХhΤjХkҨlӨkԪjҩjӪm֬lԫn׮nدnٰpڱpڱq۳q۲pڲp۳pܵt޸pܵoܵr޹rrrrsssssrsuttssustuuututsstusr߹stssrrqݸr޸pܶqܶo۳p۴qܵp۳p۳nذnذoٰm׮oدn׮m֮m֭lլlիlөkѧjѦjѦkҦiϤg̢iϣhΣi΢h͡g̠g̡eɞeȞdŚcƚ][^Śjͧ I5UUieϥ[^—cƛfɞh͡g̠g̡h͢g͢g̢iϤlҧiϥjЦlҦkөkөkӪm֭m֭mլlիn׮nدpڲoٰp۳rܳp۳rݷqܵqݵrݶp۴qݶq޸srrssr߹sussttttuutsstutuututtsr߸rstrrr߹qݷpܵrݶt޸o۴o۴p۴p۴o۳oٱp۲pڱnدm֬m֭m֬m֮kԪlիmԪkҨlԩkѦjѥjХh͢h͢h͢iΣg̡g̠gˠeɞdƛeƜdǛ^–Zd͢iUUUG[~yܶXbŚcƚfʟg̡j΢h͢h͢h͢jϤkХjХlҦjХlөmիmիmլlԪoدoدm֭n׭pٱoٰpڲrܴoٱq۳rݵs߸t޸rܵrݶqܵs޸tvts߹stutustvvvtuvuuvuuvtuuvustr߸tuvts߸sݷs޸s޷sܶrݶo۳qܴrܴqܴq۲nذq۲pڱn׮m֬n׮mլmլm֭kҨmԩlԩmԪlӨjϤjϤh͢iΣiΣjϤg̡fˠeʟfʟeɞcřaęVwس[}GU ,M;ʇ۾d̡cŚdǜfˠg̡h͢g̡hΣiΣkѦlҦkѦkѦkҧmԩmիmԪn׮m֬mիn׮n׮n׮pٰoٰpڱpڲqܳp۲qܴt޷s޷rݵss޷ttts߹ttvvuutuvuvvuvvuvuvuvtuvutvtuttr޸s߸s߸sts޷rݵqܴqܴrݴq۲rܴq۲nدoٰn׮n֭nخm֬mիlիmԪlҧlӨmԪlҧjФlҦjϣjϤiΣh͢fˠg̠gˠf̠fʟdǜ_–bˠټ+M; Vc\Ǚcřh̡i΢g͡h͡h͢h͡jϣjХkҦkҧmԩlөmԩmիmիmժoخoٯoدnدnدoذoٰqܳuݷrܴqܳsݶrݵt߸s޷qݷtus߹s߸rstuvuvuuvuuvuvuvuuvvuuuuvusuuss߸rݷrݶs޷s޷s޷rݶs޶rܴq۳sݵq۲oذq۲pڱoٰn׮m֬mիmժmիmլlӨlӨlӨkѦmԩkѥi΢kѥkХh͢g̡fˠeʞfɞeȝdƛ[ŗ`V]ɛbțh̡jΣiΣkХkФjϤjϤkХmӨmԩnլmԪmԪmԪn֭n׭n׮oٰnدq۳q۳pڱpٱrܴtݵrܳrܴt޷u߹t߸s޷t޸tutuutuuvvwvvuvwvvvvwvuvvuuvwvttuututt޷sݶrݶt޷tݶv޸rܴq۲pٱq۲pڱoٰoٰn׮oٰo׮mիmԩmիmիlӨlҧmӨmӨkѥjϤjϤjϤjХi͢i΢g̡gɟaŘ\Ǚ ,uڲ`ʝbʝd˞iФi΢jФjФi΢kҧlӨkҧlӨkҧlӨkӨlԪlԪlլm֭oٰoٰpڱoٰm׮oٰpڱp۲s޷r޶p۳pܴr߷s޷r޷q޷ttusrtuttssstsssttutrsssuur߸q߸tsr߷r޶sr޷q߷rݵp۲sܵrܴp۲q۲oٯnخm׮nخm֬m֬mլnخmլmլlԩkѥkҦkѦjХlӧkѥi΢h͡iϣh΢h̡f˟g̠aɜ_ʝtٱ,  oxܵrڰpدqٯpٰqڱqڱrܳrܳr۲rܳs߷r޶s޶tuuvvwvwyyyxyyyzzz{}{|||}}}}|~||}}}}}}}}~}}}z||{z{z{yzxzzyvvvxvuuuttttrݵrݴr޶rݵqܳr۳qٰpدpدpخpخnخp׭x۵n  U(O9r;Ϳr)P;UA I3A\NG`RF`RF`RF`RF`RF`RF`RF`RF`RF^RF^RF^PF^PF^PF^PF^PE^PF^PF^PE^PE^PE^PE^PF^PE`PE^PE`PE`PE^PE`PE`PE`PE`PE`PE`PE`PE`PE`RE`PE`PE`PE`PE`PE`PE`PE`RE`PE`PE`PE`PE`PE`PE`PE`PE`PE`PE`PE`PE`PE`PE`PE`PE`PE`PE`PE`PE`PE^PE^PE^PF`RF^PF^PE^PF^PF^PF^PF^PF^PF^PF^PF^PF`RF^RF^PF`RF^RF`RF`RF`RF`RG`RF`RHaSA^N#J4AUU??//////_` (@ @   %3 'F$J$I$I$I$I$I$I$I$I$I$I $I $I$I #I$I#I$I$I #I #I #I #I$I#I$I$I$I$I $I #I#I$I$I$I$I$I$I$I$I$I$I$I$I$I$J 'F &3~2c 2NI-X7\8[8[8\8\9]9]:]:]9^:^:^:^;^;^;_<_;_<_<_;`<`<`<`<_<`<`<_;_<_;_;_<_;_;^:^:]:^:]: ]9]9 ]9]9\8[8[7Z7[8W6I-2N 3d2% ?'c]9 i@ k@mAnBmAoCpDpCpDqDrFrFrFsFtHtHsGtHuIvJuIvJvKuJvJuJvJvJvJuIuIuItHtHuItIrGsGsGrEqEqDqDpDoCnBnBmAk@k@ k@ j@]9?&c 2!2,]_8#;`< nBlApDrFsGuIvJwKvJwKxKyMxLyMzN{N{O{O|O|P|P}Q}Q~R}Q}Q}Q~R}Q}Q}Q}P|P|P|O{O{O{OzNzNxLxLxKxLvJuIuIuHtHsGrFoCk@ nB_;8";,]]1I$#R3 nCoCuIzM{O}P~Q~QRR S!T!U"U"V"W"V#W$Y$Y$Y$Z$Z$Z$[$[$[$[$[%[$[$[#Y$Y$Z$Y#X#X#W"V"V!U!T!T SRR~Q}P}P|P{OxLtHoC nCQ3!'H9!>5&b>sFvI|O R!T"T!S"V#W$X$X%Z%Z%[%Z&\%[&]'^'_(`'_&^'`(`(a(`)b(a(`'_'`'_'_'_'_'_&]%[&\&\&Z$Y%Y$X$W"V"U!T!T!S SR|OtGsGb>*!16cV8/iCvJyM S"U"U"U"U#W$X$Y%Z&[&\&]']'_'_'_(a)a(a(a(a(b)c)c)c)c)c)c)c)c)b(`)b)a(`'_'^&^'^&\&[%Z%Z%Y$X$W#V"U"U"T S~QyLvIhC0 T9 U8/kFzN|O!T"U"U$W$W$X&[&[&\&\&^'_'_(a(a(a)c*c*c+e,f-h0k/j/j.h-h,g+f+f*e*c)d)c(a)b(`'`(`'_'^&\&[%Z%Y%Y$X#V#V"U!T!S|OyLkE0U8U8/lF}P~Q"U#V#W$W%Y&[&[&\'^'^'_(`)a)a*d*d,g0k:uFPVXWXVSNG>z7t1m.i+f*d)c)c)c(a(`(_'^']&\&[%Y%Z$X$W#V"U!T}Q|OlF/U8U8/mG~QR#V$W%Y%Y%Z&\&\&]'^(`)b)b)c*d,g/k?{VZMo=iV7ZM2UF0RC3TG7ZL9dQAr^NrX][SF:v1m-g+e)c(a(`(`(`'^&\&\&[$Y$X$W$W"UQ}PlG/U8U8/mGQ!T#W$X%Z&\&\'^'^'_(`(a)c)d*e-i4pNU}3YH7'01 0!3"2!1!1"1 1!21":-*Q?;bSOs[ZL;w0k+e)c)b(a'_'_'^']&[$Y$X$X#W R~QmG/T8U8/nHR!T$Y%Z&[&]'^(`(`(b)b*d*e+g,h4qQExe6%1 8&:':':'9':':(:(:':(:':'8&4#1!. 9)-RCGzfZWC~2m,f)b)b(`'_'^&\&[%Z%Y$X!SQmH.T7U8.nHS"V%Y&[&\&](_(a)b)c*d*f*g,i1oKDub/#7&:':':';(;(;(;(;(;(;(<(;(;(;(:(;(:(8&2"07)2YGRxQ6p+e)c)b'`(_'^&\&[%Y#W"TRnH/U8U8.nIT#V&[']'^'^'`(b*d+f*f*g,j.n@~Kt2%8&;(;(<);(<);(;(:'8&8&9&:':';(;(<)<)<(;(:':'8&0 ()RB9s.j*e)c)b(`'_'^&]&[$X!TRoI.U8U9.oJU#X&]'^'_'`(a*d+f+g,i+i-k4tN'J<4#<)=)=)=)=):'6%2".,,.1!2"5#7%8&:(;(;(;(:(:'6% $'ZF;x-k+f*e)c)b(a(`'^&\%Y"UToJ.U9U8.oKV$Y'^'_(`)b)c*e+h+i-k,k.n>|Go.!<)>*>*?*?*<(5$ ) "$, (#   # &-1!4#7%9&:'9&1!/#Bs8w,k+h+g*e)d)b(a'_&]&["VUoK.U9U9.pL!X$Z'_(a)c*e*e*g+i,j,k-l1rG3bO1!?*?+@+A,@+9& *C4=gF|GGDx=k2lV&QA9+$  " )0!3#3" &+]ID1r-l,j+h*g+f)c)a(a(_'^#XVoK.U8T9-pL X$Z'_)c)d*f*f+h,j-l.m/o3uL'N<4"@+A+A,C-?*/"K:NKC@@BEIKJDz8ya&QA/$  ! $* Ct<}/q.m-l,j+h*f)d(b)b(`'_$YVpL.U9U:.qO!Z%\'`)b+f+g+h,k-l.m/o/q7yLG49%B,C-C-D-?*5&G|I;766788:>AFKI)E.G/H0I0:&-WFT=888888887777679:74z2v1u0s/q/o.n,j+i+h+f*d)b&]!ZqN. V;V:.rP"]'`*e+h,j,k-k/o0q0s1t3x:NE4@*G/I0I1J1='-ZGR=999:99988888764}5}5|3z2w3w1t0s/p.n-k,j+i+g+f)c%]![rO/ V;V;.sQ"^&`*f+i,j,k-m/p0s0t1v3x;OF5B+I0J1L2M3>(-[GT>:::::;::98987755~5~4{3y2w2v1t/r/p.m,k,j+i*f)c&^!\sP.V;V:.tR"`'b*g,i,j.n/o/q1u2v2x3y===<;;;;:98755~5}4{2x2v0t0s/o.m-k,j*g(b#_sQ.V;U:-uS$c)e+i-l/o0r0s2v2w3y4{5~>QJ7I/Q6S8S7T9G-.bIXB>=>>>>>>==;;;;:98755~4|3y3w2v1t0q.n-l,j+h(c#`tR.V:U:-uS$c)e-k.m/p0s1t2w3x4{5}6>RL8I0S7T9V:W;I//cJY£C>??@???>>==<;;;:88655}4{2x2v1t/q/p.m-k+i(d#atR.V:V:-uS$d*f-l/o/q/r1u2w3z5|56?SM9K1U9W;X<Y<K0/dJZĥC?@@@@@???>==<:;:98765~4|3y2v1u0r/p.n-k+h)d#atS-V:V:-uT$c*g.m/o0r/s1u2x4|5~57@TN:L2V:Y<[=\>M1.eKYĦCAAAAAA@@??>>=;:::98765}3z3w1u0s/q/o-l+i(d#auS-V:U:-vT$e+h.n/o/r0s1u3y5|577@TO:N4X;[>]?]?N2/fLYŨEBBCBBBAA@@@>=<;;;99765~4{3x2v0t0r.o-l+i(d#buS-V:U9-vT$e+h.n/p/r0t2w3z5}577@TP;O5Z=\?^@_AO40hOZǩECBDCBBBBA@??==;;;99765~5|3y2w1u0r/p-l,j)e#cuT-U:U:-vU%f*h.n/q0s2v2w3z5}568BU Q<Q6]?^?_AaCR61jQ[ǪFCCCCDCCBB@@??><;;:97754}3z3x1u0r/q.n-l)e#cuS-U:U9,vT$e*g.m0q0t2v2x3z5~678BT Q<Q6\>^@`AbCS61kP\ȬGDEDEDDDBB@?@>=<;::98765~3y2w0t/r/q.n-l)e#cuS-U:U9,vT$f*h-m/p0t2v2x4{5~68;FZ!R=S7^@`AaBbDU79mSiϳTȫRǩRƩSǩSǪSȪRǩRƨPĦOĦNLKJHECA?=:965}3z2x1u/r/p/o-l)f$dvT-U9V:-vT%f+i0p2s5w9{=@DFIKUj%TAT8_AaCbDdFU7=oUrպ\ΰZ̯Z˯Z̰ZͰZ̰YˮYʭYʭXɬWǪVƨVŦUãUTRRONKIFC@<9{6w2s0p-l*g#dvT,U9"ZA/!'~^0q;vA~EGIJLLMNPXŸm%UBU9_@bCdEeFU7=oUtֻ]ϲZ̰[ͱ[α]ϲ\α[αZ̯Z̯XɬXɫWȫVƨVĥUãU¢TRQPPNMLLIIGEA}qVvؼ`Ҵ^г_г_Ѵ_Ѵ_Ҵ_Ѵ^г]ϲ[ͰYˮYˮYʬXǩXťWĤVãU TSRRPONMLLKHFC}?~7l3&*bK*bK2&9pBFJLLMNORRST]Ƥq¨%TAV9`AbCdEeGX9@sYyٽbӶ`ӵ`ҵ`ӵ`ҵ`ҵ`ҵ_Ѵ_Ѵ]г[Ͱ[ͰZˮXɫYɪZǦYƤYŤW USSRQPOMLKIIEA9n3&*bK+bK3&:pEHLMNNQRRSTV^ȥqè%TAT7`BbDdEeG\tIMPQRTUWWVXžYġ`ʧr̯/ZEM2_AbDbDdFfG[;np۽h׹fָgָh׹i׺nڼv˸{M}e#[@K/5bMεb˨ZġXžWWWUSQPQPKGaBcDdEeGdE!dI|λfDw]#^AZ<[<_@]?I3prԴ^ȥZĠZžYYWUTSRRMJ=r2&+cL,dM2&@uMQTUVVZ[\Þ]Ġ]ƣ^ȥb˧rֶPt9%U9_AaCcEdEdFdE_AAx__uec\tN~e6pY#aB];]?_?cDbD_A_@]>Q4?hUҹdͩ^ƣ]Š\ZZXVUTRPL@t2&,dM-dM2&BvOSWXXXZ]Ý^Ơ_ǣ_ȥ_ɦcͨmԲk<-G/Y<`AcDdEcDdFeGdDa@_A`@aAbBcEeGeFdEdEcCaB]?[=X;R6>*uqԳ`ʦ^Ƣ]ğ\Ü[ZYXWTPMBv2'-dN/dM2%DwQUZYZ[\›^ş`Ǡ_ɤ`˧a̧cΩiҮvعFve1 M3Z=_AbCbCcDeFfGfHgHfHfGfGeFeFdEcDbC_@\>V:Q6J1A+ *?ZPtбb̧_ɤ_Ơ^ş]Ý\[YXVRPDv2&0dM0cM1%FxSW[[\]Ü^Ğ`Ɵaɢa˥dΨdΨeϩhѬpٶtɭ,NA6#K2V9[>_AaBcDeFdEeFdEdEcDcDaC_@\?X;S7L3E.:& ,*,M@U~kϭdͨaʤaȡ_Ɵ^Ş]Ü]š\ZYTQFx1%0cM0dN1%GzUX\]™_Ŝ`ǟ`ƟaȠdˤdͦdΨeϩgѬiӭkְvݻp)J>.A+M3T8W:Y<\?\>[>[>Z=Y<V:S8O5I0B,8%.(8,:cTaxгsٶiѭeϩc̦cˣbȠaȟ^Ŝ^Ú]™]\VSFx1%0dM0dM1%HzVY]`Ś`ƞbȟbȠcʡeͥfϨfЩgЫhҭiԮk֯mٳyrƫ;fW,".7$?*D-G0H1G0F/C-@+9&4# .*-#%E9>gZ]tƫ|ܽx޼pڴjԮhѫfϨeΧeͥcʡbȠ`ƞ_ě_Ě^Ù]XUHy2%1eN2dO1%K|Y[_ÙaścȞdʠdʡeͤfϧgШgѩhҬjԮk֯kװlٲpܶx}޿hBn_(G:3&-#+!* ,"-#.$6*'F:7YNGue_p|ո}u߻qܶmٲj֯iԭhҫhҩgШfΦẹeˢcɠaƝaśaŚ_ØZXJ{1%1eN2eO1%L|[^—cǛdȝdʟeˡgͣgϥhѩhѩjӫjԭl֯lׯmرnڳo۵qݷu}׻xƭrnloquzɰ׼|wsߺpݷpܶo۴nڲkׯk֯jԭiӫgѨgϧgΥf̣eˡdʟdȝbǛ`ę]ZL|1&2eO3gO2&M}[`ØeȝfˠfˡgͣhΤhϦhѨiҪjԬl֮mׯnٱnٲp۵oܵpݷr߹sux|~}zxutsrq޸qܷpܶoڴnٲmذlׯl֮kԬjӪhѨhЦgͣg̢f̡fʟdȜcƚ^—[L|2&3gP 4fN3&O~]˜aęeɞg̠hͣhΤhΤiЦjөkԫlլnدnذoڱoڲp۴pܵqݷr߹rssstuuuuttssrsrrrq޷o۴p۴p۳nٱmدnدlլkԪjѧiЦhΣhΣg̡gˠeʟdǜ^]—O~4'5fO n_" MxaƜaęgˠh͡h͢iΣjϥkѦkөkԫmլn׮oٰpڲq۳qܵqݶqݶrsssstttttuutttrssr߹qݷqܵp۴p۳oٱoٰn׮m֭lիlӨkҧjХhΣh΢h͡fʟeǜ`×`ĚMw "n_CI{hiĠbǛgˠh͢h͢jХkѦlҨmիmլn׭n׮oٰpڲq۳rݶs޶r޷ttsuutuuuuuuuuuttts޸s޸rݶqܴqܴpڲoٰn׮m֭mիlөlөkѦjϤiΣh͢fˠeɞaƚhžIzgCFp]#8-)eqЩg͡g͡i΢jϤkѦlөlԩmժm׭nخoٰpڱq۳qܴs޶r޷s߹sstuuuuuuuuututtss߸r޷rݶrݵq۳pڱoٰn׮m֬lժlԩkҧkҧjФiϣh͢f˟eʞpϨc"7,)Do[/Ty9u4p/k+f)d)b)b(a(`'_&]&\%[%Z$X#W"V!TRzNhD    iE~P!T$W%Y%Y&\&\'](_)a)b*d+f5qJO}GkAs_=lY=kY@p^BybIoP{QMD~8t/j+e)b(`(`(_&]&\%Z$X$W#W S}PiE    jER"V$X&Z&\'^'_(`)b)c*e-i>zLx0[H;*4#2"3"2"2"3"5$8'B2,SB/8&;(;(;(;(;(9'9&:';';(;(<)<):(8&4#4%*O@9n-i)d(b(`'^&]%Z#VRkG    lHU%['^'_(a)c+f+i,j.mC~.ZH5$=)=)=);(5$ , ' ' ( +0 5#8&:';(;(:'0 =.9r-j*f)d)b(a'^&\#WTlH   lI W&\(`)b)d*f+i,j-l3sEw:+=)?*@+?*5#/!#M=+aM,cN'VED52&' % *1!7%7%+4u[9x,k+h*f*d)b(`'^%ZUlI  mJ!X&])b*d*f*g,k-l.n9z>h3#@+A+C,=)5&=kJECEGE>q3qZ#M<0$ % #=.B{2s-m,k+h*f)c)b(`&\VmI   nL"Z&_)b+f+h,j.m.o/q=8y`7$C-D-E-:&0iSJ:6678:>BFD~6yaG70qY<0r/p-m,j+h)e)c)a&]!YnL  oM"\(a*e+g,j-m/o/q0t>7w_:&F.G/H/:&DrC788877778:@@:~4y1t0r.o.m,j+h+f)c'_"ZnL  oM"\)c+g,j,k.n/q0s2w@8x`<'G/I0J1<(EuB999998887755~5|3x2w1t/q.n,k,i+g*e'`"[nL  pO#^)c+i,j-m.p0s1u2xA9ya>)I1K2M3>)FvC::::::9987655~4{2x2v0s/q.m,k+i*e(a"\pN  qO$`)e,i-k/o0r1u2w3zB9zb?*L3N4O5@*GxE;;;;;;;::88765}3z2x1u0s/p-l,j*f)c#^pN  qP$b*f,k.n/q0t1v3x4|D:{cB+P5Q6R7D,GzF<<==<<<;;:9865~4|3z2w0t0r.n-k+i)d$_pO  rP%c+h-l/p0s1v3x3{5~D:}dD-R7S8U9G-H{G>>>>>>=<;;;9865~4{3x2v0s/p-l,j*f$`qO  rQ%c+i.n/q0t2w3y5}6E;fF.T9V:X<I/I|H?@@@?>>==;;:9765}3z2w0t/q.n,k*f$aqO  rQ%d,j/o/r0t2w4|56FK0I~IAAAA@@??><;::8764{2x1u0r/o-l*f$aqP  rQ%d-k/o/r1t3x5}67F]?M2JJ£BBBBBA@@>=;;;9864}3y2v0s/p-l*g$brP  sR&e,k/p0s1v3y5}67G=iL2\>^@`BP4KKäCCCCCBA@?><;;9865~4z2w0t/p.m+h$crQ  sQ%e,j/q1t2w3z5~67G=iM3]?_@aCR5LLŦDEEEECB@@?=;:98653z2w0s/q.n+i$brQ  sQ%e,k/p1u3x6|8;>OCmN4_A`BcDT6XZͰSǪTȪTȫTȫSǩRŨQĦOMLJGEB?<85|3x0t/q.n+i$drQ  !vU+j5s;z?~CGIKN^ţMtO5`AbDdFT6_bӶZ̯[Ͱ\α[ͰZ̯YˮXɬWȪVƨVäU¢TRPNLJGC@<{7u1n(gtS "1f={EIKKLMNP`ǥMuO5`AcEeFU7_dԷ\α]ϲ^Ѵ^г\α[ͰY˭XʬWȪWƧVãUTRQOMLKKIGB|;y0d"#6jA~GKLLNOQRbɧNvP6`AcDeGU7aeֹ^Ѵ_Ѵ_Ѵ_Ҵ_г]ϲ[ͰZˮYʭXǩXťVãU TRRPOMLKHE@}6i##8lDILMOQRSTd˩OvO5aBcDeGY:fjػaӶaӶaӶaӵ`ҵ_Ѵ^г\αZ̯Yˬ^̫iϯc˪W USRQOMLKHC7j##:mGLOPQSSTWfͫOxM3`BbDeF^?cvbԶbԷcԷcԷbԶbӶbԶdԷnػ~ϸsoaʨWŸVTSRPONKF9l#${b{ưƱybHf-jN^@]>^?]>TZ<K1KudtѲ_ɥ]Š\œ[YWVRM?q$$BsRXZ[\^Ş`ȡ`˦b̧dΩo׵W9'Q6]?aBbDdEfGfHfGfGeGeFcEbC^@X<Q6F.5"$>3kcͨ_Ȣ^ş]Ü\ZXTPBs$$DuTY\^Û_Ş`ǠbˣcͧdΩgЫjկuֶDve6%I0V:\>_AaCaB`B`A^@\>W;P6G/;&2!:-(D-I1I1G0E.?*9&5#5&!C68bSV~nwٸpٴhҬfϨeͦcʢaȟ_Ŝ_Ě^ØZUFu$$HwY^—aƛcɟdʠf̤gϨgѩiӬjծkװlٲqݷzmNq4]M*K>&E9&E9(I<+NA6_OHvgXkwϲ|xrݷmٲjծiӬhҩgϧfͤeˡbȟaƛaŚ]XHw$$Jx\bŚeɞeˠgͣhϥhѩiӪkխlׯmرo۴oܵq޸w}~ڽ}չ~Թؼܿ}yuq޸pܶo۴mٲlׯkծjӫhѨhϦgͣfˡeʞcǛ`Ø[Iw$.#Lz]cǜfˠhͣhΤiЦjөkԫm׮nذoڱp۴pܵq޸rstuwwwvttrrrr߹pܶo۴oڲmذmׯlլjҩiЦhΣg͢gˠeɞaę\Ky.$1!LtaÚdȜh̡h͢jϤkѦlԪlլn׮oٰp۲qܵqݶr޸sssttttuttsssr޸qݶp۴p۳oٱn׮m֭lԪkҧjХiΣh͡fʟcŚ`Kt2! pDo^Fig̡g͡h΢jХkӨlԪm֬n׮oٰp۲qܴr޶s߸ssttuuuuuuttsr޷r޶qܵq۳oڱnخm֬lԪlӨkѦiϣh͢e˟fʟgCn]Fo .UquttѫtԬtծvװvرwڳx۶yݸz޹{߻||}~~~~~~~~}}|||z޹yݷxܶw۵vٲuװu֮tԬsӫtЪsUpu-$! RugEky{{||}}}~~~~~~~~~~~~}}}||{{{xlRuhE $!( @    iB=%!O0r S2 R1 S2 T2 T3 U3 U3 U4U4V4V5V4V4V4 U4 U4 U4 T3 T3 T2 S2 S2 R1 R1O0r>%! iB J/C*`;kAoDqFrGsHtIuJvKwKxLxMyMxMxMxMxLwLwKvJuItHsGqFpEnCkA`:C)I.uK\:^pEzM~Q R!T"V#W#X$Y%[%\%\&]&]&]%\%\%\%Z$Y#X"V"U SR~QyLpE\:^sKffBxyM!T"V$W%Z&[']'_(`(b+e.i0l0k.i,g)c(b(`'_'^&\%Z$Y#V"U RxLfAxeliDx}Q#V$X%Z&\'^(a)b-i-7&6%7&9'>, H6,YF:u^Cq=u/h(a'_&\%Y$W~RiExm pkFxT&['^(`*d*f-k>s$M<7%:(;(:'8&9':':'8&7%>-+VD7g,g(b'_&]%YSkFxo#slHx!W'^(`)c+h,j6t1kT8&>*=)3"3$6'1$-.3"8&8&3$2c-k*e)b(_&[ UlGx"r&wmIx"Y(`*d*g,j-mv>zE899877896|2v0s.o,j+h)c#[nLx({*pNx$_+h-k/p1t3y@~N8I0K1#W@G::;::9765~3y1v0r.m,j*e$]pMx)~*qOx&b,i.n0s2v4|BP:N3O4#[BH<<=<;;:864|3y1t/p-l+g%_pNx*)rPx&c-k/q1u3y5CT<R6S7$_DJ>?>>=<;:864{2w0s.n,i%aqOx*)rQx&d.m0r2v4|6DV>U9X;%bGK@A@@?><:975~3x1t/p,j%bqPx)*sQx'e.n0s2x5~7EY@Y<[>%eILBBBA@?=;:854z1v/q,k%crPx)*sRx'f.o1u3y5~8F[B\>^@&hLOEEEDB@><:863{1v/q-m&crPx)+sRx(g1q5x:>BR!]D^@`B,kO^ƪUɬUɬUɬTǩRŧPNKHD@<7{3t/n'erQx)Eҡ,ax:wDHKMP]#_F_AbC.mQe˯\β]ϳ]ϲ[ͰYʭXȪVťUSQNLIFA}7t*}^xBΜX߱6jxCJLNPS_#_G`AbD0oRhͱ_Ҵ`ҵ_Ҵ^г[ͰYˮXȩZȧXâSROMLHB~6ixWݮ]9lxGMPRSVa#^F_AcD.pSrγcոaԷbԷbԷdոjչsеogYáUSQNLF8kx\ddEdF_׽{پ|ּ|εt`A~d!]BMsf˪YžXURQJ;mxai?qxOVW[]Š^ȥiϭpxgnBsxSZ\^Ğ`ɣb̧hҮaK8R7_AcDdEcDcDbC`AY<L2@+ F5\dͨ_Ơ]Ü[XQBsxntEuxV]˜`ƝbȠdͥfϩhҭpٴ\$O=A,H0L3L3I1E.C.I73aOOxhkѭeΨcʣ`Ǟ^Ě]UEtxszHwxZaƛdʟfͣgШiӫk֯mٲs޹oɫWF|iBsbDvdHlUdpɫvڹt߹mڳjԭhѩfΥeˡcǝ`ęYHwxyyKyw]eʟg͢hϥjҩl֭nذoڳpܶswz{|{yvsq޸o۴nٲmׯkԫiЧhͣfˠdǜ\JywxkMuYbf̠hΣjѦlԪm׭oٱqܴqݶrssttttssr޷qܵp۲nدlիkӨiФh͢eʞaMtYiEq],J6(`H0^*c&\!UoHPrLP$[)d-l.z\=*G3'fN%`IL88((kP-k)b#YqKPtPP&_,j2t+sWA+/x]<:94o3r/o+h&^tOPwSP(d.o4z-x[I03h=;:85}1u-m'bvQPyUP)g0s7/}`Q65nA?=;73z/q(ewSPyUP*i1v90dX;8tGDA>:5}0s)fxTP(_P6s@I:l\>D}ZΰWʭSŧPKE>4q']P;pPHOV@q]?Kg׻dոdϳ`ZRNG:oPAvPPW^ǣJ}Y=.y\WTAo)iNL{]ĠVN@uPH{PX_ŝdͧdģ3qYU;W=W=Y@-hQSd˥^ěVGzPNO_fͣiӪnٲmѯ^Z_hĥoձmرhѨeˠ^M~OS}+g›nϦpԭsزvݸyzyxu۶sױpҫmΥeR|+!i+uMwMyMz¨M{éM|êM|êM{éMz§MyMwMtMi+"django-celery-beat-2.6.0/docs/images/logo.png000066400000000000000000000632121457112420500210230ustar00rootroot00000000000000PNG  IHDR>aiCCPICC ProfilexTkPe:g >hndStCkWZ6!Hm\$~ًo:w> كo{ a"L"4M'S9'^qZ/USO^C+hMJ&G@Ӳylto߫c՚  5"Yi\t։15LsX g8ocግ#f45@ B:K@8i ΁'&.)@ry[:Vͦ#wQ?HBd(B acĪL"JitTy8;(Gx_^[%׎ŷQ麲uan7m QH^eOQu6Su 2%vX ^*l O—ޭˀq,>S%LdB1CZ$M9P 'w\/].r#E|!3>_oa۾d1Zӑz'=~V+cjJtO%mN |-bWO+ o ^ IH.;S]i_s9*p.7U^s.3u |^,<;c=ma>Vt.[՟Ϫ x# ¡_2 pHYs   IDATx nY}sΦ,H#hA aYl(*q$ؘpSq1 %V!$!Ѯhf_w?3~W,&U.v9]y|c/eΕ /Ly#ya|]t>OmQv_%[vgn?Tǟ 4Q8.=y\9 \,._|'2x=- _k^7uONNc_yPcnC/C8y6#w`ĪUT ).B:>>ֶv/^' rnb[\~?,TzȻbpEq7?mwG̞611ٶ Jbᳳڏ;\\w)*m X]2.a 5 by۔W/Y罞\4y0Bt#C?ǂRߑno)L@N]n~W7>_{,Xw^_.]:ڹ~7ͬӫG7ϭj[k0,ǥV4i0D )N)o)&bĢK2jOJP IE2@'{vP'ċ' ߷O [x[Ql1Thz@c=_U Jp#=ip[a[a|00z83b/!UT V^s,,k ֓/ԹПjYx`5)D1CDm7?ꡅJ⑿7Xl|{v?6y+lC,O ݯK Z&U?oxYӟۚ;dN RQ9XP\V2I-AP.zHچm NOjIdDg@K^7h_ *VDg~uۇ*Fe $Me}c3.# $+ޜ{o;^;D]:-4i]_;}%{i0^vRQ2EU~&UѾ;^8dSLy0p]#jlorA{ʷPWIuo$5៏8=ڴGAi.4Bu.OL$1G:iT\xu8sp7Pmjͥ_{uܽ:w|sM1*в^Imè *S~ y 3T0x(ۤQ0q,!wȫ]X4W֓V 1Pv!k ` 4?\#WPy[?. ;hD'iF"? 'omF3 3(#&۩'6oE ]ZsG^ 钥_fy{;nkva]X]) 1z0'Q5WW_ca5^PE3 Y2I_ɂIKUJ裱9*:YpQp2˫vWΔiJ+6:*=؞55z)0dкpHVށvWVt{=7Qjom'Y)P[۷~-}u #y?WxAO G@ڤIf"2 0Qe( 7Z^I\=KcT%[08,Bm{s‰jt Ϯ1Qź7C+"ȹ)l*ƠUNфe/F@ &'~N4}ĭׇډ׏Z "C9'r'sNJBtI6ʋ!\7Q&T):Ӻ& 1 0'oi**$r,1Yp7QI 35eEYFWΠ N^W3> e^5Q!1Ox'/$ jo=R<QSk7*v\s (·HKo v"RKi(@8n(HL87SWޤP*yGHYU:QBnCdmmQQ ʢ0:L~UyPEQfE$AQTYšr:j_WQ`}t:0p3b#"!$4jND.VF! 'I!q/z*`gOGipeou>FOOSON9WP9ަR F)ɳ\l yjz."Ɯ)h`f#PØ.R%o)Nhi^8 r86XApd .M @T1@\1 g1B} Qko4%cn~jMO= XYf[X+Kt^pIa5Gnu>F(&hxh2GaB*nJ0N]akq7CH1kWFAsNr0R)(p*fL(&a Ӷ1Efgε/|?z=}=<Xگv[opk{-=v[a3@FЌcc)c+v)/#VzΛjHdLJ,*?q*TGF F<Ŋ%.dpyy cxd)V!|}֬IM}6m`j 1$(ɨa~3±oﵥ=׷wq:qk1cbZқ&έoOLo uÑo~-寸kKn9Ԏ\̓k|Rh+m}G( *1JI>"rh7 /Q6z8]4[(MW0y(b[P.1S":Cⵋi*7fm1qG (ꐃOdo><|{Ͽ@?]ZᕋE4u1CY`j#й٦ƦQZύŶݦo&~YQOOvkvniwW bC,//6jxLƘ3Zo5,oK$$֜0ւPlx6ø%!`ѝ lsUS𢯑%FD O$P(u . x'8i< ]3*Dr1xWYA[>GN>uګpMclMчs3 b|=MM*8?37Q ܑ2>qҠEi`喚U,_oO;o>R{ -͡x-xfoG(<^:˹1ĥ[͞Ymgu 'P,i(&gkN'K4ekkЋa9vK^~D8۾5W剳…%;Tp% hANRLbsK~+۝"r/K@FbJ BI̕ȖL݅{T N1a$Ub,j8f@(l06mG;,2ܯG.Mea螝i 5,L)_X^o 5m\g,o@f1 ?{<vƐ7F2Qef(+(ivKk ] ϛo`[:{2YTicP|dʔ %Bnj=<d/Qik<:qHeh<Й%I*e%$pG18ȴOFQcqOm7ͽ6M7<=;֦0yz~pOWAGGj (~Fۿ5BejXuJۻw&us0VOvp~^[÷>ok(tcr ̜HD)]Ro{!46>/ﺮ;_׾]>G\=C eYY+]`)SHΥnԾʤG$!H˔́]"G$3aJRB/1cHNvj|:O5t?wMY{!L ͣNfP( Pz 00:^Deh3R2rqឱu h2O TL܄%i _A'_ l;SzEvKŒbq~w?vjX5\ :\L;xp5Ta LG񮽋afTTfp/]`ηq轀 0TJ4 d#9Idz蟲c_嶷Fp/sd б>\f*sqGjNN1Ĺέb6$ k}aj9Zc$8'#| z}߾9Hn#Qsis18|h_{mCv뵍+Rgp 2h߻o&_ 0;;!X@bMz{~T[;v۝׶'O}4ӽuV QQ]c.:m5);˺7Ct\*<]pnnys(aN'`++́n61˪5ȐuQb%6 !e ll;{bۭ7m20MsH]5b//ߋB#i`oO=ߞfD;־_n{٭BF'Oj'OjN'x=ǏN=ܞ9gDڛ_1N!LCfX^8QPFDP.+2X\D]:,$YMUm+W0 [vQJ`&0lر3Dia1dx{hS>PBߺ!ί&k L;&X[kj{SЍsO*pV4=.tiާkbVnϟ񔵅q6l 3W}M{뿶}˷~C?f|{YsejCm^G޸wniվ V'o~?'?nO Ay"icĹdÖ{Pp 3}gPۿpC{^|{?P7~vK&h~诵=Kc𩱩xyA_ Mؤή#mP[ E9|4sQ!#o07kTZ(@cī³VAHT*ATR#l IDATr.p=硆)n)ۼ1\pLJ{=|u{׾=s3=_xmmrTtRm+mgoe{\ @/gթإ)a iCJT[|Hgt V}2˔#B)3+i)1nάlSs#_CNղ$, 'UM'mC,8XY]Cϴ[Y2|8Gu||=wͶF{sJ Yw9Uyo 9r:\ɾo?19b5D o1[#G'>Llomox&Mo~wcǟ3sc rPqgl!Ł$Q%eS pJlIu3%i%> #pd(m(=b(O vC⭓qaPvxiwi>^/zkip=qAfs THIhH:I# @URXskx=r0$:P8.Ȕge86 ͺC.(vU(ߛ9y*@pUgLsgBAX pm?b/q"W<)d=St_;&Rq$|Xs=Spk] -dڦzCBƩAt4D(0#;{ UEf0 ‹CLM. +R!Oڔ2q1<:MvYZZ͍ܱ 3K7dw:"thdPY;.eq'aNǮ0) 'BC K1S`#m\;Jũ}WlS Lm+E1udvw&)o#)Nb2q48t)dAQfxs~l)L >,,.9'lKLB,Y w\~vpQqHʵ+]J# *;a6t1(ҹ;z3JB*c}Б,\J1m`(Stt#+d8Y|9;yؚPgn9 }r.G!+wRdsxląSpLw!2pQe'h ǔ6Jq3 G̃%-4.Њl u|#|QεЌAJ1*gQ[+R;bڨ4έ>V׭(F3ӳ-`А0k=(f< h'1t߾}w~ag:˫; 0 0j*v|su'Vb٨4WQ 1&X[7-gh.cՓ,*4oʍ /2$#xz>\_ZYv nteV k\QGè~|P7y_ɠri6f]yT]qn!,Mi7 JksY@A990ƾ5 H\Y fr7\OOg,`*u:sw{X T8,An*9& r8?!\<E2^f|@-kr%ixu d)s Ù 爇V7D+R] 1I/" ՚\PǹΧg"k^k(CK`B3_Vn+QR!Pn%K*h i.謲9\ı7>#%n6pΜ+`[k'=VyS!QF"9C2Obnu8ݝ+RW! [2\B)Dj4 9WҨg0zw^4H[rguQFZFA$'_b`Q삋h?Ȭc4-#~PeQgh'bz._`{ɽӷGNlY@y싁{X+ og=WXH=Ti8%+u#\2$)O 5U8xsS 1fՊ957yfxW..5P4YEpKdT EG]̌MN:S nCCsn\ek#}o[#k 3HȢIFah_yJ_4 hayK^<֝ђaxG*7YYӹ^/X]*eDxv*kcEʫ1:H(,`6sP2d# k2hr[?DkCIt"LFWXf \`[}VRM= Z]8RE EK4HBq/pV34,j`|p6pr RL35œXhR!_VHc5e|1uAG\W(b9_k* Jz@$M!*ti-(8 c0c9/%Xę8ZS @_ GQ .4m%x@:wSiX!; qx*6]]{cig@#gq>S5*C/4w}N U2'[=8+;ɐtۑ3w!=lJNaDNi+ PTQr02Ɉ .#/G4rI`]̷#*)hpdE9J7Dýa[]MdDy1TZw>]]du(Q27{Hz/ V|oM`1h+Da*"?yK#Z^' 9 jwG6g/:4:F]9 ,\9ri!F`NgrG@6VAr (y25huM6 \]5KC h}@GU)\"LzM|< Gc?ܢWKdOd ;0TXy՟,4#BuKR7aW6OjXz\TxJ^+lb8L# - ~#7D6SWaxyIW s[!!BaY*'^c5_,fs iX8U_ʠ]/֝c A5Kp<-*Q˸Dx([~T~)鍥οP6c&ݨ6xuDl/M=OEMC'KM1ͯeiYpH Τ¶gzµ]yʩV%R}rz+OGpKe$H n@u:<x *W{!H/?\IHntQ k]aM#p`(Q+=ԆJT`È( #0,@K]ؾBvGnsЧ(R0- z ' S:XǴ I8eevپIS8]Q"Oo%\X[ #b22Ls` x{lQ_6daR&`ӿɐzqXUPUi;8yU!+%0TYb1 B?@JP-{K)NASa]:-zS6bԩY6l+ ay;$dӦpH GV.z5 3O"jp({'wj")QNs}+@3d"A&h\ %Xy ֺ/(0ݍ!3<)Pp*Vt 0 ݓpD +]$AeS>o22/ Ag9*0? penEP.]F\zMo_rQR(.qR_WF++@H04xHM*o2v$ -> ̚텓Oέ+`Igdb1Hÿ ́i#(h?B)m@l𬁾ϹBʂB2 vyœK,3 BYu~dmfFRu l']rR鑿0"A/hg!կF $YM(-AI_/wU:>]!Z"|_Ԫ(Q-Yg :u !^~_ 1=t%Pap:чlC),~--4{ 9F N@ΰ ~IQH5#RK^N5N*zt_fs-5IVMYhXB,u^ Ma67)T/u;:ċ3c2  %!DlWio.f|F~"n*l^E]FA6W"G.}Q̗d}ֲ4N][J# @o#LedN|PAH`2f GZHHC& ̟lVqsqƟ/29"{4W֌CL gZ^TJ # "-1$#4ɖ/^]jx>QqNE}k44OAeN<ܾ'?h{ "_z'U~jI ĝ#vdJ(:2+S!Z\C)]UH0pgHVRW{Tnժug%);aC%6`%~8n߁vsxaC[p̰'P{> o=|}o_-2PtiE;tt޾+9 R^fpNT|ut \wkU8Kg)=־gg?L6ÏSNQv?śCna69 IT)vCf8~yq+99KQiM*^`a "z?}ɗ^_b2"߰6/KVgސ {d?su9~=g*B o n|վ݇<ܮe;oLM͵1~ySLJu b#>6Z \*ړ?sZZ5, .Zl0~W~ud#oDu_nGYZ嗖wK;k l; xəW8Hjh6OxtvC,{VPocӽ3 AsL@0 u1>JW4'Q 6K?3`x;3K,+GJo7; yp3guA3'1~Ez6u慬E8JF6ůj{fc?vێ΂!3@-/ EI"櫢AuFEIwxH?$O#C_dL hfqQ"f@(1(`rkhh6&_%045ܻHߟ]E:,Rv(KL fN_oC_n0#V;5ZQEc*e3'۱gηg=yCZ`qmF)+Ǯ=iZwT=n67V;䒧*vMjSc#I9NPFMJ黀3hGyX:Gq*p%sS+q2Ṗ>oܮvíW<@}o]`Пs\>-^m-7%^wӾp'iLX{O]pζ<۞vy^?A[3s" $ӾUJNoyf]<^yr LjcֈL/B2=Me(&zkX Z=Q}|W0"4Ó+d&|wu V!H4A}ht+/%{&1ƥȍS5okwM_2C#CI9 㥯iX|^ nt~2n߇)DzCOr-[gl'$1m| FpToqmA,co^`Ԏ:ef<"(E `y@ՉR^a!!8QXNnN[_ov9|>]?a? Q||x++Ƨ p6ɚ/(}|XX# û@O3ݔw9b%Ҳ F iҳ0AʿpT ?0>πrcTt@mC Hq@3M] o>Ң"wu=G<5>v_̇n?p:}E M<3p& "Hi״?~q/1B [ *P,J/G2v@>hv!5}9d.>$:0ByH?ow* %~Rs_w8t?o? S#5ĥZ,&<FS+< Ҡ:bdeRѯ CB8heV(!2hHsK.: a۾/\MʌU_K.1|]ww#03)L:8&:,b:=)B7}=um񪩶z=g z#nh2Q# *ۼi5М*~q*C38wX\84T?n\)|ϻ!|>!5!Jvj V>*d}zen?v~j#,\]˷O}h59-`;.Rd 0qNzY @CxWOl9֎=E<%+ᄃ}߻CGN=}i\LsuT Dz~rd nVu>TyꦾzK+~4 PpԾB0P7CD7:BMD/Y>a| IȔ׻!SAX"Fp'Omqg펯xuY$=vvy zn"2b7k Ac5&o$uB4!}6x;_پnlv-WŃ(]?Ξh_xYdvϹR x5jP%+eL(2<嘞bDGKipGjjHQWJW0{]#v@L5>UDvUF -5M·>8bPa:'NϬ~x-_l~?N]}W6λTϐ-) e, k癧϶13|Hw;h[np;įc8k+%g1ny_<> _zT gMUK:rPΦ܇q$N:ԡ܍6/T=Qjc̠pНD.!罈\|t l[??1C#@u˺ }uv=ϵps?G=g>a4rKsI>Ǵϙ%Loo\sU;r͡vKrci_[?pblJZVۣGmg~b_WsctcaųD?=BL KN#/ dȜuG`@9Rm" C^J ˕N.ʬLR)@\To(|]41ZI[q\S>^׶7fFx.#cϝ?sr):d>~w`1LuTЏn0Nᅓ'N ,?d RG"^ ]Z4 en0v$ , ZtOAEwWFa G}`WJ A/Rnx=G=BxivapQ+XOEJ< nl b˞M (sOE ^51' nck~18xܬY#ߐ׭^r'hhKR: p'}1UhT*lu5ձ3_)g+xz@eiBNeT ixRH#Ԩ~]B eLjC].`#F01aEy:r[sHQ8RF<:ybYk^(8Qp[s+cn[(^30&x-n5J ^E:e\ hϠ3K9]{XFH 6HZ !x1V8ƺxѭUk Z+XseXjBGC8ɨҭ˵uT|§2r0b'ϐ,z0{?ܭZ&Vx4t~(nxvShUy O Z5 <(ɓ)C{]9 O 2 V26hqّY9H݅L}(Ӷ0JWĶ%jW,#rW(Be ^#BTP/2E\p"2R`0(p GS%Ql@MzM9|hgϝ! R5i=*;y.ZӰQRe()7Н}Wf_/gi Odzn-nSg7mg7X/WT^8ѥw3,l0f|+m$N"/" se\`>Xf*X WzL'e6u0Gq~2 zuڶf2[eMZ*9N%>tK?)TjU~* @WiqxQmO^S,ۗ<5pgϻbnZ~v>hn r}_jq̪ҙ\^7w$ئ?8_\a"B;a 8!Քixj >Sk6~#fٜ;+<Tݠpg&*)(Y. "1ԡM"|ؚ[Xn?O?kz1eҕ @͝99=5/ߺg(ۍ >W-*o\3HGX,+!GUFͷc#:F-N/XB0|O8"(Ca,|οvVશ|Oia7GS0%$|M_$(Oy wȻ0<څWgكGDZr=SHf8ҭ4IDATL}v=.;n[,KH*u׷' S{X+CSۨer$0\%IEі;x+М\MMJ^{C{*p;HSc(8sse~9pͨJ2ڡ%j /SbT&繎,.;ʷ~UkU6szyf艧pG>|qsEH%5mómصly䁯Z7yY\A~1:\\7+XsuA b$6A97?ݡ~u.<7jHGt<W[q庲z F^pj y{cmʹ/ٸoeg>>peK@*Wcw&gvͭG~Zn٬/2MNM+%\*仏,nW 'Y/ZHү){I=:.xt |x4ISY'UC!:~m^TbY@vVW{&VX78nɹ|} E ˧?Mc_5mvcM.X=j˫֗B%@=3`ʩ7mbn K."c ^.8 !J?\ ċ|$?_Lʿx1/_# =!˔PM(%IENDB`django-celery-beat-2.6.0/docs/includes/000077500000000000000000000000001457112420500177125ustar00rootroot00000000000000django-celery-beat-2.6.0/docs/includes/installation.txt000066400000000000000000000016451457112420500231620ustar00rootroot00000000000000Installation ============ You can install django-celery-beat either via the Python Package Index (PyPI) or from source. To install using `pip`,:: $ pip install -U django-celery-beat Downloading and installing from source -------------------------------------- Download the latest version of django-celery-beat from http://pypi.python.org/pypi/django-celery-beat You can install it by doing the following,:: $ tar xvfz django-celery-beat-0.0.0.tar.gz $ cd django-celery-beat-0.0.0 $ python setup.py build # python setup.py install The last command must be executed as a privileged user if you are not currently using a virtualenv. Using the development version ----------------------------- With pip ~~~~~~~~ You can install the latest snapshot of django-celery-beat using the following pip command:: $ pip install https://github.com/celery/django-celery-beat/zipball/master#egg=django-celery-beat django-celery-beat-2.6.0/docs/includes/introduction.txt000066400000000000000000000206121457112420500231750ustar00rootroot00000000000000:Version: 2.6.0 :Web: http://django-celery-beat.readthedocs.io/ :Download: http://pypi.python.org/pypi/django-celery-beat :Source: http://github.com/celery/django-celery-beat :Keywords: django, celery, beat, periodic task, cron, scheduling About ===== This extension enables you to store the periodic task schedule in the database. The periodic tasks can be managed from the Django Admin interface, where you can create, edit and delete periodic tasks and how often they should run. Using the Extension =================== Usage and installation instructions for this extension are available from the :ref:`Celery documentation `. Important Warning about Time Zones ================================== .. warning:: If you change the Django :setting:`TIME_ZONE` setting your periodic task schedule will still be based on the old timezone. To fix that you would have to reset the "last run time" for each periodic task: >>> from django_celery_beat.models import PeriodicTask, PeriodicTasks >>> PeriodicTask.objects.update(last_run_at=None) >>> PeriodicTasks.changed() Note that this will reset the state as if the periodic tasks have never run before. Models ====== - :class:`django_celery_beat.models.PeriodicTask` This model defines a single periodic task to be run. It must be associated with a schedule, which defines how often the task should run. - :class:`django_celery_beat.models.IntervalSchedule` A schedule that runs at a specific interval (e.g. every 5 seconds). - :class:`django_celery_beat.models.CrontabSchedule` A schedule with fields like entries in cron: ``minute hour day-of-week day_of_month month_of_year``. - :class:`django_celery_beat.models.PeriodicTasks` This model is only used as an index to keep track of when the schedule has changed. Whenever you update a :class:`~django_celery_beat.models.PeriodicTask`, a counter in this table is also incremented, which tells the ``celery beat`` service to reload the schedule from the database. If you update periodic tasks in bulk, you will need to update the counter manually: >>> from django_celery_beat.models import PeriodicTasks >>> PeriodicTasks.changed() Example creating interval-based periodic task --------------------------------------------- To create a periodic task executing at an interval you must first create the interval object:: >>> from django_celery_beat.models import PeriodicTask, IntervalSchedule # executes every 10 seconds. >>> schedule, created = IntervalSchedule.objects.get_or_create( ... every=10, ... period=IntervalSchedule.SECONDS, ... ) That's all the fields you need: a period type and the frequency. You can choose between a specific set of periods: - :data:`IntervalSchedule.DAYS ` - :data:`IntervalSchedule.HOURS ` - :data:`IntervalSchedule.MINUTES ` - :data:`IntervalSchedule.SECONDS ` - :data:`IntervalSchedule.MICROSECONDS ` .. note:: If you have multiple periodic tasks executing every 10 seconds, then they should all point to the same schedule object. There's also a "choices tuple" available should you need to present this to the user: >>> IntervalSchedule.PERIOD_CHOICES Now that we have defined the schedule object, we can create the periodic task entry: >>> PeriodicTask.objects.create( ... interval=schedule, # we created this above. ... name='Importing contacts', # simply describes this periodic task. ... task='proj.tasks.import_contacts', # name of task. ... ) Note that this is a very basic example, you can also specify the arguments and keyword arguments used to execute the task, the ``queue`` to send it to [#f1]_, and set an expiry time. Here's an example specifying the arguments, note how JSON serialization is required: >>> import json >>> from datetime import datetime, timedelta >>> PeriodicTask.objects.create( ... interval=schedule, # we created this above. ... name='Importing contacts', # simply describes this periodic task. ... task='proj.tasks.import_contacts', # name of task. ... args=json.dumps(['arg1', 'arg2']), ... kwargs=json.dumps({ ... 'be_careful': True, ... }), ... expires=datetime.utcnow() + timedelta(seconds=30) ... ) .. [#f1] you can also use low-level AMQP routing using the ``exchange`` and ``routing_key`` fields. Example creating crontab-based periodic task -------------------------------------------- A crontab schedule has the fields: ``minute``, ``hour``, ``day_of_week``, ``day_of_month`` and ``month_of_year``, so if you want the equivalent of a ``30 * * * *`` (execute at 30 minutes past the hour every hour) crontab entry you specify: >>> from django_celery_beat.models import CrontabSchedule, PeriodicTask >>> schedule, _ = CrontabSchedule.objects.get_or_create( ... minute='30', ... hour='*', ... day_of_week='*', ... day_of_month='*', ... month_of_year='*', ... ) Then to create a periodic task using this schedule, use the same approach as the interval-based periodic task earlier in this document, but instead of ``interval=schedule``, specify ``crontab=schedule``: >>> PeriodicTask.objects.create( ... crontab=schedule, ... name='Importing contacts', ... task='proj.tasks.import_contacts', ... ) Temporarily disable a periodic task ----------------------------------- You can use the ``enabled`` flag to temporarily disable a periodic task: >>> periodic_task.enabled = False >>> periodic_task.save() Example running periodic tasks ------------------------------ The periodic tasks still need 'workers' to execute them. So make sure the default **Celery** package is installed. (If not installed, please follow the installation instructions here: :github_project:`celery/celery`) Both the worker and beat services need to be running at the same time. 1. Start a Celery worker service (specify your Django project name): .. code-block:: sh $ celery -A [project-name] worker --loglevel=info 2. As a separate process, start the beat service (specify the Django scheduler): .. code-block:: sh $ celery -A [project-name] beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler **OR** you can use the -S (scheduler flag), for more options see ``celery beat --help``): .. code-block:: sh $ celery -A [project-name] beat -l info -S django **OR** you can set the scheduler through Django's settings: .. code-block:: sh CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers:DatabaseScheduler' Also, as an alternative, you can run the two steps above (worker and beat services) with only one command (recommended for **development environment only**): .. code-block:: sh $ celery -A [project-name] worker --beat --scheduler django --loglevel=info 3. Now you can add and manage your periodic tasks from the Django Admin interface. Working with django-celery-results ----------------------------------- Now you can store :attr:`PeriodicTask.name ` to django-celery-results (``TaskResult.periodic_task_name``). Suppose we have two periodic tasks, their schedules are different, but the tasks are the same. +-----------+------------------+------+---------------+ | name | task | args | schedule | +===========+==================+======+===============+ | schedule1 | some.celery.task | (1,) | every hour | | schedule2 | some.celery.task | (2,) | every 2 hours | +-----------+------------------+------+---------------+ Now you can distinguish the source of the task from the results by the ``periodic_task_name`` field. +--------+------------------+--------------------+ | id | task_name | periodic_task_name | +========+==================+====================+ | uuid1 | some.celery.task | schedule1 | | uuid2 | some.celery.task | schedule1 | | uuid3 | some.celery.task | schedule2 | | uuid4 | some.celery.task | schedule2 | +--------+------------------+--------------------+ (more technical details here: :github_pr:`477`, :github_pr:`261`) django-celery-beat-2.6.0/docs/index.rst000066400000000000000000000007721457112420500177530ustar00rootroot00000000000000======================================================================= django-celery-beat - Database-backed Periodic Tasks ======================================================================= .. include:: includes/introduction.txt Contents ======== .. toctree:: :maxdepth: 1 copyright .. toctree:: :maxdepth: 2 reference/index .. toctree:: :maxdepth: 1 changelog glossary Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` django-celery-beat-2.6.0/docs/make.bat000066400000000000000000000161121457112420500175120ustar00rootroot00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. epub3 to make an epub3 echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. xml to make Docutils-native XML files echo. pseudoxml to make pseudoxml-XML files for display purposes echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled echo. coverage to run coverage check of the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) REM Check if sphinx-build is available and fallback to Python version if any %SPHINXBUILD% 1>NUL 2>NUL if errorlevel 9009 goto sphinx_python goto sphinx_ok :sphinx_python set SPHINXBUILD=python -m sphinx.__init__ %SPHINXBUILD% 2> nul if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) :sphinx_ok if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\PROJ.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\PROJ.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "epub3" ( %SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3 if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub3 file is in %BUILDDIR%/epub3. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf cd %~dp0 echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdfja" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf-ja cd %~dp0 echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/django_celery_beat/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/django_celery_beat/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) if "%1" == "coverage" ( %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage if errorlevel 1 exit /b 1 echo. echo.Testing of coverage in the sources finished, look at the ^ results in %BUILDDIR%/coverage/python.txt. goto end ) if "%1" == "xml" ( %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml if errorlevel 1 exit /b 1 echo. echo.Build finished. The XML files are in %BUILDDIR%/xml. goto end ) if "%1" == "pseudoxml" ( %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml if errorlevel 1 exit /b 1 echo. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. goto end ) :end django-celery-beat-2.6.0/docs/reference/000077500000000000000000000000001457112420500200425ustar00rootroot00000000000000django-celery-beat-2.6.0/docs/reference/django-celery-beat.admin.rst000066400000000000000000000004351457112420500253210ustar00rootroot00000000000000===================================================== ``django_celery_beat.admin`` ===================================================== .. contents:: :local: .. currentmodule:: django_celery_beat.admin .. automodule:: django_celery_beat.admin :members: :undoc-members: django-celery-beat-2.6.0/docs/reference/django-celery-beat.clockedschedule.rst000066400000000000000000000004731457112420500273540ustar00rootroot00000000000000===================================================== ``django_celery_beat.clockedschedule`` ===================================================== .. contents:: :local: .. currentmodule:: django_celery_beat.clockedschedule .. automodule:: django_celery_beat.clockedschedule :members: :undoc-members: django-celery-beat-2.6.0/docs/reference/django-celery-beat.models.rst000066400000000000000000000004141457112420500255110ustar00rootroot00000000000000===================================================== ``django_celery_beat.models`` ===================================================== .. contents:: :local: .. currentmodule:: django_celery_beat.models .. automodule:: django_celery_beat.models :members: django-celery-beat-2.6.0/docs/reference/django-celery-beat.querysets.rst000066400000000000000000000004511457112420500262730ustar00rootroot00000000000000===================================================== ``django_celery_beat.querysets`` ===================================================== .. contents:: :local: .. currentmodule:: django_celery_beat.querysets .. automodule:: django_celery_beat.querysets :members: :undoc-members: django-celery-beat-2.6.0/docs/reference/django-celery-beat.rst000066400000000000000000000004131457112420500242260ustar00rootroot00000000000000===================================================== ``django_celery_beat`` ===================================================== .. contents:: :local: .. currentmodule:: django_celery_beat .. automodule:: django_celery_beat :members: :undoc-members: django-celery-beat-2.6.0/docs/reference/django-celery-beat.schedulers.rst000066400000000000000000000004541457112420500263730ustar00rootroot00000000000000===================================================== ``django_celery_beat.schedulers`` ===================================================== .. contents:: :local: .. currentmodule:: django_celery_beat.schedulers .. automodule:: django_celery_beat.schedulers :members: :undoc-members: django-celery-beat-2.6.0/docs/reference/django-celery-beat.signals.rst000066400000000000000000000004431457112420500256700ustar00rootroot00000000000000===================================================== ``django_celery_beat.signals`` ===================================================== .. contents:: :local: .. currentmodule:: django_celery_beat.signals .. automodule:: django_celery_beat.signals :members: :undoc-members: django-celery-beat-2.6.0/docs/reference/django-celery-beat.tzcrontab.rst000066400000000000000000000004511457112420500262350ustar00rootroot00000000000000===================================================== ``django_celery_beat.tzcrontab`` ===================================================== .. contents:: :local: .. currentmodule:: django_celery_beat.tzcrontab .. automodule:: django_celery_beat.tzcrontab :members: :undoc-members: django-celery-beat-2.6.0/docs/reference/django-celery-beat.utils.rst000066400000000000000000000004351457112420500253710ustar00rootroot00000000000000===================================================== ``django_celery_beat.utils`` ===================================================== .. contents:: :local: .. currentmodule:: django_celery_beat.utils .. automodule:: django_celery_beat.utils :members: :undoc-members: django-celery-beat-2.6.0/docs/reference/django-celery-beat.validators.rst000066400000000000000000000004541457112420500264020ustar00rootroot00000000000000===================================================== ``django_celery_beat.validators`` ===================================================== .. contents:: :local: .. currentmodule:: django_celery_beat.validators .. automodule:: django_celery_beat.validators :members: :undoc-members: django-celery-beat-2.6.0/docs/reference/index.rst000066400000000000000000000006731457112420500217110ustar00rootroot00000000000000.. _apiref: =============== API Reference =============== :Release: |version| :Date: |today| .. toctree:: :maxdepth: 1 django-celery-beat django-celery-beat.models django-celery-beat.tzcrontab django-celery-beat.querysets django-celery-beat.schedulers django-celery-beat.admin django-celery-beat.utils django-celery-beat.validators django-celery-beat.clockedschedule django-celery-beat.signals django-celery-beat-2.6.0/docs/templates/000077500000000000000000000000001457112420500201025ustar00rootroot00000000000000django-celery-beat-2.6.0/docs/templates/readme.txt000066400000000000000000000026021457112420500221000ustar00rootroot00000000000000===================================================================== Database-backed Periodic Tasks ===================================================================== |build-status| |coverage| |license| |wheel| |pyversion| |pyimp| .. include:: ../includes/introduction.txt .. include:: ../includes/installation.txt .. |build-status| image:: https://secure.travis-ci.org/celery/django-celery-beat.svg?branch=master :alt: Build status :target: https://travis-ci.org/celery/django-celery-beat .. |coverage| image:: https://codecov.io/github/celery/django-celery-beat/coverage.svg?branch=master :target: https://codecov.io/github/celery/django-celery-beat?branch=master .. |license| image:: https://img.shields.io/pypi/l/django-celery-beat.svg :alt: BSD License :target: https://opensource.org/licenses/BSD-3-Clause .. |wheel| image:: https://img.shields.io/pypi/wheel/django-celery-beat.svg :alt: django-celery-beat can be installed via wheel :target: http://pypi.python.org/pypi/django-celery-beat/ .. |pyversion| image:: https://img.shields.io/pypi/pyversions/django-celery-beat.svg :alt: Supported Python versions. :target: http://pypi.python.org/pypi/django-celery-beat/ .. |pyimp| image:: https://img.shields.io/pypi/implementation/django-celery-beat.svg :alt: Support Python implementations. :target: http://pypi.python.org/pypi/django-celery-beat/ django-celery-beat-2.6.0/issue_template.md000066400000000000000000000006141457112420500205220ustar00rootroot00000000000000### Summary: Include a *brief* description of the problem here, and fill out the version info below. * Celery Version: * Celery-Beat Version: ### Exact steps to reproduce the issue: 1. 2. 3. ### Detailed information Please include more detailed information here, such as relevant information about your system setup, things you did to try and debug the problem, log messages, etc. django-celery-beat-2.6.0/manage.py000077500000000000000000000003721457112420500167630ustar00rootroot00000000000000#!/usr/bin/env python3 import os import sys if __name__ == '__main__': os.environ.setdefault('DJANGO_SETTINGS_MODULE', 't.proj.settings') from django.core.management import execute_from_command_line execute_from_command_line(sys.argv) django-celery-beat-2.6.0/requirements/000077500000000000000000000000001457112420500176775ustar00rootroot00000000000000django-celery-beat-2.6.0/requirements/default.txt000066400000000000000000000003421457112420500220630ustar00rootroot00000000000000celery>=5.2.3,<6.0 importlib-metadata<5.0; python_version<"3.8" # TODO: remove this when celery >= 5.3.0 django-timezone-field>=5.0 backports.zoneinfo; python_version<"3.9" tzdata python-crontab>=2.3.4 cron-descriptor>=1.2.32 django-celery-beat-2.6.0/requirements/docs.txt000066400000000000000000000003401457112420500213650ustar00rootroot00000000000000Django>=2.2,<5.0 sphinxcontrib-django https://github.com/celery/sphinx_celery/archive/master.zip https://github.com/celery/kombu/zipball/main#egg=kombu https://github.com/celery/celery/zipball/main#egg=celery -r default.txt django-celery-beat-2.6.0/requirements/pkgutils.txt000066400000000000000000000001411457112420500222760ustar00rootroot00000000000000setuptools>=40.8.0 wheel>=0.33.1 flake8>=3.8.3 tox>=2.3.1 sphinx2rst>=1.0 bumpversion pydocstyle django-celery-beat-2.6.0/requirements/runtime.txt000066400000000000000000000000211457112420500221140ustar00rootroot00000000000000Django>=2.2,<5.1 django-celery-beat-2.6.0/requirements/test-ci.txt000066400000000000000000000000231457112420500220030ustar00rootroot00000000000000pytest-cov codecov django-celery-beat-2.6.0/requirements/test-django.txt000066400000000000000000000000211457112420500226500ustar00rootroot00000000000000Django>=3.2,<5.0 django-celery-beat-2.6.0/requirements/test.txt000066400000000000000000000001021457112420500214100ustar00rootroot00000000000000pytest-django>=4.5.2,<5.0 pytest>=6.2.5,<9.0 pytest-timeout ephem django-celery-beat-2.6.0/setup.cfg000066400000000000000000000005571457112420500170040ustar00rootroot00000000000000[tool:pytest] testpaths = t/unit/ python_classes = test_* DJANGO_SETTINGS_MODULE=t.proj.settings [flake8] # classes can be lowercase, arguments and variables can be uppercase # whenever it makes the code more readable. ignore = N806, N802, N801, N803, W503, W504 exclude = **/migrations/*.py [pep257] ignore = D102,D104,D203,D105,D213 match-dir = [^migrations] django-celery-beat-2.6.0/setup.py000066400000000000000000000103731457112420500166720ustar00rootroot00000000000000#!/usr/bin/env python3 import codecs import os import re import sys import setuptools import setuptools.command.test try: import platform _pyimp = platform.python_implementation except (AttributeError, ImportError): def _pyimp(): return 'Python' NAME = 'django-celery-beat' PACKAGE = 'django_celery_beat' E_UNSUPPORTED_PYTHON = f'{NAME} 1.0 requires %s %s or later!' PYIMP = _pyimp() PY38_OR_LESS = sys.version_info < (3, 8) PYPY_VERSION = getattr(sys, 'pypy_version_info', None) PYPY24_ATLEAST = PYPY_VERSION and PYPY_VERSION >= (2, 4) if PY38_OR_LESS and not PYPY24_ATLEAST: raise Exception(E_UNSUPPORTED_PYTHON % (PYIMP, '3.8')) # -*- Classifiers -*- classes = """ Development Status :: 5 - Production/Stable License :: OSI Approved :: BSD License Programming Language :: Python Programming Language :: Python :: 3 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 Programming Language :: Python :: 3.12 Programming Language :: Python :: Implementation :: CPython Programming Language :: Python :: Implementation :: PyPy Framework :: Django Framework :: Django :: 3.2 Framework :: Django :: 4.1 Framework :: Django :: 4.2 Framework :: Django :: 5.0 Operating System :: OS Independent Topic :: Communications Topic :: System :: Distributed Computing Topic :: Software Development :: Libraries :: Python Modules """ classifiers = [s.strip() for s in classes.split('\n') if s] # -*- Distribution Meta -*- re_meta = re.compile(r'__(\w+?)__\s*=\s*(.*)') re_doc = re.compile(r'^"""(.+?)"""') def add_default(m): attr_name, attr_value = m.groups() return ((attr_name, attr_value.strip("\"'")),) def add_doc(m): return (('doc', m.groups()[0]),) pats = {re_meta: add_default, re_doc: add_doc} here = os.path.abspath(os.path.dirname(__file__)) with open(os.path.join(here, PACKAGE, '__init__.py')) as meta_fh: meta = {} for line in meta_fh: if line.strip() == '# -eof meta-': break for pattern, handler in pats.items(): m = pattern.match(line.strip()) if m: meta.update(handler(m)) # -*- Installation Requires -*- def strip_comments(line): return line.split('#', 1)[0].strip() def _pip_requirement(req): if req.startswith('-r '): _, path = req.split() return reqs(*path.split('/')) return [req] def _reqs(*f): return [ _pip_requirement(r) for r in ( strip_comments(line) for line in open( os.path.join(os.getcwd(), 'requirements', *f)).readlines() ) if r] def reqs(*f): return [req for subreq in _reqs(*f) for req in subreq] # -*- Long Description -*- if os.path.exists('README.rst'): long_description = codecs.open('README.rst', 'r', 'utf-8').read() long_description_content_type = 'text/x-rst' else: long_description = f'See http://pypi.python.org/pypi/{NAME}' long_description_content_type = 'text/markdown' # -*- %%% -*- class pytest(setuptools.command.test.test): user_options = [('pytest-args=', 'a', 'Arguments to pass to pytest')] def initialize_options(self): setuptools.command.test.test.initialize_options(self) self.pytest_args = [] def run_tests(self): import pytest sys.exit(pytest.main(self.pytest_args)) setuptools.setup( name=NAME, packages=setuptools.find_packages(exclude=[ 'ez_setup', 't', 't.*', ]), version=meta['version'], description=meta['doc'], long_description=long_description, long_description_content_type=long_description_content_type, keywords='django celery beat periodic task database', author=meta['author'], author_email=meta['contact'], url=meta['homepage'], platforms=['any'], license='BSD', install_requires=reqs('default.txt') + reqs('runtime.txt'), tests_require=reqs('test.txt') + reqs('test-django.txt'), cmdclass={'test': pytest}, classifiers=classifiers, entry_points={ 'celery.beat_schedulers': [ 'django = django_celery_beat.schedulers:DatabaseScheduler', ], }, include_package_data=True, zip_safe=False, ) django-celery-beat-2.6.0/t/000077500000000000000000000000001457112420500154175ustar00rootroot00000000000000django-celery-beat-2.6.0/t/.coveragerc000066400000000000000000000003561457112420500175440ustar00rootroot00000000000000[run] branch = 1 cover_pylib = 0 include=*thorn* omit = */tests/*;testproj/*;testapp/*;*/migrations/* [report] omit = */python?.?/* */site-packages/* */pypy/* */tests/* */testproj/* */testapp/* */migrations/* django-celery-beat-2.6.0/t/__init__.py000066400000000000000000000000001457112420500175160ustar00rootroot00000000000000django-celery-beat-2.6.0/t/proj/000077500000000000000000000000001457112420500163715ustar00rootroot00000000000000django-celery-beat-2.6.0/t/proj/__init__.py000066400000000000000000000000561457112420500205030ustar00rootroot00000000000000from .celery import app as celery_app # noqa django-celery-beat-2.6.0/t/proj/celery.py000066400000000000000000000004721457112420500202310ustar00rootroot00000000000000import os from celery import Celery os.environ.setdefault('DJANGO_SETTINGS_MODULE', 't.proj.settings') app = Celery('proj') # Using a string here means the worker doesn't have to serialize # the configuration object. app.config_from_object('django.conf:settings', namespace='CELERY') app.autodiscover_tasks() django-celery-beat-2.6.0/t/proj/migrations/000077500000000000000000000000001457112420500205455ustar00rootroot00000000000000django-celery-beat-2.6.0/t/proj/migrations/0001_initial.py000066400000000000000000000012721457112420500232120ustar00rootroot00000000000000# Generated by Django 4.0.7 on 2022-10-13 05:09 from django.db import migrations, models import django.db.models.deletion class Migration(migrations.Migration): initial = True dependencies = [ ('django_celery_beat', '0016_alter_crontabschedule_timezone'), ] operations = [ migrations.CreateModel( name='O2OToPeriodicTasks', fields=[ ('periodictask_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='django_celery_beat.periodictask')), ], bases=('django_celery_beat.periodictask',), ), ] django-celery-beat-2.6.0/t/proj/migrations/__init__.py000066400000000000000000000000001457112420500226440ustar00rootroot00000000000000django-celery-beat-2.6.0/t/proj/models.py000066400000000000000000000002441457112420500202260ustar00rootroot00000000000000from django_celery_beat.models import PeriodicTask class O2OToPeriodicTasks(PeriodicTask): """ The test-case model of OneToOne relation. """ pass django-celery-beat-2.6.0/t/proj/settings.py000066400000000000000000000061741457112420500206130ustar00rootroot00000000000000""" Django settings for Test project. Generated by 'django-admin startproject' using Django 1.9.1. For more information on this file, see https://docs.djangoproject.com/en/1.9/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/1.9/ref/settings/ """ import os import sys CELERY_DEFAULT_EXCHANGE = 'testcelery' CELERY_DEFAULT_ROUTING_KEY = 'testcelery' CELERY_DEFAULT_QUEUE = 'testcelery' CELERY_QUEUES = {'testcelery': {'binding_key': 'testcelery'}} CELERY_ACCEPT_CONTENT = ['pickle', 'json'] CELERY_TASK_SERIALIZER = 'pickle' CELERY_RESULT_SERIALIZER = 'pickle' # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, os.path.abspath(os.path.join(BASE_DIR, os.pardir))) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = 'u($kbs9$irs0)436gbo9%!b&#zyd&70tx!n7!i&fl6qun@z1_l' # 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_celery_beat', 't.proj', ] 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', ] ROOT_URLCONF = 't.proj.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 = 't.proj.wsgi.application' # Database # https://docs.djangoproject.com/en/1.9/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 'OPTIONS': { 'timeout': 1000, }, } } # Password validation # https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators django_auth = 'django.contrib.auth.password_validation.' AUTH_PASSWORD_VALIDATORS = [ ] # Internationalization # https://docs.djangoproject.com/en/1.9/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.9/howto/static-files/ STATIC_URL = '/static/' DJANGO_CELERY_BEAT_TZ_AWARE = True django-celery-beat-2.6.0/t/proj/urls.py000066400000000000000000000001661457112420500177330ustar00rootroot00000000000000from django.contrib import admin from django.urls import path urlpatterns = [ path('admin/', admin.site.urls), ] django-celery-beat-2.6.0/t/proj/wsgi.py000066400000000000000000000006001457112420500177100ustar00rootroot00000000000000""" WSGI config for Test 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/1.9/howto/deployment/wsgi/ """ import os from django.core.wsgi import get_wsgi_application os.environ.setdefault("DJANGO_SETTINGS_MODULE", "proj.settings") application = get_wsgi_application() django-celery-beat-2.6.0/t/unit/000077500000000000000000000000001457112420500163765ustar00rootroot00000000000000django-celery-beat-2.6.0/t/unit/__init__.py000066400000000000000000000000001457112420500204750ustar00rootroot00000000000000django-celery-beat-2.6.0/t/unit/conftest.py000066400000000000000000000030041457112420500205720ustar00rootroot00000000000000from unittest.mock import MagicMock import pytest # we have to import the pytest plugin fixtures here, # in case user did not do the `python setup.py develop` yet, # that installs the pytest plugin into the setuptools registry. from celery.contrib.pytest import (celery_app, celery_config, celery_enable_logging, celery_parameters, depends_on_current_app, use_celery_app_trap) from celery.contrib.testing.app import TestApp, Trap # Tricks flake8 into silencing redefining fixtures warnings. __all__ = ( 'celery_app', 'celery_enable_logging', 'depends_on_current_app', 'celery_parameters', 'celery_config', 'use_celery_app_trap' ) @pytest.fixture(scope='session', autouse=True) def setup_default_app_trap(): from celery._state import set_default_app set_default_app(Trap()) @pytest.fixture() def app(celery_app): return celery_app @pytest.fixture(autouse=True) def test_cases_shortcuts(request, app, patching): if request.instance: @app.task def add(x, y): return x + y # IMPORTANT: We set an .app attribute for every test case class. request.instance.app = app request.instance.Celery = TestApp request.instance.add = add request.instance.patching = patching yield if request.instance: request.instance.app = None @pytest.fixture def patching(monkeypatch): def _patching(attr): monkeypatch.setattr(attr, MagicMock()) return _patching django-celery-beat-2.6.0/t/unit/test_admin.py000066400000000000000000000136751457112420500211130ustar00rootroot00000000000000from itertools import combinations from unittest import mock import pytest from django.core.exceptions import ValidationError from django.test import TestCase from django_celery_beat.admin import PeriodicTaskAdmin from django_celery_beat.models import (DAYS, ClockedSchedule, CrontabSchedule, IntervalSchedule, PeriodicTask, SolarSchedule) @pytest.mark.django_db() class ActionsTests(TestCase): @classmethod def setUpTestData(cls): super().setUpTestData() cls.interval_schedule = IntervalSchedule.objects.create(every=10, period=DAYS) def test_toggle_action(self): PeriodicTask.objects.create(name='name1', task='task1', enabled=False, interval=self.interval_schedule) PeriodicTask.objects.create(name='name2', task='task2', enabled=True, interval=self.interval_schedule) PeriodicTask.objects.create(name='name3', task='task3', enabled=False, interval=self.interval_schedule) qs = PeriodicTask.objects.all() PeriodicTaskAdmin(PeriodicTask, None)._toggle_tasks_activity(qs) e1 = PeriodicTask.objects.get(name='name1', task='task1').enabled e2 = PeriodicTask.objects.get(name='name2', task='task2').enabled e3 = PeriodicTask.objects.get(name='name3', task='task3').enabled self.assertTrue(e1) self.assertFalse(e2) self.assertTrue(e3) def test_toggle_action_all_enabled(self): PeriodicTask.objects.create(name='name1', task='task1', enabled=True, interval=self.interval_schedule) PeriodicTask.objects.create(name='name2', task='task2', enabled=True, interval=self.interval_schedule) PeriodicTask.objects.create(name='name3', task='task3', enabled=True, interval=self.interval_schedule) qs = PeriodicTask.objects.all() PeriodicTaskAdmin(PeriodicTask, None)._toggle_tasks_activity(qs) e1 = PeriodicTask.objects.get(name='name1', task='task1').enabled e2 = PeriodicTask.objects.get(name='name2', task='task2').enabled e3 = PeriodicTask.objects.get(name='name3', task='task3').enabled self.assertFalse(e1) self.assertFalse(e2) self.assertFalse(e3) def test_toggle_action_all_disabled(self): PeriodicTask.objects.create(name='name1', task='task1', enabled=False, interval=self.interval_schedule) PeriodicTask.objects.create(name='name2', task='task2', enabled=False, interval=self.interval_schedule) PeriodicTask.objects.create(name='name3', task='task3', enabled=False, interval=self.interval_schedule) qs = PeriodicTask.objects.all() PeriodicTaskAdmin(PeriodicTask, None)._toggle_tasks_activity(qs) e1 = PeriodicTask.objects.get(name='name1', task='task1').enabled e2 = PeriodicTask.objects.get(name='name2', task='task2').enabled e3 = PeriodicTask.objects.get(name='name3', task='task3').enabled self.assertTrue(e1) self.assertTrue(e2) self.assertTrue(e3) @pytest.mark.django_db() class ValidateUniqueTests(TestCase): def test_validate_unique_raises_if_schedule_not_set(self): with self.assertRaises(ValidationError) as cm: PeriodicTask(name='task0').validate_unique() self.assertEqual( cm.exception.args[0], 'One of clocked, interval, crontab, or solar must be set.', ) def test_validate_unique_raises_for_multiple_schedules(self): schedules = [ ('crontab', CrontabSchedule()), ('interval', IntervalSchedule()), ('solar', SolarSchedule()), ('clocked', ClockedSchedule()) ] expected_error_msg = ( 'Only one of clocked, interval, crontab, or solar ' 'must be set' ) for i, options in enumerate(combinations(schedules, 2)): name = f'task{i}' options_dict = dict(options) with self.assertRaises(ValidationError) as cm: PeriodicTask(name=name, **options_dict).validate_unique() errors = cm.exception.args[0] self.assertEqual(errors.keys(), options_dict.keys()) for error_msg in errors.values(): self.assertEqual(error_msg, [expected_error_msg]) def test_validate_unique_not_raises(self): PeriodicTask(crontab=CrontabSchedule()).validate_unique() PeriodicTask(interval=IntervalSchedule()).validate_unique() PeriodicTask(solar=SolarSchedule()).validate_unique() PeriodicTask(clocked=ClockedSchedule(), one_off=True).validate_unique() @pytest.mark.django_db() class DisableTasksTest(TestCase): @classmethod def setUpTestData(cls): super().setUpTestData() cls.interval_schedule = IntervalSchedule.objects.create(every=10, period=DAYS) @mock.patch('django_celery_beat.admin.PeriodicTaskAdmin.' '_message_user_about_update') def test_disable_tasks(self, mock_message_user): PeriodicTask.objects.create(name='name1', task='task1', enabled=True, interval=self.interval_schedule) PeriodicTask.objects.create(name='name2', task='task2', enabled=True, interval=self.interval_schedule) qs = PeriodicTask.objects.all() PeriodicTaskAdmin(PeriodicTask, None).disable_tasks(None, qs) for periodic_task in qs: self.assertFalse(periodic_task.enabled) self.assertIsNone(periodic_task.last_run_at) mock_message_user.assert_called_once() django-celery-beat-2.6.0/t/unit/test_crontabs.py000066400000000000000000000332011457112420500216210ustar00rootroot00000000000000from unittest import TestCase from django.core.exceptions import ValidationError from django_celery_beat import validators class MinuteTests(TestCase): def test_good(self): try: validators.minute_validator('*') validators.minute_validator('0') validators.minute_validator('1') validators.minute_validator('54') validators.minute_validator('59') validators.minute_validator('1,2,59') validators.minute_validator('43,2') validators.minute_validator('5,20,25,43') validators.minute_validator('1-4') validators.minute_validator('1-29') validators.minute_validator('45-59') validators.minute_validator('*/4') validators.minute_validator('*/43') validators.minute_validator('1-2/43') except ValidationError as e: self.fail(e) def test_space(self): with self.assertRaises(ValidationError): validators.minute_validator('1, 2') def test_big_number(self): with self.assertRaises(ValidationError): validators.minute_validator('60') with self.assertRaises(ValidationError): validators.minute_validator('420') with self.assertRaises(ValidationError): validators.minute_validator('100500') def test_text(self): with self.assertRaises(ValidationError): validators.minute_validator('fsd') with self.assertRaises(ValidationError): validators.minute_validator('.') with self.assertRaises(ValidationError): validators.minute_validator('432a') def test_out_range(self): with self.assertRaises(ValidationError): validators.minute_validator('0-432') with self.assertRaises(ValidationError): validators.minute_validator('342-432') with self.assertRaises(ValidationError): validators.minute_validator('4-60') def test_bad_range(self): with self.assertRaises(ValidationError): validators.minute_validator('10-4') def test_bad_slice(self): with self.assertRaises(ValidationError): validators.minute_validator('*/100') with self.assertRaises(ValidationError): validators.minute_validator('10/30') with self.assertRaises(ValidationError): validators.minute_validator('10-20/100') class HourTests(TestCase): def test_good(self): try: validators.hour_validator('*') validators.hour_validator('0') validators.hour_validator('1') validators.hour_validator('22') validators.hour_validator('23') validators.hour_validator('1,2,23') validators.hour_validator('23,2') validators.hour_validator('5,20,21,22') validators.hour_validator('1-4') validators.hour_validator('1-23') validators.hour_validator('*/4') validators.hour_validator('*/22') validators.hour_validator('1-2/5') except ValidationError as e: self.fail(e) def test_space(self): with self.assertRaises(ValidationError): validators.hour_validator('1, 2') def test_big_number(self): with self.assertRaises(ValidationError): validators.hour_validator('24') with self.assertRaises(ValidationError): validators.hour_validator('420') with self.assertRaises(ValidationError): validators.hour_validator('100500') def test_text(self): with self.assertRaises(ValidationError): validators.hour_validator('fsd') with self.assertRaises(ValidationError): validators.hour_validator('.') with self.assertRaises(ValidationError): validators.hour_validator('432a') def test_out_range(self): with self.assertRaises(ValidationError): validators.hour_validator('0-24') with self.assertRaises(ValidationError): validators.hour_validator('342-432') with self.assertRaises(ValidationError): validators.hour_validator('4-25') def test_bad_range(self): with self.assertRaises(ValidationError): validators.hour_validator('10-4') def test_bad_slice(self): with self.assertRaises(ValidationError): validators.hour_validator('*/100') with self.assertRaises(ValidationError): validators.hour_validator('10/30') with self.assertRaises(ValidationError): validators.hour_validator('10-20/100') class DayOfMonthTests(TestCase): def test_good(self): try: validators.day_of_month_validator('*') validators.day_of_month_validator('1') validators.day_of_month_validator('29') validators.day_of_month_validator('31') validators.day_of_month_validator('1,2,31') validators.day_of_month_validator('30,2') validators.day_of_month_validator('5,20,25,31') validators.day_of_month_validator('1-4') validators.day_of_month_validator('1-30') validators.day_of_month_validator('*/4') validators.day_of_month_validator('*/22') validators.day_of_month_validator('1-2/5') except ValidationError as e: self.fail(e) def test_space(self): with self.assertRaises(ValidationError): validators.day_of_month_validator('1, 2') def test_zero(self): with self.assertRaises(ValidationError): validators.day_of_month_validator('0') def test_big_number(self): with self.assertRaises(ValidationError): validators.day_of_month_validator('32') with self.assertRaises(ValidationError): validators.day_of_month_validator('420') with self.assertRaises(ValidationError): validators.day_of_month_validator('100500') def test_text(self): with self.assertRaises(ValidationError): validators.day_of_month_validator('fsd') with self.assertRaises(ValidationError): validators.day_of_month_validator('.') with self.assertRaises(ValidationError): validators.day_of_month_validator('432a') def test_out_range(self): with self.assertRaises(ValidationError): validators.day_of_month_validator('0-32') with self.assertRaises(ValidationError): validators.day_of_month_validator('342-432') with self.assertRaises(ValidationError): validators.day_of_month_validator('4-33') def test_bad_range(self): with self.assertRaises(ValidationError): validators.day_of_month_validator('10-4') def test_bad_slice(self): with self.assertRaises(ValidationError): validators.day_of_month_validator('*/100') with self.assertRaises(ValidationError): validators.day_of_month_validator('10/30') with self.assertRaises(ValidationError): validators.day_of_month_validator('10-20/100') class MonthTests(TestCase): def test_good(self): try: validators.month_of_year_validator('*') validators.month_of_year_validator('1') validators.month_of_year_validator('10') validators.month_of_year_validator('12') validators.month_of_year_validator('1,2,12') validators.month_of_year_validator('12,2') validators.month_of_year_validator('5,10,11,12') validators.month_of_year_validator('1-4') validators.month_of_year_validator('1-12') validators.month_of_year_validator('*/4') validators.month_of_year_validator('*/12') validators.month_of_year_validator('1-2/12') except ValidationError as e: self.fail(e) def test_good_month_name(self): try: validators.month_of_year_validator('jan') validators.month_of_year_validator('feb') validators.month_of_year_validator('mar') validators.month_of_year_validator('apr') validators.month_of_year_validator('may') validators.month_of_year_validator('jun') validators.month_of_year_validator('jul') validators.month_of_year_validator('aug') validators.month_of_year_validator('sep') validators.month_of_year_validator('oct') validators.month_of_year_validator('nov') validators.month_of_year_validator('dec') except ValidationError as e: self.fail(e) def test_good_month_name_case(self): try: validators.month_of_year_validator('jan') validators.month_of_year_validator('JAN') validators.month_of_year_validator('JaN') except ValidationError as e: self.fail(e) def test_space(self): with self.assertRaises(ValidationError): validators.month_of_year_validator('1, 2') def test_zero(self): with self.assertRaises(ValidationError): validators.month_of_year_validator('0') def test_big_number(self): with self.assertRaises(ValidationError): validators.month_of_year_validator('13') with self.assertRaises(ValidationError): validators.month_of_year_validator('420') with self.assertRaises(ValidationError): validators.month_of_year_validator('100500') def test_text(self): with self.assertRaises(ValidationError): validators.month_of_year_validator('fsd') with self.assertRaises(ValidationError): validators.month_of_year_validator('.') with self.assertRaises(ValidationError): validators.month_of_year_validator('432a') def test_out_range(self): with self.assertRaises(ValidationError): validators.month_of_year_validator('0-13') with self.assertRaises(ValidationError): validators.month_of_year_validator('342-432') with self.assertRaises(ValidationError): validators.month_of_year_validator('4-14') def test_bad_range(self): with self.assertRaises(ValidationError): validators.month_of_year_validator('10-4') def test_bad_slice(self): with self.assertRaises(ValidationError): validators.month_of_year_validator('*/13') with self.assertRaises(ValidationError): validators.month_of_year_validator('10/30') with self.assertRaises(ValidationError): validators.month_of_year_validator('10-20/100') class DayOfWeekTests(TestCase): def test_good(self): try: validators.day_of_week_validator('*') validators.day_of_week_validator('1') validators.day_of_week_validator('6') validators.day_of_week_validator('7') validators.day_of_week_validator('1,2,6') validators.day_of_week_validator('6,2') validators.day_of_week_validator('5,6,4,6') validators.day_of_week_validator('1-4') validators.day_of_week_validator('1-7') validators.day_of_week_validator('*/4') validators.day_of_week_validator('*/6') validators.day_of_week_validator('2-7/5') except ValidationError as e: self.fail(e) def test_good_month_name(self): try: validators.day_of_week_validator('sun') validators.day_of_week_validator('mon') validators.day_of_week_validator('tue') validators.day_of_week_validator('wed') validators.day_of_week_validator('thu') validators.day_of_week_validator('fri') validators.day_of_week_validator('sat') except ValidationError as e: self.fail(e) def test_good_month_name_case(self): try: validators.day_of_week_validator('mon') validators.day_of_week_validator('MoN') validators.day_of_week_validator('MON') except ValidationError as e: self.fail(e) def test_space(self): with self.assertRaises(ValidationError): validators.day_of_week_validator('1, 2') def test_big_number(self): with self.assertRaises(ValidationError): validators.day_of_week_validator('8') with self.assertRaises(ValidationError): validators.day_of_week_validator('420') with self.assertRaises(ValidationError): validators.day_of_week_validator('100500') def test_text(self): with self.assertRaises(ValidationError): validators.day_of_week_validator('fsd') with self.assertRaises(ValidationError): validators.day_of_week_validator('.') with self.assertRaises(ValidationError): validators.day_of_week_validator('432a') def test_out_range(self): with self.assertRaises(ValidationError): validators.day_of_week_validator('0-32') with self.assertRaises(ValidationError): validators.day_of_week_validator('342-432') with self.assertRaises(ValidationError): validators.day_of_week_validator('4-33') def test_bad_range(self): with self.assertRaises(ValidationError): validators.day_of_week_validator('10-4') def test_bad_slice(self): with self.assertRaises(ValidationError): validators.day_of_week_validator('*/8') with self.assertRaises(ValidationError): validators.day_of_week_validator('10/30') with self.assertRaises(ValidationError): validators.day_of_week_validator('10-20/100') django-celery-beat-2.6.0/t/unit/test_models.py000066400000000000000000000217501457112420500212770ustar00rootroot00000000000000import datetime import os try: from zoneinfo import ZoneInfo, available_timezones except ImportError: from backports.zoneinfo import available_timezones, ZoneInfo import pytest from celery import schedules from django.apps import apps from django.conf import settings from django.db.migrations.autodetector import MigrationAutodetector from django.db.migrations.loader import MigrationLoader from django.db.migrations.questioner import NonInteractiveMigrationQuestioner from django.db.migrations.state import ProjectState from django.test import TestCase, override_settings from django.utils import timezone from django_celery_beat import migrations as beat_migrations from django_celery_beat.models import (DAYS, ClockedSchedule, CrontabSchedule, IntervalSchedule, PeriodicTasks, SolarSchedule, crontab_schedule_celery_timezone) from t.proj.models import O2OToPeriodicTasks class MigrationTests(TestCase): def test_no_future_duplicate_migration_numbers(self): """Verify no duplicate migration numbers. Migration files with the same number can cause issues with backward migrations, so avoid them. """ path = os.path.dirname(beat_migrations.__file__) files = [f[:4] for f in os.listdir(path) if f.endswith('.py')] expected_duplicates = [ (3, '0006'), ] duplicates_extra = sum(count - 1 for count, _ in expected_duplicates) duplicates_numbers = [number for _, number in expected_duplicates] self.assertEqual( len(files), len(set(files)) + duplicates_extra, msg=('Detected migration files with the same migration number' ' (besides {})'.format(' and '.join(duplicates_numbers)))) def test_models_match_migrations(self): """Make sure that no model changes exist. This logic is taken from django's makemigrations.py file. Here just detect if model changes exist that require a migration, and if so we fail. """ app_labels = ['django_celery_beat'] loader = MigrationLoader(None, ignore_no_migrations=True) questioner = NonInteractiveMigrationQuestioner( specified_apps=app_labels, dry_run=False) autodetector = MigrationAutodetector( loader.project_state(), ProjectState.from_apps(apps), questioner, ) changes = autodetector.changes( graph=loader.graph, trim_to_apps=app_labels, convert_apps=app_labels, migration_name='fake_name', ) self.assertTrue( not changes, msg='Model changes exist that do not have a migration') class TestDuplicatesMixin: def _test_duplicate_schedules(self, cls, kwargs, schedule=None): sched1 = cls.objects.create(**kwargs) cls.objects.create(**kwargs) self.assertEqual(cls.objects.filter(**kwargs).count(), 2) # try to create a duplicate schedule from a celery schedule if schedule is None: schedule = sched1.schedule sched3 = cls.from_schedule(schedule) # the schedule should be the first of the 2 previous duplicates self.assertEqual(sched3, sched1) # and the duplicates should not be deleted ! self.assertEqual(cls.objects.filter(**kwargs).count(), 2) class CrontabScheduleTestCase(TestCase, TestDuplicatesMixin): FIRST_VALID_TIMEZONE = available_timezones().pop() def test_default_timezone_without_settings_config(self): assert crontab_schedule_celery_timezone() == "UTC" @override_settings(CELERY_TIMEZONE=FIRST_VALID_TIMEZONE) def test_default_timezone_with_settings_config(self): assert crontab_schedule_celery_timezone() == self.FIRST_VALID_TIMEZONE def test_duplicate_schedules(self): # See: https://github.com/celery/django-celery-beat/issues/322 kwargs = { "minute": "*", "hour": "4", "day_of_week": "*", "day_of_month": "*", "month_of_year": "*", "day_of_week": "*", } schedule = schedules.crontab(hour="4") self._test_duplicate_schedules(CrontabSchedule, kwargs, schedule) class SolarScheduleTestCase(TestCase): EVENT_CHOICES = SolarSchedule._meta.get_field("event").choices def test_celery_solar_schedules_sorted(self): assert all( self.EVENT_CHOICES[i] <= self.EVENT_CHOICES[i + 1] for i in range(len(self.EVENT_CHOICES) - 1) ), "SolarSchedule event choices are unsorted" def test_celery_solar_schedules_included_as_event_choices(self): """Make sure that all Celery solar schedules are included in SolarSchedule `event` field choices, keeping synchronized Celery solar events with `django-celery-beat` supported solar events. This test is necessary because Celery solar schedules are hardcoded at models so that Django can discover their translations. """ event_choices_values = [value for value, tr in self.EVENT_CHOICES] for solar_event in schedules.solar._all_events: assert solar_event in event_choices_values for event_choice in event_choices_values: assert event_choice in schedules.solar._all_events class IntervalScheduleTestCase(TestCase, TestDuplicatesMixin): def test_duplicate_schedules(self): kwargs = {'every': 1, 'period': IntervalSchedule.SECONDS} schedule = schedules.schedule(run_every=1.0) self._test_duplicate_schedules(IntervalSchedule, kwargs, schedule) class ClockedScheduleTestCase(TestCase, TestDuplicatesMixin): def test_duplicate_schedules(self): kwargs = {'clocked_time': timezone.now()} self._test_duplicate_schedules(ClockedSchedule, kwargs) # IMPORTANT: we must have a valid timezone (not UTC) for accurate testing @override_settings(TIME_ZONE='Africa/Cairo') def test_timezone_format(self): """Ensure scheduled time is not shown in UTC when timezone is used""" tz_info = datetime.datetime.now(ZoneInfo(settings.TIME_ZONE)) schedule, created = ClockedSchedule.objects.get_or_create( clocked_time=tz_info) # testnig str(schedule) calls make_aware() internally assert str(schedule.clocked_time) == str(schedule) @pytest.mark.django_db() class OneToOneRelTestCase(TestCase): """ Make sure that when OneToOne relation Model changed, the `PeriodicTasks.last_update` will be update. """ @classmethod def setUpTestData(cls): super().setUpTestData() cls.interval_schedule = IntervalSchedule.objects.create( every=10, period=DAYS ) def test_trigger_update_when_saved(self): o2o_to_periodic_tasks = O2OToPeriodicTasks.objects.create( name='name1', task='task1', enabled=True, interval=self.interval_schedule ) not_changed_dt = PeriodicTasks.last_change() o2o_to_periodic_tasks.enabled = True # Change something on instance. o2o_to_periodic_tasks.save() has_changed_dt = PeriodicTasks.last_change() self.assertTrue( not_changed_dt != has_changed_dt, 'The `PeriodicTasks.last_update` has not be update.' ) # Check the `PeriodicTasks` does be updated. def test_trigger_update_when_deleted(self): o2o_to_periodic_tasks = O2OToPeriodicTasks.objects.create( name='name1', task='task1', enabled=True, interval=self.interval_schedule ) not_changed_dt = PeriodicTasks.last_change() o2o_to_periodic_tasks.delete() has_changed_dt = PeriodicTasks.last_change() self.assertTrue( not_changed_dt != has_changed_dt, 'The `PeriodicTasks.last_update` has not be update.' ) # Check the `PeriodicTasks` does be updated. class HumanReadableTestCase(TestCase): def test_good(self): """Valid crontab display.""" cron = CrontabSchedule.objects.create( hour="2", minute="0", day_of_week="mon", ) self.assertNotEqual( cron.human_readable, "0 2 * * mon UTC" ) def test_invalid(self): """Invalid crontab display.""" cron = CrontabSchedule.objects.create( hour="2", minute="0", day_of_week="monxxx", ) self.assertEqual( cron.human_readable, "0 2 * * monxxx UTC" ) def test_long_name(self): """Long day name display.""" # TODO: this should eventually work, but probably needs conversion # before passing data to cron_description cron = CrontabSchedule.objects.create( hour="2", minute="0", day_of_week="monday", ) self.assertEqual( cron.human_readable, "0 2 * * monday UTC" ) django-celery-beat-2.6.0/t/unit/test_schedulers.py000066400000000000000000000736071457112420500221650ustar00rootroot00000000000000import math import os import time from datetime import datetime, timedelta from itertools import count from time import monotonic import pytest from celery.schedules import crontab, schedule, solar from django.contrib.admin.sites import AdminSite from django.contrib.messages.storage.fallback import FallbackStorage from django.test import RequestFactory, override_settings from django.utils import timezone from django_celery_beat import schedulers from django_celery_beat.admin import PeriodicTaskAdmin from django_celery_beat.clockedschedule import clocked from django_celery_beat.models import (DAYS, ClockedSchedule, CrontabSchedule, IntervalSchedule, PeriodicTask, PeriodicTasks, SolarSchedule) from django_celery_beat.utils import NEVER_CHECK_TIMEOUT, make_aware _ids = count(0) @pytest.fixture(autouse=True) def no_multiprocessing_finalizers(patching): patching('multiprocessing.util.Finalize') patching('django_celery_beat.schedulers.Finalize') class EntryTrackSave(schedulers.ModelEntry): def __init__(self, *args, **kwargs): self.saved = 0 super().__init__(*args, **kwargs) def save(self): self.saved += 1 super().save() class EntrySaveRaises(schedulers.ModelEntry): def save(self): raise RuntimeError('this is expected') class TrackingScheduler(schedulers.DatabaseScheduler): Entry = EntryTrackSave def __init__(self, *args, **kwargs): self.flushed = 0 schedulers.DatabaseScheduler.__init__(self, *args, **kwargs) def sync(self): self.flushed += 1 schedulers.DatabaseScheduler.sync(self) @pytest.mark.django_db() class SchedulerCase: def create_model_interval(self, schedule, **kwargs): interval = IntervalSchedule.from_schedule(schedule) interval.save() return self.create_model(interval=interval, **kwargs) def create_model_crontab(self, schedule, **kwargs): crontab = CrontabSchedule.from_schedule(schedule) crontab.save() return self.create_model(crontab=crontab, **kwargs) def create_model_solar(self, schedule, **kwargs): solar = SolarSchedule.from_schedule(schedule) solar.save() return self.create_model(solar=solar, **kwargs) def create_model_clocked(self, schedule, **kwargs): clocked = ClockedSchedule.from_schedule(schedule) clocked.save() return self.create_model(clocked=clocked, one_off=True, **kwargs) def create_conf_entry(self): name = f'thefoo{next(_ids)}' return name, dict( task=f'djcelery.unittest.add{next(_ids)}', schedule=timedelta(0, 600), args=(), relative=False, kwargs={}, options={'queue': 'extra_queue'} ) def create_model(self, Model=PeriodicTask, **kwargs): entry = dict( name=f'thefoo{next(_ids)}', task=f'djcelery.unittest.add{next(_ids)}', args='[2, 2]', kwargs='{"callback": "foo"}', queue='xaz', routing_key='cpu', priority=1, headers='{"_schema_name": "foobar"}', exchange='foo', ) return Model(**dict(entry, **kwargs)) def create_interval_schedule(self): return IntervalSchedule.objects.create(every=10, period=DAYS) def create_crontab_schedule(self): return CrontabSchedule.objects.create() @pytest.mark.django_db() class test_ModelEntry(SchedulerCase): Entry = EntryTrackSave def test_entry(self): m = self.create_model_interval(schedule(timedelta(seconds=10))) e = self.Entry(m, app=self.app) assert e.args == [2, 2] assert e.kwargs == {'callback': 'foo'} assert e.schedule assert e.total_run_count == 0 assert isinstance(e.last_run_at, datetime) assert e.options['queue'] == 'xaz' assert e.options['exchange'] == 'foo' assert e.options['routing_key'] == 'cpu' assert e.options['priority'] == 1 assert e.options['headers'] == {'_schema_name': 'foobar'} assert e.options['periodic_task_name'] == m.name right_now = self.app.now() m2 = self.create_model_interval( schedule(timedelta(seconds=10)), last_run_at=right_now, ) assert m2.last_run_at e2 = self.Entry(m2, app=self.app) assert e2.last_run_at is right_now e3 = e2.next() assert e3.last_run_at > e2.last_run_at assert e3.total_run_count == 1 @override_settings( USE_TZ=False, DJANGO_CELERY_BEAT_TZ_AWARE=False ) @pytest.mark.usefixtures('depends_on_current_app') @timezone.override('Europe/Berlin') @pytest.mark.celery(timezone='Europe/Berlin') def test_entry_is_due__no_use_tz(self): old_tz = os.environ.get("TZ") os.environ["TZ"] = "Europe/Berlin" if hasattr(time, "tzset"): time.tzset() assert self.app.timezone.key == 'Europe/Berlin' # simulate last_run_at from DB - not TZ aware but localtime right_now = datetime.utcnow() m = self.create_model_crontab( crontab(minute='*/10'), last_run_at=right_now, ) e = self.Entry(m, app=self.app) assert e.is_due().is_due is False assert e.is_due().next <= 600 # 10 minutes; see above if old_tz is not None: os.environ["TZ"] = old_tz else: del os.environ["TZ"] if hasattr(time, "tzset"): time.tzset() @override_settings( USE_TZ=False, DJANGO_CELERY_BEAT_TZ_AWARE=False ) @pytest.mark.usefixtures('depends_on_current_app') @timezone.override('Europe/Berlin') @pytest.mark.celery(timezone='Europe/Berlin') def test_entry_and_model_last_run_at_with_utc_no_use_tz(self, monkeypatch): old_tz = os.environ.get("TZ") os.environ["TZ"] = "Europe/Berlin" if hasattr(time, "tzset"): time.tzset() assert self.app.timezone.key == 'Europe/Berlin' # simulate last_run_at from DB - not TZ aware but localtime right_now = datetime.utcnow() # make sure to use fixed date time monkeypatch.setattr(self.Entry, '_default_now', lambda o: right_now) m = self.create_model_crontab( crontab(minute='*/10') ) m.save() e = self.Entry(m, app=self.app) e.save() m.refresh_from_db() assert m.last_run_at == e.last_run_at if old_tz is not None: os.environ["TZ"] = old_tz else: del os.environ["TZ"] if hasattr(time, "tzset"): time.tzset() @override_settings( USE_TZ=False, DJANGO_CELERY_BEAT_TZ_AWARE=False, TIME_ZONE="Europe/Berlin", CELERY_TIMEZONE="America/New_York" ) @pytest.mark.usefixtures('depends_on_current_app') @timezone.override('Europe/Berlin') @pytest.mark.celery(timezone='America/New_York') def test_entry_is_due__celery_timezone_doesnt_match_time_zone(self): old_tz = os.environ.get("TZ") os.environ["TZ"] = "Europe/Berlin" if hasattr(time, "tzset"): time.tzset() assert self.app.timezone.key == 'America/New_York' # simulate last_run_at all none, doing the same thing that # _default_now() would do right_now = datetime.utcnow() m = self.create_model_crontab( crontab(minute='*/10'), last_run_at=right_now, ) e = self.Entry(m, app=self.app) assert e.is_due().is_due is False assert e.is_due().next <= 600 # 10 minutes; see above if old_tz is not None: os.environ["TZ"] = old_tz else: del os.environ["TZ"] if hasattr(time, "tzset"): time.tzset() def test_task_with_start_time(self): interval = 10 right_now = self.app.now() one_interval_ago = right_now - timedelta(seconds=interval) m = self.create_model_interval(schedule(timedelta(seconds=interval)), start_time=right_now, last_run_at=one_interval_ago) e = self.Entry(m, app=self.app) isdue, delay = e.is_due() assert isdue assert delay == interval tomorrow = right_now + timedelta(days=1) m2 = self.create_model_interval(schedule(timedelta(seconds=interval)), start_time=tomorrow, last_run_at=one_interval_ago) e2 = self.Entry(m2, app=self.app) isdue, delay = e2.is_due() assert not isdue assert delay == math.ceil((tomorrow - right_now).total_seconds()) def test_one_off_task(self): interval = 10 right_now = self.app.now() one_interval_ago = right_now - timedelta(seconds=interval) m = self.create_model_interval(schedule(timedelta(seconds=interval)), one_off=True, last_run_at=one_interval_ago, total_run_count=0) e = self.Entry(m, app=self.app) isdue, delay = e.is_due() assert isdue assert delay == interval m2 = self.create_model_interval(schedule(timedelta(seconds=interval)), one_off=True, last_run_at=one_interval_ago, total_run_count=1) e2 = self.Entry(m2, app=self.app) isdue, delay = e2.is_due() assert not isdue assert delay == NEVER_CHECK_TIMEOUT @pytest.mark.django_db() class test_DatabaseSchedulerFromAppConf(SchedulerCase): Scheduler = TrackingScheduler @pytest.mark.django_db() @pytest.fixture(autouse=True) def setup_scheduler(self, app): self.app = app self.entry_name, entry = self.create_conf_entry() self.app.conf.beat_schedule = {self.entry_name: entry} self.m1 = PeriodicTask(name=self.entry_name, interval=self.create_interval_schedule()) def test_constructor(self): s = self.Scheduler(app=self.app) assert isinstance(s._dirty, set) assert s._last_sync is None assert s.sync_every def test_periodic_task_model_enabled_schedule(self): s = self.Scheduler(app=self.app) sched = s.schedule assert len(sched) == 2 assert 'celery.backend_cleanup' in sched assert self.entry_name in sched for n, e in sched.items(): assert isinstance(e, s.Entry) if n == 'celery.backend_cleanup': assert e.options['expires'] == 12 * 3600 assert e.model.expires is None assert e.model.expire_seconds == 12 * 3600 def test_periodic_task_model_disabled_schedule(self): self.m1.enabled = False self.m1.save() s = self.Scheduler(app=self.app) sched = s.schedule assert sched assert len(sched) == 1 assert 'celery.backend_cleanup' in sched assert self.entry_name not in sched def test_periodic_task_model_schedule_type_change(self): self.m1.interval = None self.m1.crontab = self.create_crontab_schedule() self.m1.save() self.Scheduler(app=self.app) self.m1.refresh_from_db() assert self.m1.interval assert self.m1.crontab is None @pytest.mark.django_db() class test_DatabaseScheduler(SchedulerCase): Scheduler = TrackingScheduler @pytest.mark.django_db() @pytest.fixture(autouse=True) def setup_scheduler(self, app): self.app = app self.app.conf.beat_schedule = {} self.m1 = self.create_model_interval( schedule(timedelta(seconds=10))) self.m1.save() self.m1.refresh_from_db() self.m2 = self.create_model_interval( schedule(timedelta(minutes=20))) self.m2.save() self.m2.refresh_from_db() self.m3 = self.create_model_crontab( crontab(minute='2,4,5')) self.m3.save() self.m3.refresh_from_db() self.m4 = self.create_model_solar( solar('solar_noon', 48.06, 12.86)) self.m4.save() self.m4.refresh_from_db() dt_aware = make_aware(datetime(day=26, month=7, year=3000, hour=1, minute=0)) # future time self.m6 = self.create_model_clocked( clocked(dt_aware) ) self.m6.save() self.m6.refresh_from_db() # disabled, should not be in schedule m5 = self.create_model_interval( schedule(timedelta(seconds=1))) m5.enabled = False m5.save() self.s = self.Scheduler(app=self.app) def test_constructor(self): assert isinstance(self.s._dirty, set) assert self.s._last_sync is None assert self.s.sync_every def test_all_as_schedule(self): sched = self.s.schedule assert sched assert len(sched) == 6 assert 'celery.backend_cleanup' in sched for n, e in sched.items(): assert isinstance(e, self.s.Entry) def test_schedule_changed(self): self.m2.args = '[16, 16]' self.m2.save() e2 = self.s.schedule[self.m2.name] assert e2.args == [16, 16] self.m1.args = '[32, 32]' self.m1.save() e1 = self.s.schedule[self.m1.name] assert e1.args == [32, 32] e1 = self.s.schedule[self.m1.name] assert e1.args == [32, 32] self.m3.delete() with pytest.raises(KeyError): self.s.schedule.__getitem__(self.m3.name) def test_should_sync(self): assert self.s.should_sync() self.s._last_sync = monotonic() assert not self.s.should_sync() self.s._last_sync -= self.s.sync_every assert self.s.should_sync() def test_reserve(self): e1 = self.s.schedule[self.m1.name] self.s.schedule[self.m1.name] = self.s.reserve(e1) assert self.s.flushed == 1 e2 = self.s.schedule[self.m2.name] self.s.schedule[self.m2.name] = self.s.reserve(e2) assert self.s.flushed == 1 assert self.m2.name in self.s._dirty def test_sync_not_saves_last_run_at_while_schedule_changed(self): # Update e1 last_run_at and add to dirty e1 = self.s.schedule[self.m2.name] time.sleep(3) e1.model.last_run_at = e1._default_now() self.s._dirty.add(e1.model.name) # Record e1 pre sync last_run_at e1_pre_sync_last_run_at = e1.model.last_run_at # Set schedule_changed() == True self.s._last_timestamp = monotonic() # Do sync self.s.sync() # Record e1 post sync last_run_at e1_m = PeriodicTask.objects.get(pk=e1.model.pk) e1_post_sync_last_run_at = e1_m.last_run_at # Check assert e1_pre_sync_last_run_at == e1_post_sync_last_run_at def test_sync_saves_last_run_at(self): e1 = self.s.schedule[self.m2.name] last_run = e1.last_run_at last_run2 = last_run - timedelta(days=1) e1.model.last_run_at = last_run2 self.s._dirty.add(self.m2.name) self.s.sync() e2 = self.s.schedule[self.m2.name] assert e2.last_run_at == last_run2 def test_sync_syncs_before_save(self): # Get the entry for m2 e1 = self.s.schedule[self.m2.name] # Increment the entry (but make sure it doesn't sync) self.s._last_sync = monotonic() e2 = self.s.schedule[e1.name] = self.s.reserve(e1) assert self.s.flushed == 1 # Fetch the raw object from db, change the args # and save the changes. m2 = PeriodicTask.objects.get(pk=self.m2.pk) m2.args = '[16, 16]' m2.save() # get_schedule should now see the schedule has changed. # and also sync the dirty objects. e3 = self.s.schedule[self.m2.name] assert self.s.flushed == 2 assert e3.last_run_at == e2.last_run_at assert e3.args == [16, 16] def test_periodic_task_disabled_and_enabled(self): # Get the entry for m2 e1 = self.s.schedule[self.m2.name] # Increment the entry (but make sure it doesn't sync) self.s._last_sync = monotonic() self.s.schedule[e1.name] = self.s.reserve(e1) assert self.s.flushed == 1 # Fetch the raw object from db, change the args # and save the changes. m2 = PeriodicTask.objects.get(pk=self.m2.pk) m2.enabled = False m2.save() # get_schedule should now see the schedule has changed. # and remove entry for m2 assert self.m2.name not in self.s.schedule assert self.s.flushed == 2 m2.enabled = True m2.save() # get_schedule should now see the schedule has changed. # and add entry for m2 assert self.m2.name in self.s.schedule assert self.s.flushed == 3 def test_periodic_task_disabled_while_reserved(self): # Get the entry for m2 e1 = self.s.schedule[self.m2.name] # Increment the entry (but make sure it doesn't sync) self.s._last_sync = monotonic() e2 = self.s.schedule[e1.name] = self.s.reserve(e1) assert self.s.flushed == 1 # Fetch the raw object from db, change the args # and save the changes. m2 = PeriodicTask.objects.get(pk=self.m2.pk) m2.enabled = False m2.save() # reserve is called because the task gets called from # tick after the database change is made self.s.reserve(e2) # get_schedule should now see the schedule has changed. # and remove entry for m2 assert self.m2.name not in self.s.schedule assert self.s.flushed == 2 def test_sync_not_dirty(self): self.s._dirty.clear() self.s.sync() def test_sync_object_gone(self): self.s._dirty.add('does-not-exist') self.s.sync() def test_sync_rollback_on_save_error(self): self.s.schedule[self.m1.name] = EntrySaveRaises(self.m1, app=self.app) self.s._dirty.add(self.m1.name) with pytest.raises(RuntimeError): self.s.sync() def test_update_scheduler_heap_invalidation(self, monkeypatch): # mock "schedule_changed" to always trigger update for # all calls to schedule, as a change may occur at any moment monkeypatch.setattr(self.s, 'schedule_changed', lambda: True) self.s.tick() def test_heap_size_is_constant(self, monkeypatch): # heap size is constant unless the schedule changes monkeypatch.setattr(self.s, 'schedule_changed', lambda: True) expected_heap_size = len(self.s.schedule.values()) self.s.tick() assert len(self.s._heap) == expected_heap_size self.s.tick() assert len(self.s._heap) == expected_heap_size def test_scheduler_schedules_equality_on_change(self, monkeypatch): monkeypatch.setattr(self.s, 'schedule_changed', lambda: False) assert self.s.schedules_equal(self.s.schedule, self.s.schedule) monkeypatch.setattr(self.s, 'schedule_changed', lambda: True) assert not self.s.schedules_equal(self.s.schedule, self.s.schedule) def test_heap_always_return_the_first_item(self): interval = 10 s1 = schedule(timedelta(seconds=interval)) m1 = self.create_model_interval(s1, enabled=False) m1.last_run_at = self.app.now() - timedelta(seconds=interval + 2) m1.save() m1.refresh_from_db() s2 = schedule(timedelta(seconds=interval)) m2 = self.create_model_interval(s2, enabled=True) m2.last_run_at = self.app.now() - timedelta(seconds=interval + 1) m2.save() m2.refresh_from_db() e1 = EntryTrackSave(m1, self.app) # because the disabled task e1 runs first, e2 will never be executed e2 = EntryTrackSave(m2, self.app) s = self.Scheduler(app=self.app) s.schedule.clear() s.schedule[e1.name] = e1 s.schedule[e2.name] = e2 tried = set() for _ in range(len(s.schedule) * 8): tick_interval = s.tick() if tick_interval and tick_interval > 0.0: tried.add(s._heap[0].entry.name) time.sleep(tick_interval) if s.should_sync(): s.sync() assert len(tried) == 1 and tried == {e1.name} def test_starttime_trigger(self, monkeypatch): # Ensure there is no heap block in case of new task with start_time PeriodicTask.objects.all().delete() s = self.Scheduler(app=self.app) assert not s._heap m1 = self.create_model_interval(schedule(timedelta(seconds=3))) m1.save() s.tick() assert len(s._heap) == 2 m2 = self.create_model_interval( schedule(timedelta(days=1)), start_time=make_aware( datetime.now() + timedelta(seconds=2))) m2.save() s.tick() assert s._heap[0][2].name == m2.name assert len(s._heap) == 3 assert s._heap[0] time.sleep(2) s.tick() assert s._heap[0] assert s._heap[0][2].name == m1.name @pytest.mark.django_db() class test_models(SchedulerCase): def test_IntervalSchedule_unicode(self): assert (str(IntervalSchedule(every=1, period='seconds')) == 'every second') assert (str(IntervalSchedule(every=10, period='seconds')) == 'every 10 seconds') def test_CrontabSchedule_unicode(self): assert str(CrontabSchedule( minute=3, hour=3, day_of_week=None, )) == '3 3 * * * (m/h/dM/MY/d) UTC' assert str(CrontabSchedule( minute=3, hour=3, day_of_week='tue', day_of_month='*/2', month_of_year='4,6', )) == '3 3 */2 4,6 tue (m/h/dM/MY/d) UTC' def test_PeriodicTask_unicode_interval(self): p = self.create_model_interval(schedule(timedelta(seconds=10))) assert str(p) == f'{p.name}: every 10.0 seconds' def test_PeriodicTask_unicode_crontab(self): p = self.create_model_crontab(crontab( hour='4, 5', day_of_week='4, 5', )) assert str(p) == """{}: * 4,5 * * 4,5 (m/h/dM/MY/d) UTC""".format( p.name ) def test_PeriodicTask_unicode_solar(self): p = self.create_model_solar( solar('solar_noon', 48.06, 12.86), name='solar_event' ) assert str(p) == 'solar_event: {} ({}, {})'.format( 'Solar noon', '48.06', '12.86' ) def test_PeriodicTask_unicode_clocked(self): time = make_aware(datetime.now()) p = self.create_model_clocked( clocked(time), name='clocked_event' ) assert str(p) == '{}: {}'.format( 'clocked_event', str(time) ) def test_PeriodicTask_schedule_property(self): p1 = self.create_model_interval(schedule(timedelta(seconds=10))) s1 = p1.schedule assert s1.run_every.total_seconds() == 10 p2 = self.create_model_crontab(crontab( hour='4, 5', minute='10,20,30', day_of_month='1-7', month_of_year='*/3', )) s2 = p2.schedule assert s2.hour == {4, 5} assert s2.minute == {10, 20, 30} assert s2.day_of_week == {0, 1, 2, 3, 4, 5, 6} assert s2.day_of_month == {1, 2, 3, 4, 5, 6, 7} assert s2.month_of_year == {1, 4, 7, 10} def test_PeriodicTask_unicode_no_schedule(self): p = self.create_model() assert str(p) == f'{p.name}: {{no schedule}}' def test_CrontabSchedule_schedule(self): s = CrontabSchedule( minute='3, 7', hour='3, 4', day_of_week='*', day_of_month='1, 16', month_of_year='1, 7', ) assert s.schedule.minute == {3, 7} assert s.schedule.hour == {3, 4} assert s.schedule.day_of_week == {0, 1, 2, 3, 4, 5, 6} assert s.schedule.day_of_month == {1, 16} assert s.schedule.month_of_year == {1, 7} def test_CrontabSchedule_long_schedule(self): s = CrontabSchedule( minute=str(list(range(60)))[1:-1], hour=str(list(range(24)))[1:-1], day_of_week=str(list(range(7)))[1:-1], day_of_month=str(list(range(1, 32)))[1:-1], month_of_year=str(list(range(1, 13)))[1:-1] ) assert s.schedule.minute == set(range(60)) assert s.schedule.hour == set(range(24)) assert s.schedule.day_of_week == set(range(7)) assert s.schedule.day_of_month == set(range(1, 32)) assert s.schedule.month_of_year == set(range(1, 13)) fields = [ 'minute', 'hour', 'day_of_week', 'day_of_month', 'month_of_year' ] for field in fields: str_length = len(str(getattr(s.schedule, field))) field_length = s._meta.get_field(field).max_length assert str_length <= field_length def test_SolarSchedule_schedule(self): s = SolarSchedule(event='solar_noon', latitude=48.06, longitude=12.86) dt = datetime(day=26, month=7, year=2050, hour=1, minute=0) dt_lastrun = make_aware(dt) assert s.schedule is not None isdue, nextcheck = s.schedule.is_due(dt_lastrun) assert isdue is False # False means task isn't due, but keep checking. assert (nextcheck > 0) and (isdue is False) or \ (nextcheck == s.max_interval) and (isdue is True) s2 = SolarSchedule(event='solar_noon', latitude=48.06, longitude=12.86) dt2 = datetime(day=26, month=7, year=2000, hour=1, minute=0) dt2_lastrun = make_aware(dt2) assert s2.schedule is not None isdue2, nextcheck2 = s2.schedule.is_due(dt2_lastrun) assert isdue2 is True # True means task is due and should run. assert (nextcheck2 > 0) and (isdue2 is True) or \ (nextcheck2 == s2.max_interval) and (isdue2 is False) def test_ClockedSchedule_schedule(self): due_datetime = make_aware(datetime(day=26, month=7, year=3000, hour=1, minute=0)) # future time s = ClockedSchedule(clocked_time=due_datetime) dt = datetime(day=25, month=7, year=2050, hour=1, minute=0) dt_lastrun = make_aware(dt) assert s.schedule is not None isdue, nextcheck = s.schedule.is_due(dt_lastrun) assert isdue is False # False means task isn't due, but keep checking. assert (nextcheck > 0) and (isdue is False) or \ (nextcheck == s.max_interval) and (isdue is True) due_datetime = make_aware(datetime.now()) s = ClockedSchedule(clocked_time=due_datetime) dt2_lastrun = make_aware(datetime.now()) assert s.schedule is not None isdue2, nextcheck2 = s.schedule.is_due(dt2_lastrun) assert isdue2 is True # True means task is due and should run. assert (nextcheck2 == NEVER_CHECK_TIMEOUT) and (isdue2 is True) @pytest.mark.django_db() class test_model_PeriodicTasks(SchedulerCase): def test_track_changes(self): assert PeriodicTasks.last_change() is None m1 = self.create_model_interval(schedule(timedelta(seconds=10))) m1.save() x = PeriodicTasks.last_change() assert x m1.args = '(23, 24)' m1.save() y = PeriodicTasks.last_change() assert y assert y > x @pytest.mark.django_db() class test_modeladmin_PeriodicTaskAdmin(SchedulerCase): @pytest.mark.django_db() @pytest.fixture(autouse=True) def setup_scheduler(self, app): self.app = app self.site = AdminSite() self.request_factory = RequestFactory() interval_schedule = self.create_interval_schedule() entry_name, entry = self.create_conf_entry() self.app.conf.beat_schedule = {entry_name: entry} self.m1 = PeriodicTask(name=entry_name, interval=interval_schedule) self.m1.task = 'celery.backend_cleanup' self.m1.save() entry_name, entry = self.create_conf_entry() self.app.conf.beat_schedule = {entry_name: entry} self.m2 = PeriodicTask(name=entry_name, interval=interval_schedule) self.m2.task = 'celery.backend_cleanup' self.m2.save() def patch_request(self, request): """patch request to allow for django messages storage""" setattr(request, 'session', 'session') messages = FallbackStorage(request) setattr(request, '_messages', messages) return request # don't hang if broker is down # https://github.com/celery/celery/issues/4627 @pytest.mark.timeout(5) def test_run_task(self): ma = PeriodicTaskAdmin(PeriodicTask, self.site) self.request = self.patch_request(self.request_factory.get('/')) ma.run_tasks(self.request, PeriodicTask.objects.filter(id=self.m1.id)) assert len(self.request._messages._queued_messages) == 1 queued_message = self.request._messages._queued_messages[0].message assert queued_message == '1 task was successfully run' # don't hang if broker is down # https://github.com/celery/celery/issues/4627 @pytest.mark.timeout(5) def test_run_tasks(self): ma = PeriodicTaskAdmin(PeriodicTask, self.site) self.request = self.patch_request(self.request_factory.get('/')) ma.run_tasks(self.request, PeriodicTask.objects.all()) assert len(self.request._messages._queued_messages) == 1 queued_message = self.request._messages._queued_messages[0].message assert queued_message == '2 tasks were successfully run' django-celery-beat-2.6.0/tox.ini000066400000000000000000000035661457112420500165010ustar00rootroot00000000000000; https://docs.djangoproject.com/en/stable/faq/install/#what-python-version-can-i-use-with-django [gh-actions] python = 3.8: py38, apicheck, linkcheck 3.9: py39, flake8, pydocstyle, cov 3.10: py310 3.11: py311 3.12: py312 pypy-3.10: pypy3 [gh-actions:env] DJANGO = 3.2: django32 4.1: django41 4.2: django42 5.0: django50 [tox] envlist = py38-django{32,42} py39-django{32,42} py310-django{32,42,50} py311-django{42,50} py312-django{42,50} pypy3-django{32,42,50} flake8 apicheck linkcheck pydocstyle cov [testenv] deps= -r{toxinidir}/requirements/default.txt -r{toxinidir}/requirements/test.txt -r{toxinidir}/requirements/test-ci.txt cov: -r{toxinidir}/requirements/test-django.txt django32: Django ~= 3.2 django41: Django ~= 4.1 django42: Django ~= 4.2 django50: Django ~= 5.0 linkcheck,apicheck: -r{toxinidir}/requirements/docs.txt flake8,pydocstyle: -r{toxinidir}/requirements/pkgutils.txt sitepackages = False recreate = False commands = pip list pytest -xv [testenv:apicheck] basepython = python3.8 commands = sphinx-build -W -b apicheck -d {envtmpdir}/doctrees docs docs/_build/apicheck [testenv:linkcheck] basepython = python3.8 commands = sphinx-build -W -b linkcheck -d {envtmpdir}/doctrees docs docs/_build/linkcheck [testenv:flake8] basepython = python3.9 commands = python -m flake8 {toxinidir}/django_celery_beat {toxinidir}/t [testenv:pydocstyle] basepython = python3.9 commands = pydocstyle {toxinidir}/django_celery_beat [testenv:cov] basepython = python3.9 usedevelop = true commands = pip install --upgrade https://github.com/celery/celery/zipball/main#egg=celery pip install --upgrade https://github.com/celery/kombu/zipball/main#egg=kombu pip install Django pytest -x --cov=django_celery_beat --cov-report=xml --no-cov-on-fail