From 8822e7d409c3e9a01f713d765aae7004a6745cfb Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Thu, 20 Oct 2022 15:17:44 +0200 Subject: [PATCH 01/39] Remove funding file, add docker/compose for development project and fix (#18) task names in logs --- .github/FUNDING.yml | 3 --- Dockerfile | 8 ++++++++ django_q/cluster.py | 15 ++++++++------- web-docker-compose.yaml | 11 +++++++++++ 4 files changed, 27 insertions(+), 10 deletions(-) delete mode 100644 .github/FUNDING.yml create mode 100644 Dockerfile create mode 100644 web-docker-compose.yaml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index e21bb1d..0000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,3 +0,0 @@ -# These are supported funding model platforms - -github: [koed00] diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..34bd734 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,8 @@ +FROM python:3.9 + +ENV PYTHONUNBUFFERED 1 +RUN mkdir -p /app +WORKDIR /app +COPY . . +RUN pip install django blessed django-picklefield + diff --git a/django_q/cluster.py b/django_q/cluster.py index df4afb4..8a9046a 100644 --- a/django_q/cluster.py +++ b/django_q/cluster.py @@ -390,13 +390,13 @@ def monitor(result_queue: Queue, broker: Broker = None): # signal execution done post_execute.send(sender="django_q", task=task) # log the result - info_name = f"{task['name']} ({task['func']})" + info_name = get_func_repr(task['func']) if task["success"]: # log success - logger.info(_(f"Processed [{info_name}]")) + logger.info(_(f"Processed {info_name} ({task['name']})")) else: # log failure - logger.error(_(f"Failed [{info_name}] - {task['result']}")) + logger.error(_(f"Failed {info_name} ({task['name']}) - {task['result']}")) logger.info(_(f"{name} stopped monitoring results")) @@ -422,8 +422,8 @@ def worker( task_count += 1 # Get the function from the task func = task["func"] - func_name = func.__name__ if hasattr(func, "__name__") else str(func) - logger.info(_(f'{proc_name} processing [{task["name"]}({func_name})]')) + func_name = get_func_repr(func) + logger.info(_(f'{proc_name} processing {func_name} ({task["name"]})')) f = task["func"] # if it's not an instance try to get it from the string if not callable(task["func"]): @@ -460,12 +460,13 @@ def get_func_repr(func): # convert func to string if inspect.isfunction(func): return f"{func.__module__}.{func.__name__}" - elif inspect.ismethod(func): + elif inspect.ismethod(func) and hasattr(func.__self__, '__name__'): return ( f"{func.__self__.__module__}." f"{func.__self__.__name__}.{func.__name__}" ) - return func + else: + return str(func) def save_task(task, broker: Broker): """ diff --git a/web-docker-compose.yaml b/web-docker-compose.yaml new file mode 100644 index 0000000..19548a3 --- /dev/null +++ b/web-docker-compose.yaml @@ -0,0 +1,11 @@ +version: '3' + +services: + web: + restart: always + command: python manage.py runserver 0.0.0.0:8000 + ports: + - "127.0.0.1:8000:8000" + build: . + volumes: + - .:/app From 0aac4e7b0d1aeedc3c1c77a13f27dd6d7619d962 Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Thu, 20 Oct 2022 17:24:17 +0200 Subject: [PATCH 02/39] Fix unclear error when function is not called correctly (#19) --- django_q/cluster.py | 12 ++++++------ django_q/tests/test_cluster.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/django_q/cluster.py b/django_q/cluster.py index 8a9046a..7382944 100644 --- a/django_q/cluster.py +++ b/django_q/cluster.py @@ -393,10 +393,10 @@ def monitor(result_queue: Queue, broker: Broker = None): info_name = get_func_repr(task['func']) if task["success"]: # log success - logger.info(_(f"Processed {info_name} ({task['name']})")) + logger.info(_(f"Processed '{info_name}' ({task['name']})")) else: # log failure - logger.error(_(f"Failed {info_name} ({task['name']}) - {task['result']}")) + logger.error(_(f"Failed '{info_name}' ({task['name']}) - {task['result']}")) logger.info(_(f"{name} stopped monitoring results")) @@ -423,7 +423,7 @@ def worker( # Get the function from the task func = task["func"] func_name = get_func_repr(func) - logger.info(_(f'{proc_name} processing {func_name} ({task["name"]})')) + logger.info(_(f"{proc_name} processing '{func_name}' ({task['name']})")) f = task["func"] # if it's not an instance try to get it from the string if not callable(task["func"]): @@ -437,12 +437,12 @@ def worker( try: res = f(*task["args"], **task["kwargs"]) result = (res, True) - except Exception as e: - result = (f"{e} : {traceback.format_exc()}", False) + except Exception: + result = (f"Could not process '{func_name}'. Check the location of the function and the args/kwargs.", False) if error_reporter: error_reporter.report() if task.get("sync", False): - raise + raise Exception(result) with timer.get_lock(): # Process result task["result"] = result[0] diff --git a/django_q/tests/test_cluster.py b/django_q/tests/test_cluster.py index 0e5aee8..57500ec 100644 --- a/django_q/tests/test_cluster.py +++ b/django_q/tests/test_cluster.py @@ -64,7 +64,7 @@ def test_sync(broker): @pytest.mark.django_db def test_sync_raise_exception(broker): - with pytest.raises(TaskError): + with pytest.raises(Exception): async_task("django_q.tests.tasks.raise_exception", broker=broker, sync=True) From 529a7de59a60a52758272ad4dd8e112f83d1c4d9 Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Thu, 20 Oct 2022 22:16:48 +0200 Subject: [PATCH 03/39] Make blessed optional (#20) --- README.rst | 1 + django_q/monitor.py | 29 +++++++++++++++++++++++------ docs/conf.py | 2 +- docs/monitor.rst | 5 +++++ poetry.lock | 34 +++++++++++++++++----------------- pyproject.toml | 4 ++-- 6 files changed, 49 insertions(+), 26 deletions(-) diff --git a/README.rst b/README.rst index 8cdee8d..d726054 100644 --- a/README.rst +++ b/README.rst @@ -195,6 +195,7 @@ Testing Running tests is easy with docker compose, it will also start the necessary databases. Just run: .. code:: bash + docker-compose -f test-services-docker-compose.yaml run --rm django-q2 poetry run pytest Locale diff --git a/django_q/monitor.py b/django_q/monitor.py index 9740418..0ce0d79 100644 --- a/django_q/monitor.py +++ b/django_q/monitor.py @@ -1,8 +1,5 @@ from datetime import timedelta -# external -from blessed import Terminal - # django from django.db import connection from django.db.models import F, Sum @@ -22,6 +19,11 @@ try: except ImportError: psutil = None +# optional +try: + from blessed import Terminal +except ImportError: + pass def get_process_mb(pid): try: @@ -31,11 +33,17 @@ def get_process_mb(pid): mb_used = "NO_PROCESS_FOUND" return mb_used +BLESSED_INSTALL_MESSAGE = "Blessed is not installed. Please install blessed to use this: https://pypi.org/project/blessed/" def monitor(run_once=False, broker=None): if not broker: broker = get_broker() - term = Terminal() + try: + term = Terminal() + except: + print(BLESSED_INSTALL_MESSAGE) + return + broker.ping() with term.fullscreen(), term.hidden_cursor(), term.cbreak(): val = None @@ -195,7 +203,12 @@ def monitor(run_once=False, broker=None): def info(broker=None): if not broker: broker = get_broker() - term = Terminal() + try: + term = Terminal() + except: + print(BLESSED_INSTALL_MESSAGE) + return + broker.ping() stat = Stat.get_all(broker=broker) # general stats @@ -294,7 +307,11 @@ def info(broker=None): def memory(run_once=False, workers=False, broker=None): if not broker: broker = get_broker() - term = Terminal() + try: + term = Terminal() + except: + print(BLESSED_INSTALL_MESSAGE) + return broker.ping() if not psutil: print(term.clear_eos()) diff --git a/docs/conf.py b/docs/conf.py index 433769c..353b8d5 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -73,7 +73,7 @@ author = 'Ilan Steemers, Stan Triepels' # The short X.Y version. version = '1.3' # The full version, including alpha/beta/rc tags. -release = '1.3.9' +release = '1.4.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/monitor.rst b/docs/monitor.rst index 1e8b655..a5be095 100644 --- a/docs/monitor.rst +++ b/docs/monitor.rst @@ -2,6 +2,11 @@ Monitor ======= .. py:currentmodule::django_q.monitor + +.. warning:: + + Blessed needs to be installed to get this to work! See: https://pypi.org/project/blessed/ + The cluster monitor shows live information about all the Q clusters connected to your project. Start the monitor with Django's `manage.py` command:: diff --git a/poetry.lock b/poetry.lock index c21311a..c19030b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -11,7 +11,7 @@ name = "ansicon" version = "1.89.0" description = "Python wrapper for loading Jason Hood's ANSICON" category = "main" -optional = false +optional = true python-versions = "*" [[package]] @@ -96,7 +96,7 @@ name = "blessed" version = "1.19.1" description = "Easy, practical library for making terminal apps, by providing an elegant, well-documented interface to Colors, Keyboard input, and screen Positioning capabilities." category = "main" -optional = false +optional = true python-versions = ">=2.7" [package.dependencies] @@ -106,14 +106,14 @@ wcwidth = ">=0.1.4" [[package]] name = "boto3" -version = "1.24.93" +version = "1.24.94" description = "The AWS SDK for Python" category = "main" optional = true python-versions = ">= 3.7" [package.dependencies] -botocore = ">=1.27.93,<1.28.0" +botocore = ">=1.27.94,<1.28.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.6.0,<0.7.0" @@ -122,7 +122,7 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.27.93" +version = "1.27.94" description = "Low-level, data-driven core of boto 3." category = "main" optional = true @@ -422,7 +422,7 @@ name = "jinxed" version = "1.2.0" description = "Jinxed Terminal Library" category = "main" -optional = false +optional = true python-versions = "*" [package.dependencies] @@ -718,7 +718,7 @@ crt = ["botocore[crt] (>=1.20.29,<2.0a.0)"] [[package]] name = "sentry-sdk" -version = "1.9.10" +version = "1.10.0" description = "Python client for Sentry (https://sentry.io)" category = "main" optional = true @@ -753,7 +753,7 @@ name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" category = "main" -optional = false +optional = true python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] @@ -917,7 +917,7 @@ name = "wcwidth" version = "0.2.5" description = "Measures the displayed width of unicode strings in a terminal" category = "main" -optional = false +optional = true python-versions = "*" [[package]] @@ -956,12 +956,12 @@ build-backend = [] requires = [] rollbar = ["django-q-rollbar"] sentry = ["django-q-sentry"] -testing = ["django-redis", "croniter", "hiredis", "psutil", "iron-mq", "boto3", "pymongo"] +testing = ["django-redis", "croniter", "hiredis", "psutil", "iron-mq", "boto3", "pymongo", "blessed"] [metadata] lock-version = "1.1" python-versions = ">=3.8.14, <4" -content-hash = "3164c7b86a93925523372abdfa8f2a88f5dbda725bd0576c0bf429de06a631db" +content-hash = "ac947d27d316a58fe8f86837360e1328a6771fa740f93841d610e26b85ce859a" [metadata.files] alabaster = [ @@ -1034,12 +1034,12 @@ blessed = [ {file = "blessed-1.19.1.tar.gz", hash = "sha256:9a0d099695bf621d4680dd6c73f6ad547f6a3442fbdbe80c4b1daa1edbc492fc"}, ] boto3 = [ - {file = "boto3-1.24.93-py3-none-any.whl", hash = "sha256:db9f04eeb942e7998d1971c35e1658e2d9d6687166a4ebc036f484a71a79bbeb"}, - {file = "boto3-1.24.93.tar.gz", hash = "sha256:7881fc380f2f489ae9b3a2f2448334aef9f7be58d85a7a0e8c10458247b09afa"}, + {file = "boto3-1.24.94-py3-none-any.whl", hash = "sha256:f13db0beb3c9fe2cc1ed0f031189f144610d2909b5874a616e77b0bd1ae3b686"}, + {file = "boto3-1.24.94.tar.gz", hash = "sha256:f4842b395d1580454756622069f4ca0408993885ecede967001d2c101201cdfa"}, ] botocore = [ - {file = "botocore-1.27.93-py3-none-any.whl", hash = "sha256:7648891692c3c69038eef902f8d64af59f91211f713fe9072fb83ecdd310dbbc"}, - {file = "botocore-1.27.93.tar.gz", hash = "sha256:d5200f7b9150cdb91c9d3994980870d7bb4554e19c4d9d847f64626d8ceacf95"}, + {file = "botocore-1.27.94-py3-none-any.whl", hash = "sha256:8237c070d2ab29fac4fbcfe9dd2e84e0ee147402e0fed3ac1629f92459c7f1d2"}, + {file = "botocore-1.27.94.tar.gz", hash = "sha256:572224608a0b7662966fc303b768e2eba61bf53bdbf314481cd9e63a0d8e1a66"}, ] certifi = [ {file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"}, @@ -1465,8 +1465,8 @@ s3transfer = [ {file = "s3transfer-0.6.0.tar.gz", hash = "sha256:2ed07d3866f523cc561bf4a00fc5535827981b117dd7876f036b0c1aca42c947"}, ] sentry-sdk = [ - {file = "sentry-sdk-1.9.10.tar.gz", hash = "sha256:4fbace9a763285b608c06f01a807b51acb35f6059da6a01236654e08b0ee81ff"}, - {file = "sentry_sdk-1.9.10-py2.py3-none-any.whl", hash = "sha256:2469240f6190aaebcb453033519eae69cfe8cc602065b4667e18ee14fc1e35dc"}, + {file = "sentry-sdk-1.10.0.tar.gz", hash = "sha256:1b965bcdbfe52321bb1307c7c93c74035afdbfceb5f585f01a963327c5befc4e"}, + {file = "sentry_sdk-1.10.0-py2.py3-none-any.whl", hash = "sha256:8c648e96e0e2ec5e17ca75a28c442e2f523453fa7cf761ec093f4a656153490e"}, ] six = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, diff --git a/pyproject.toml b/pyproject.toml index 85191d8..2e0d414 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,9 +46,9 @@ include = ['CHANGELOG.md'] [tool.poetry.dependencies] python = ">=3.8.14, <4" django = ">=3.2" -blessed = "^1.19.1" django-picklefield = "^3.1" +blessed = { version = "^1.19.1", optional = true } hiredis = { version = "^2.0.0", optional = true } redis = { version = "^4.3.4", optional = true } psutil = { version = "^5.9.2", optional = true } @@ -72,7 +72,7 @@ isort = {extras = ["requirements_deprecated_finder"], version = "^5.10.1"} [tool.poetry.extras] requires = ["poetry_core>=1.0.0"] build-backend = ["poetry.core.masonry.api"] -testing = ["django-redis", "croniter", "hiredis", "psutil", "iron-mq", "boto3", "pymongo"] +testing = ["django-redis", "croniter", "hiredis", "psutil", "iron-mq", "boto3", "pymongo", "blessed"] rollbar = ["django-q-rollbar"] sentry = ["django-q-sentry"] From 0ddef44400e7a54e2219c9574e7cf81718753139 Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Fri, 21 Oct 2022 00:04:58 +0200 Subject: [PATCH 04/39] Bump version and docs fixes (#21) --- README.rst | 6 +++++- docs/admin.rst | 4 ++-- docs/conf.py | 4 ++-- docs/configure.rst | 2 +- docs/index.rst | 2 +- docs/install.rst | 8 ++++---- docs/monitor.rst | 2 +- pyproject.toml | 2 +- 8 files changed, 17 insertions(+), 13 deletions(-) diff --git a/README.rst b/README.rst index d726054..0bd8215 100644 --- a/README.rst +++ b/README.rst @@ -27,7 +27,6 @@ Requirements - `Django `__ > = 3.2 - `Django-picklefield `__ -- `Blessed `__ Tested with: Python 3.7, 3.8, 3.9, 3.10 Django 3.2.X and 4.1.X @@ -93,6 +92,11 @@ For full configuration options, see the `configuration documentation + + Start a cluster with:: $ python manage.py qcluster diff --git a/docs/admin.rst b/docs/admin.rst index a774c4c..d51fe72 100644 --- a/docs/admin.rst +++ b/docs/admin.rst @@ -4,8 +4,8 @@ Admin pages =========== -Django Q does not use custom pages, but instead leverages what is offered by Django's model admin by default. -When you open Django Q's admin pages you will see three models: +Django Q2 does not use custom pages, but instead leverages what is offered by Django's model admin by default. +When you open Django Q2's admin pages you will see three models: Successful tasks ---------------- diff --git a/docs/conf.py b/docs/conf.py index 353b8d5..469ac4a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -71,9 +71,9 @@ author = 'Ilan Steemers, Stan Triepels' # built documents. # # The short X.Y version. -version = '1.3' +version = '1.4' # The full version, including alpha/beta/rc tags. -release = '1.4.0' +release = '1.4.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/configure.rst b/docs/configure.rst index 01241f3..32d6f11 100644 --- a/docs/configure.rst +++ b/docs/configure.rst @@ -143,7 +143,7 @@ Limits the amount of successful tasks saved to Django. - Failures are always saved. save_limit_per -~~~~~~~~~~~~~ +~~~~~~~~~~~~~~ The above ``save_limit`` for successful tasks can be fine tuned per task type using - Set to ``"group"`` to store the tasks per group diff --git a/docs/index.rst b/docs/index.rst index 02628be..d5a2dea 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -27,7 +27,7 @@ Features - Rollbar and Sentry support -Django Q is tested with: Python 3.7, 3.8, 3.9 and 3.10, Django 2.2.x and 3.2.x +Django Q2 is tested with: Python 3.7, 3.8, 3.9 and 3.10, Django 2.2.x and 3.2.x Currently available in English, German and French. diff --git a/docs/install.rst b/docs/install.rst index 2a110d5..3e72ffe 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -38,13 +38,13 @@ Django Q2 is tested for Python 3.7, 3.8, 3.9 and 3.10 Used to store args, kwargs and result objects in the database. -- `Blessed `__ - - This feature-filled fork of Erik Rose's blessings project provides the terminal layout of the monitor. - Optional ~~~~~~~~ +- `Blessed `__ is used to display the statistics in the terminal:: + + $ pip install blessed + - `Redis-py `__ client by Andy McCurdy is used to interface with both the Redis:: $ pip install redis diff --git a/docs/monitor.rst b/docs/monitor.rst index a5be095..d142195 100644 --- a/docs/monitor.rst +++ b/docs/monitor.rst @@ -4,9 +4,9 @@ Monitor .. warning:: - Blessed needs to be installed to get this to work! See: https://pypi.org/project/blessed/ + The cluster monitor shows live information about all the Q clusters connected to your project. Start the monitor with Django's `manage.py` command:: diff --git a/pyproject.toml b/pyproject.toml index 2e0d414..06e3e8b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "django-q2" -version = "1.4.0" +version = "1.4.1" packages = [ { include = "django_q" }, ] From 19d434ed4f1583e5c4ae85ef44c1d767d34c0b79 Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Fri, 21 Oct 2022 01:29:21 +0200 Subject: [PATCH 05/39] Make redis dependency optional and update boto3 (#22) --- docs/conf.py | 2 +- poetry.lock | 18 +++++++++--------- pyproject.toml | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 469ac4a..f78a072 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -73,7 +73,7 @@ author = 'Ilan Steemers, Stan Triepels' # The short X.Y version. version = '1.4' # The full version, including alpha/beta/rc tags. -release = '1.4.1' +release = '1.4.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/poetry.lock b/poetry.lock index c19030b..8dade84 100644 --- a/poetry.lock +++ b/poetry.lock @@ -106,14 +106,14 @@ wcwidth = ">=0.1.4" [[package]] name = "boto3" -version = "1.24.94" +version = "1.24.95" description = "The AWS SDK for Python" category = "main" optional = true python-versions = ">= 3.7" [package.dependencies] -botocore = ">=1.27.94,<1.28.0" +botocore = ">=1.27.95,<1.28.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.6.0,<0.7.0" @@ -122,7 +122,7 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.27.94" +version = "1.27.95" description = "Low-level, data-driven core of boto 3." category = "main" optional = true @@ -956,12 +956,12 @@ build-backend = [] requires = [] rollbar = ["django-q-rollbar"] sentry = ["django-q-sentry"] -testing = ["django-redis", "croniter", "hiredis", "psutil", "iron-mq", "boto3", "pymongo", "blessed"] +testing = ["django-redis", "croniter", "hiredis", "psutil", "iron-mq", "boto3", "pymongo", "blessed", "redis"] [metadata] lock-version = "1.1" python-versions = ">=3.8.14, <4" -content-hash = "ac947d27d316a58fe8f86837360e1328a6771fa740f93841d610e26b85ce859a" +content-hash = "a5007f22e20151981df5e8e478ceea4b7c3d1932b0c1cef14b9cec39f04bcc84" [metadata.files] alabaster = [ @@ -1034,12 +1034,12 @@ blessed = [ {file = "blessed-1.19.1.tar.gz", hash = "sha256:9a0d099695bf621d4680dd6c73f6ad547f6a3442fbdbe80c4b1daa1edbc492fc"}, ] boto3 = [ - {file = "boto3-1.24.94-py3-none-any.whl", hash = "sha256:f13db0beb3c9fe2cc1ed0f031189f144610d2909b5874a616e77b0bd1ae3b686"}, - {file = "boto3-1.24.94.tar.gz", hash = "sha256:f4842b395d1580454756622069f4ca0408993885ecede967001d2c101201cdfa"}, + {file = "boto3-1.24.95-py3-none-any.whl", hash = "sha256:05818ed61af104f28f039592c5c54d802a0398b1f158c2d485ec86352b48033f"}, + {file = "boto3-1.24.95.tar.gz", hash = "sha256:285d29042c1684f8fc68492ddf20180d28b94aac1f19dd7161bcad3067c01314"}, ] botocore = [ - {file = "botocore-1.27.94-py3-none-any.whl", hash = "sha256:8237c070d2ab29fac4fbcfe9dd2e84e0ee147402e0fed3ac1629f92459c7f1d2"}, - {file = "botocore-1.27.94.tar.gz", hash = "sha256:572224608a0b7662966fc303b768e2eba61bf53bdbf314481cd9e63a0d8e1a66"}, + {file = "botocore-1.27.95-py3-none-any.whl", hash = "sha256:04ff12a8d1d0687a1f1c2dfad5b6fc9f5a81de4b639cf9c9e41fee9449680fd4"}, + {file = "botocore-1.27.95.tar.gz", hash = "sha256:0b90945aa7080179a0c4941a3809ce4df30792931e16b9b6ef3c739c4f2b7a59"}, ] certifi = [ {file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"}, diff --git a/pyproject.toml b/pyproject.toml index 06e3e8b..1c560ac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "django-q2" -version = "1.4.1" +version = "1.4.2" packages = [ { include = "django_q" }, ] @@ -50,7 +50,6 @@ django-picklefield = "^3.1" blessed = { version = "^1.19.1", optional = true } hiredis = { version = "^2.0.0", optional = true } -redis = { version = "^4.3.4", optional = true } psutil = { version = "^5.9.2", optional = true } django-redis = { version = "^5.2.0", optional = true } iron-mq = { version = "^0.9", optional = true } @@ -59,6 +58,7 @@ pymongo = { version = "^4.2.0", optional = true } croniter = { version = "^1.3.7", optional = true } django-q-rollbar = {version = ">=0.1", optional = true} django-q-sentry = {version = ">=0.1", optional = true} +redis = {version = "^4.3.4", optional = true} [tool.poetry.dev-dependencies] @@ -72,7 +72,7 @@ isort = {extras = ["requirements_deprecated_finder"], version = "^5.10.1"} [tool.poetry.extras] requires = ["poetry_core>=1.0.0"] build-backend = ["poetry.core.masonry.api"] -testing = ["django-redis", "croniter", "hiredis", "psutil", "iron-mq", "boto3", "pymongo", "blessed"] +testing = ["django-redis", "croniter", "hiredis", "psutil", "iron-mq", "boto3", "pymongo", "blessed", "redis"] rollbar = ["django-q-rollbar"] sentry = ["django-q-sentry"] From f62bd7b6b47f714463b172bbed90878c6c7f2dcc Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Thu, 27 Oct 2022 02:08:08 +0200 Subject: [PATCH 06/39] Fix install docs: update q to q2 (#25) --- docs/install.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install.rst b/docs/install.rst index 3e72ffe..7d6c35b 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -4,7 +4,7 @@ Installation - Install the latest version with pip:: - $ pip install django-q + $ pip install django-q2 - Add :mod:`django_q` to ``INSTALLED_APPS`` in your projects :file:`settings.py`:: From 6f19b3d270f709c0fd587fceba485283a0143dfa Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Sat, 5 Nov 2022 02:45:44 +0100 Subject: [PATCH 07/39] Fix: func reference in admin (#28) --- django_q/cluster.py | 15 +-------------- django_q/models.py | 3 ++- django_q/utils.py | 16 ++++++++++++++-- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/django_q/cluster.py b/django_q/cluster.py index 7382944..4848a4c 100644 --- a/django_q/cluster.py +++ b/django_q/cluster.py @@ -1,6 +1,5 @@ # Standard import ast -import inspect import pydoc import signal import socket @@ -44,7 +43,7 @@ from django_q.signals import post_execute, pre_execute from django_q.signing import BadSignature, SignedPackage from django_q.status import Stat, Status -from .utils import add_months, add_years +from .utils import add_months, add_years, get_func_repr class Cluster: @@ -456,18 +455,6 @@ def worker( break logger.info(_(f"{proc_name} stopped doing work")) -def get_func_repr(func): - # convert func to string - if inspect.isfunction(func): - return f"{func.__module__}.{func.__name__}" - elif inspect.ismethod(func) and hasattr(func.__self__, '__name__'): - return ( - f"{func.__self__.__module__}." - f"{func.__self__.__name__}.{func.__name__}" - ) - else: - return str(func) - def save_task(task, broker: Broker): """ Saves the task package to Django or the cache diff --git a/django_q/models.py b/django_q/models.py index de9ef27..d90c8d0 100644 --- a/django_q/models.py +++ b/django_q/models.py @@ -15,6 +15,7 @@ from picklefield.fields import dbsafe_decode # Local from django_q.conf import croniter from django_q.signing import SignedPackage +from .utils import get_func_repr class Task(models.Model): @@ -241,7 +242,7 @@ class OrmQ(models.Model): return SignedPackage.loads(self.payload) def func(self): - return self.task()["func"] + return get_func_repr(self.task()["func"]) def task_id(self): return self.task()["id"] diff --git a/django_q/utils.py b/django_q/utils.py index dff6c89..eed72be 100644 --- a/django_q/utils.py +++ b/django_q/utils.py @@ -1,6 +1,5 @@ -import datetime +import inspect from datetime import date -from django.utils.timezone import make_aware import calendar # credits: https://stackoverflow.com/a/4131114 @@ -28,3 +27,16 @@ def add_years(d, years): new_date = d + (date(d.year + years, 3, 1) - date(d.year, 3, 1)) return d.replace(year=new_date.year, month=new_date.month, day=new_date.day) + +def get_func_repr(func): + # convert func to string + if inspect.isfunction(func): + return f"{func.__module__}.{func.__name__}" + elif inspect.ismethod(func) and hasattr(func.__self__, '__name__'): + return ( + f"{func.__self__.__module__}." + f"{func.__self__.__name__}.{func.__name__}" + ) + else: + return str(func) + From 167c3485091bc149cfe7adb1f981f72fb3b6dd0b Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Sat, 5 Nov 2022 23:06:34 +0100 Subject: [PATCH 08/39] Update changelog and readme (#29) Added changes from the previous versions and diff between Q and Q2 --- CHANGELOG.md | 40 ++++++++++++++++++++++++++++++++++++++-- README.rst | 12 ++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7204555..f16f435 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,44 @@ # Changelog -## [Unreleased](https://github.com/koed00/django-q/tree/HEAD) +## [Unreleased](https://github.com/GDay/django-q2/tree/HEAD) -[Full Changelog](https://github.com/koed00/django-q/compare/v1.3.9...HEAD) +**Merged pull requests:** + +- Fix: func reference in admin https://github.com/GDay/django-q2/pull/28 + + +## [v1.4.2](https://github.com/GDay/django-q2/tree/v1.4.2) (2022-11-22) + +**Merged pull requests:** + +- Make redis dependency optional and update boto3 #22 + +## [v1.4.1](https://github.com/GDay/django-q2/tree/v1.4.1) (2022-11-21) + +**Merged pull requests:** + +- Fix typo configure.rst https://github.com/GDay/django-q2/pull/1 +- Update dependencies https://github.com/GDay/django-q2/pull/2 +- Show function name in log when running task https://github.com/GDay/django-q2/pull/3 +- Codecov -> Coveralls https://github.com/GDay/django-q2/pull/4 +- Fix: readthedocs config file https://github.com/GDay/django-q2/pull/5 +- Docs updates https://github.com/GDay/django-q2/pull/6 +- Feat: Release plan to pypi https://github.com/GDay/django-q2/pull/7 +- Feat: Turkish translations https://github.com/GDay/django-q2/pull/8 +- Fix: Connection issues with CONN_MAX_AGE > 0 https://github.com/GDay/django-q2/pull/9 +- Replace use of eval() by ast.parse() + ast.literal_eval() https://github.com/GDay/django-q2/pull/10 +- Admin improvements https://github.com/GDay/django-q2/pull/11 +- Save limit per group/func/name https://github.com/GDay/django-q2/pull/12 +- Use logger.hasHandlers() to setup fallback logging https://github.com/GDay/django-q2/pull/13 +- allow atomic on external db https://github.com/GDay/django-q2/pull/14 +- Fix install command and remove old warnings https://github.com/GDay/django-q2/pull/16 +- Remove arrow dependency https://github.com/GDay/django-q2/pull/17 +- Remove funding file, add docker/compose for development project and fix https://github.com/GDay/django-q2/pull/18 +- Fix unclear error when function is not called correctly https://github.com/GDay/django-q2/pull/19 +- Remove blessed dependency https://github.com/GDay/django-q2/pull/20 +- Release new version and docs fixes https://github.com/GDay/django-q2/pull/21 + +## v1.4.0 **Closed issues:** diff --git a/README.rst b/README.rst index 0bd8215..7ca2d4b 100644 --- a/README.rst +++ b/README.rst @@ -22,6 +22,18 @@ Features - Redis, IronMQ, SQS, MongoDB or ORM - Rollbar and Sentry support +Changes compared to the original Django-Q: + +- Dropped support for Disque (hasn't been updated in a long time) +- Dropped Redis, Arrow and Blessed dependencies +- Updated all current dependencies +- Added tests for Django 4.x +- Added Turkish language +- Improved admin area +- Fixed a lot of issues + +See the `changelog `__ for all changes. + Requirements ~~~~~~~~~~~~ From f0cb10bc371720a9882e2c734ef3b3ff5dc53dd8 Mon Sep 17 00:00:00 2001 From: Mikhail Krassavin Date: Mon, 7 Nov 2022 22:29:29 +0600 Subject: [PATCH 09/39] Add Python 3.11 support and tests, remove Python 3.7 (#31) --- .github/workflows/test.yml | 2 +- README.rst | 2 +- docs/index.rst | 2 +- docs/install.rst | 4 ++-- pyproject.toml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1a58fa6..af11374 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [ "3.8", "3.9", "3.10" ] + python-version: [ "3.8", "3.9", "3.10", "3.11" ] django: [ "3.2", "4.1" ] services: diff --git a/README.rst b/README.rst index 7ca2d4b..6a3c022 100644 --- a/README.rst +++ b/README.rst @@ -40,7 +40,7 @@ Requirements - `Django `__ > = 3.2 - `Django-picklefield `__ -Tested with: Python 3.7, 3.8, 3.9, 3.10 Django 3.2.X and 4.1.X +Tested with: Python 3.8, 3.9, 3.10, 3.11 Django 3.2.X and 4.1.X Brokers ~~~~~~~ diff --git a/docs/index.rst b/docs/index.rst index d5a2dea..15ca5c7 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -27,7 +27,7 @@ Features - Rollbar and Sentry support -Django Q2 is tested with: Python 3.7, 3.8, 3.9 and 3.10, Django 2.2.x and 3.2.x +Django Q2 is tested with: Python 3.8, 3.9 and 3.10, 3.11, Django 3.2.x and 4.1.x Currently available in English, German and French. diff --git a/docs/install.rst b/docs/install.rst index 7d6c35b..e862e68 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -27,7 +27,7 @@ Installation Requirements ------------ -Django Q2 is tested for Python 3.7, 3.8, 3.9 and 3.10 +Django Q2 is tested for Python 3.8, 3.9, 3.10 and 3.11 - `Django `__ @@ -125,7 +125,7 @@ Other known issues are: Python ~~~~~~ -Current tests are performed with 3.7, 3.8, 3.9 and 3.10 +Current tests are performed with 3.8, 3.9, 3.10 and 3.11 If you do encounter any regressions with earlier versions, please submit an issue on `github `__ Open-source packages diff --git a/pyproject.toml b/pyproject.toml index 1c560ac..13f4f79 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,10 +26,10 @@ classifiers = [ 'Operating System :: MacOS', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', 'Topic :: Internet :: WWW/HTTP', 'Topic :: System :: Distributed Computing', 'Topic :: Software Development :: Libraries :: Python Modules', From 1764c5c8ae4022589b441aaf79253a72f5fae222 Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Mon, 7 Nov 2022 17:47:05 +0100 Subject: [PATCH 10/39] Release 1.4.3 (#32) Update changelog and bump version number --- CHANGELOG.md | 8 ++++++-- docs/conf.py | 2 +- pyproject.toml | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f16f435..204b686 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,18 +2,22 @@ ## [Unreleased](https://github.com/GDay/django-q2/tree/HEAD) + +## [v1.4.3](https://github.com/GDay/django-q2/tree/v1.4.3) (2022-11-07) + **Merged pull requests:** - Fix: func reference in admin https://github.com/GDay/django-q2/pull/28 +- Add python 3.11 support and remove 3.7 (as it was never supported by this package anyway) -## [v1.4.2](https://github.com/GDay/django-q2/tree/v1.4.2) (2022-11-22) +## [v1.4.2](https://github.com/GDay/django-q2/tree/v1.4.2) (2022-10-22) **Merged pull requests:** - Make redis dependency optional and update boto3 #22 -## [v1.4.1](https://github.com/GDay/django-q2/tree/v1.4.1) (2022-11-21) +## [v1.4.1](https://github.com/GDay/django-q2/tree/v1.4.1) (2022-10-21) **Merged pull requests:** diff --git a/docs/conf.py b/docs/conf.py index f78a072..e643bed 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -73,7 +73,7 @@ author = 'Ilan Steemers, Stan Triepels' # The short X.Y version. version = '1.4' # The full version, including alpha/beta/rc tags. -release = '1.4.2' +release = '1.4.3' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pyproject.toml b/pyproject.toml index 13f4f79..de2cc15 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "django-q2" -version = "1.4.2" +version = "1.4.3" packages = [ { include = "django_q" }, ] From 17205549eb667d8b993eb485e468a36100d96026 Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Wed, 9 Nov 2022 00:41:12 +0100 Subject: [PATCH 11/39] Fix baseconv/base62 deprecation warning for Django 5.x (#34) --- CHANGELOG.md | 3 ++- django_q/core_signing.py | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 204b686..ec11595 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## [Unreleased](https://github.com/GDay/django-q2/tree/HEAD) +**Merged pull requests:** +- Fix: Deprecation warning for Django 5.x ## [v1.4.3](https://github.com/GDay/django-q2/tree/v1.4.3) (2022-11-07) @@ -10,7 +12,6 @@ - Fix: func reference in admin https://github.com/GDay/django-q2/pull/28 - Add python 3.11 support and remove 3.7 (as it was never supported by this package anyway) - ## [v1.4.2](https://github.com/GDay/django-q2/tree/v1.4.2) (2022-10-22) **Merged pull requests:** diff --git a/django_q/core_signing.py b/django_q/core_signing.py index 03e83a4..6d2d899 100644 --- a/django_q/core_signing.py +++ b/django_q/core_signing.py @@ -6,7 +6,11 @@ from django.core.signing import BadSignature, JSONSerializer, SignatureExpired from django.core.signing import Signer as Sgnr from django.core.signing import TimestampSigner as TsS from django.core.signing import b64_decode, dumps -from django.utils import baseconv +try: + from django.core.signing import base62 +except ImportError: + # For django < 4.0 + from django.utils.baseconv import base62 from django.utils.crypto import constant_time_compare from django.utils.encoding import force_bytes, force_str @@ -69,7 +73,7 @@ class TimestampSigner(Signer, TsS): """ result = super(TimestampSigner, self).unsign(value) value, timestamp = result.rsplit(self.sep, 1) - timestamp = baseconv.base62.decode(timestamp) + timestamp = base62.decode(timestamp) if max_age is not None: if isinstance(max_age, datetime.timedelta): max_age = max_age.total_seconds() From 542e04db544476c84dc3699da89eafb84c6023a1 Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Sun, 13 Nov 2022 01:00:11 +0100 Subject: [PATCH 12/39] Feat: Add biweekly and bimonthly and fix translations (#36) --- .github/workflows/release.yml | 7 +- CHANGELOG.md | 4 +- django_q/cluster.py | 70 +-- django_q/conf.py | 2 +- django_q/locale/de/LC_MESSAGES/django.mo | Bin 4333 -> 0 bytes django_q/locale/de/LC_MESSAGES/django.po | 512 ++++++++++-------- django_q/locale/fr/LC_MESSAGES/django.mo | Bin 6405 -> 0 bytes django_q/locale/fr/LC_MESSAGES/django.po | 434 ++++++++++----- django_q/locale/tr/LC_MESSAGES/django.po | 401 ++++++++------ .../0015_alter_schedule_schedule_type.py | 18 + django_q/models.py | 6 +- django_q/monitor.py | 19 +- django_q/signals.py | 6 +- django_q/tests/test_scheduler.py | 24 + docs/schedules.rst | 15 +- 15 files changed, 906 insertions(+), 612 deletions(-) delete mode 100644 django_q/locale/de/LC_MESSAGES/django.mo delete mode 100644 django_q/locale/fr/LC_MESSAGES/django.mo create mode 100644 django_q/migrations/0015_alter_schedule_schedule_type.py diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d9ab35e..8e97b7a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,8 +22,11 @@ jobs: - name: Install dependencies run: | - python -m pip install -U pip setuptools poetry - python -m pip install poetry + apt-get update + apt-get -y install gettext + python -m pip install pip setuptools django poetry + # compile messages to get .mo files + django-admin compilemessages - name: Build and publish package if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') run: poetry --build --username=__token__ --password=${{ secrets.PYPI_TOKEN }} publish diff --git a/CHANGELOG.md b/CHANGELOG.md index ec11595..4debe71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,9 @@ ## [Unreleased](https://github.com/GDay/django-q2/tree/HEAD) **Merged pull requests:** -- Fix: Deprecation warning for Django 5.x +- Fix: Deprecation warning for Django 5.x https://github.com/GDay/django-q2/pull/34 +- Feat: Add biweekly and bimonthly https://github.com/GDay/django-q2/pull/36 +- Fix: Fix all translation strings and remove compiled https://github.com/GDay/django-q2/pull/36 ## [v1.4.3](https://github.com/GDay/django-q2/tree/v1.4.3) (2022-11-07) diff --git a/django_q/cluster.py b/django_q/cluster.py index 4848a4c..1e95390 100644 --- a/django_q/cluster.py +++ b/django_q/cluster.py @@ -74,7 +74,7 @@ class Cluster: ), ) self.sentinel.start() - logger.info(_(f"Q Cluster {self.name} starting.")) + logger.info(_("Q Cluster %(name)s starting.") % {'name': self.name}) while not self.start_event.is_set(): sleep(0.1) return self.pid @@ -82,10 +82,10 @@ class Cluster: def stop(self) -> bool: if not self.sentinel.is_alive(): return False - logger.info(_(f"Q Cluster {self.name} stopping.")) + logger.info(_("Q Cluster %(name)s stopping.") % {'name': self.name}) self.stop_event.set() self.sentinel.join() - logger.info(_(f"Q Cluster {self.name} has stopped.")) + logger.info(_("Q Cluster %(name)s has stopped.") % {'name': self.name}) self.start_event = None self.stop_event = None return True @@ -93,8 +93,8 @@ class Cluster: def sig_handler(self, signum, frame): logger.debug( _( - f'{current_process().name} got signal {Conf.SIGNAL_NAMES.get(signum, "UNKNOWN")}' - ) + '%(name)s got signal %(signal)s' + ) % {'name': current_process().name, 'signal': Conf.SIGNAL_NAMES.get(signum, "UNKNOWN")} ) self.stop() @@ -216,21 +216,21 @@ class Sentinel: db.connections.close_all() if process == self.monitor: self.monitor = self.spawn_monitor() - logger.error(_(f"reincarnated monitor {process.name} after sudden death")) + logger.error(_("reincarnated monitor %(name)s after sudden death") % {'name': process.name}) elif process == self.pusher: self.pusher = self.spawn_pusher() - logger.error(_(f"reincarnated pusher {process.name} after sudden death")) + logger.error(_("reincarnated pusher %(name)s after sudden death") % {'name': process.name}) else: self.pool.remove(process) self.spawn_worker() if process.timer.value == 0: # only need to terminate on timeout, otherwise we risk destabilizing the queues process.terminate() - logger.warning(_(f"reincarnated worker {process.name} after timeout")) + logger.warning(_("reincarnated worker %(name)s after timeout") % {'name': process.name}) elif int(process.timer.value) == -2: - logger.info(_(f"recycled worker {process.name}")) + logger.info(_("recycled worker %(name)s") % {'name': process.name}) else: - logger.error(_(f"reincarnated worker {process.name} after death")) + logger.error(_("reincarnated worker %(name)s after death") % {'name': process.name}) self.reincarnations += 1 @@ -253,12 +253,12 @@ class Sentinel: def guard(self): logger.info( _( - f"{current_process().name} guarding cluster {humanize(self.cluster_id.hex)}" - ) + "%(name)s guarding cluster %(cluster_name)s" + ) % {'name': current_process().name, 'cluster_name': humanize(self.cluster_id.hex)} ) self.start_event.set() Stat(self).save() - logger.info(_(f"Q Cluster {humanize(self.cluster_id.hex)} running.")) + logger.info(_("Q Cluster %(cluster_name)s running.") % {'cluster_name': humanize(self.cluster_id.hex)}) counter = 0 cycle = Conf.GUARD_CYCLE # guard loop sleep in seconds # Guard loop. Runs at least once @@ -292,7 +292,7 @@ class Sentinel: def stop(self): Stat(self).save() name = current_process().name - logger.info(_(f"{name} stopping cluster processes")) + logger.info(_("%(name)s stopping cluster processes") % {'name': name}) # Stopping pusher self.event_out.set() # Wait for it to stop @@ -317,7 +317,7 @@ class Sentinel: self.result_queue.close() # Wait for the result queue to empty self.result_queue.join_thread() - logger.info(_(f"{name} waiting for the monitor.")) + logger.info(_("%(name)s waiting for the monitor.") % {'name': name}) # Wait for everything to close or time out count = 0 if not self.timeout: @@ -339,7 +339,7 @@ def pusher(task_queue: Queue, event: Event, broker: Broker = None): """ if not broker: broker = get_broker() - logger.info(_(f"{current_process().name} pushing tasks at {current_process().pid}")) + logger.info(_("%(process_name)s pushing tasks at %(id)s") % {'process_name': current_process().name, 'id': current_process().pid}) while True: try: task_set = broker.dequeue() @@ -360,10 +360,10 @@ def pusher(task_queue: Queue, event: Event, broker: Broker = None): continue task["ack_id"] = ack_id task_queue.put(task) - logger.debug(_(f"queueing from {broker.list_key}")) + logger.debug(_("queueing from %(list_key)s") % {'list_key': broker.list_key}) if event.is_set(): break - logger.info(_(f"{current_process().name} stopped pushing tasks")) + logger.info(_("%(name)s stopped pushing tasks") % {'name': current_process().name}) def monitor(result_queue: Queue, broker: Broker = None): @@ -375,7 +375,7 @@ def monitor(result_queue: Queue, broker: Broker = None): if not broker: broker = get_broker() name = current_process().name - logger.info(_(f"{name} monitoring at {current_process().pid}")) + logger.info(_("%(name)s monitoring at %(id)s") % {'name': name, 'id': current_process().pid}) for task in iter(result_queue.get, "STOP"): # save the result if task.get("cached", False): @@ -392,11 +392,11 @@ def monitor(result_queue: Queue, broker: Broker = None): info_name = get_func_repr(task['func']) if task["success"]: # log success - logger.info(_(f"Processed '{info_name}' ({task['name']})")) + logger.info(_("Processed '%(info_name)s' (%(task_name)s)") % {'info_name': info_name, 'task_name': task['name']}) else: # log failure - logger.error(_(f"Failed '{info_name}' ({task['name']}) - {task['result']}")) - logger.info(_(f"{name} stopped monitoring results")) + logger.error(_("Failed '%(info_name)s' (%(task_name)s) - %(task_result)s") % {'info_name': info_name, 'task_name': task['name'], 'task_result': task['result']}) + logger.info(_("%(name)s stopped monitoring results") % {'name': name}) def worker( @@ -410,7 +410,7 @@ def worker( :type timer: multiprocessing.Value """ proc_name = current_process().name - logger.info(_(f"{proc_name} ready for work at {current_process().pid}")) + logger.info(_("%(proc_name)s ready for work at %(id)s") % {'proc_name': proc_name, 'id': current_process().pid}) task_count = 0 if timeout is None: timeout = -1 @@ -422,7 +422,7 @@ def worker( # Get the function from the task func = task["func"] func_name = get_func_repr(func) - logger.info(_(f"{proc_name} processing '{func_name}' ({task['name']})")) + logger.info(_("%(proc_name)s processing '%(func_name)s' (%(task_name)s)") % {'proc_name': proc_name, 'func_name': func_name, 'task_name': task['name']}) f = task["func"] # if it's not an instance try to get it from the string if not callable(task["func"]): @@ -437,7 +437,7 @@ def worker( res = f(*task["args"], **task["kwargs"]) result = (res, True) except Exception: - result = (f"Could not process '{func_name}'. Check the location of the function and the args/kwargs.", False) + result = (_("Could not process '%(func_name)s'. Check the location of the function and the args/kwargs.") % {'func_name': func_name}, False) if error_reporter: error_reporter.report() if task.get("sync", False): @@ -453,7 +453,7 @@ def worker( if task_count == Conf.RECYCLE or rss_check(): timer.value = -2 # Recycled break - logger.info(_(f"{proc_name} stopped doing work")) + logger.info(_("%(proc_name)s stopped doing work") % {'proc_name': proc_name}) def save_task(task, broker: Broker): """ @@ -632,8 +632,12 @@ def scheduler(broker: Broker = None): next_run = next_run + timedelta(days=1) elif s.schedule_type == s.WEEKLY: next_run = next_run + timedelta(weeks=1) + elif s.schedule_type == s.BIWEEKLY: + next_run = next_run + timedelta(weeks=2) elif s.schedule_type == s.MONTHLY: next_run = add_months(next_run, 1) + elif s.schedule_type == s.BIMONTHLY: + next_run = add_months(next_run, 2) elif s.schedule_type == s.QUARTERLY: next_run = add_months(next_run, 3) elif s.schedule_type == s.YEARLY: @@ -665,14 +669,14 @@ def scheduler(broker: Broker = None): if not s.task: logger.error( _( - f"{current_process().name} failed to create a task from schedule [{s.name or s.id}]" - ) + "%(process_name)s failed to create a task from schedule [%(schedule)s]" + ) % {'process_name': current_process().name, 'schedule': s.name or s.id} ) else: logger.info( _( - f"{current_process().name} created a task from schedule [{s.name or s.id}]" - ) + "%(process_name)s created a task from schedule [%(schedule)s]" + ) % {'process_name': current_process().name, 'schedule': s.name or s.id} ) # default behavior is to delete a ONCE schedule if s.schedule_type == s.ONCE: @@ -711,12 +715,12 @@ def set_cpu_affinity(n: int, process_ids: list, actual: bool = not Conf.TESTING) """ # check if we have the psutil module if not psutil: - logger.warning("Skipping cpu affinity because psutil was not found.") + logger.warning(_("Skipping cpu affinity because psutil was not found.")) return # check if the platform supports cpu_affinity if actual and not hasattr(psutil.Process(process_ids[0]), "cpu_affinity"): logger.warning( - "Faking cpu affinity because it is not supported on this platform" + _("Faking cpu affinity because it is not supported on this platform") ) actual = False # get the available processors @@ -737,7 +741,7 @@ def set_cpu_affinity(n: int, process_ids: list, actual: bool = not Conf.TESTING) p = psutil.Process(pid) if actual: p.cpu_affinity(affinity) - logger.info(_(f"{pid} will use cpu {affinity}")) + logger.info(_("%(pid)s will use cpu %(affinity)s") % {'pid': pid, 'affinity': affinity}) def rss_check(): diff --git a/django_q/conf.py b/django_q/conf.py index 13a1098..886a58e 100644 --- a/django_q/conf.py +++ b/django_q/conf.py @@ -82,7 +82,7 @@ class Conf: # Verify SAVE_LIMIT_PER is valid if SAVE_LIMIT_PER not in ["group", "name", "func", None]: - warn(f"SAVE_LIMIT_PER ({SAVE_LIMIT_PER}) is not a valid option. Options are: 'group', 'name', 'func' and None. Default is None.") + warn(_("SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', 'name', 'func' and None. Default is None.") % {'option': SAVE_LIMIT_PER}) # Guard loop sleep in seconds. Should be between 0 and 60 seconds. GUARD_CYCLE = conf.get("guard_cycle", 0.5) diff --git a/django_q/locale/de/LC_MESSAGES/django.mo b/django_q/locale/de/LC_MESSAGES/django.mo deleted file mode 100644 index 2a2ec938cbdb56022d0a52782fad7b09ed2d3edf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4333 zcmb`JU2Ggz6@V`#Eyewzl)nOn-lP!Qjc4n1TjDx#iyb?ulX&C5#A%}tjd$ledrFQo`?H)aG`zw&SLxncsJvJm)voeQlDph zACy<0fFFXRkXO`m@G)3}_rP^{FT4ar&Ntw0_+2R9{{r$;*SMg9dZnCy6@Gy6@8PH6 z^>X|c6ghYB@Kf*}xEt<M$ z--aUhN06WTDVNW{E)>09hqA9XAWN$^%lZF8+2>s>CVJctKL#I#qR-PM_d{9tStxRj zmOKtczb`>K*8!AxxCF)DFTq{#Whi?5s^o8=#K~(=*8c}Q0sjS$!5W*Z!S6xBAwOdv z_r1iowB2-BTl^zU_AhJ5zNLMZK1kmy1Dg1$*G9P!`^lbq?b+T9l-Q9bdlElAP5&bO zb9C8Pg)Vj=4D)ybx&2T-j|&+~+(~hGoH<#k`<>AFQFy@&3|`b5dRJvvP(WV1928Lw2hsv$JUy<(=OJ&UDs1#dM-0O zX&By0Vw+#IIp0Z4nud(0{4iQq2f3PtKDFWeboErf_1mWZ^u^PfJrpy%o<)wi-m5Zw z<9(VBGTu{%j5UcLu^0B#_8rUUc+Di*k0M^ z#Yw8?b-79H*Il?4x^;Qx0=}u4^G+{hR@LI0_9-@KhAmWSs9M%uVd1!`+lA!Z%q}px zTuHn2j#0;K-Ke?9_^Cnb6gQzL)(Ww%n9^8(B{KQc4Yo_wTpUMgOT~>KYx`C_oSLXv zDYtqiY*Yes9_J;QwV`cQ)O_YAh-MS>naR+zfX|WCB;p) z(hi+wA>57YLweEk9J` zkwc`5I~_F7nSYVh>%^2=EQk}!yJi*@8+*q%RZH{gct-D%bE*OjTXD!MwPM}~C&;W)7U#mxC}=GMoVl?Wa$9|gpiD*Ugk9@jQM zJ?W74s*H$HLvX6p5H}6AQO}aZSa+tA#Im1(!HUSbs9T(_G;CP{yExa2GlyyuN6*wI zW~Ub`E#n5{Y1SUnyN=h6)Q&CJb`4(qKjH|12K($C2z{I2d3Q;jEDc0Z5dpr_+ial| zHZH2UBtA>9cry*}1eWGlj_E!^D^8p@o3_G+H<`6kZz*Pa?wGe=)J9UIN>@k6Mn?Axj|>m@9raV^EhWB9BcB61rVq!~PxW$WS0j_~*tRmiWxOThw-MVL zkLiZ-rl$L5XJ)6jl&MyR`$(A%^LrAvW7=`XAMZqdX!q%Q;3uhZwn=;{OX@*d56Cets^}L?=z95F9U+N3qc3E7)r8ix%k<_QA;TN1 ziPn|SHcXMs^Nj9IWN9PG>Z@w0d$|>b^+4T{%fr;^rU{~!Vc7_$*lpAMO>Y=Iku_WX zictr*pSSq~5y-kmO+<)qi_&^#EBmuj_p0P!@~Y`2^dkQ+y6#om$Q7mr95p0GELPS5 ztLDAU^uJ2_FT}j)liaM-0pI0c*1DImB^JX9&FTMUbeAVp$GXKgL@wQxlDYJD~L zpD$YHua~uAb3eB^?pnNs$q0*zIwAU+=xq0LkmMUisg^tooak5HZux4PIjf3FvK*R* zNrE_tun|VA8U8}#B?a5H%!@1$<%Z0?Zna6Q$(;5}!}5hhDksv)38mD_?bZjkO!VIG zUbaRphe<;dezKr(Qb>f_@TaFJGv21Zi!zhRpNUi|jobP-A5ACCIBKZ^rX&_2GB!iD zczE-q?G>Hw6$zpuekPI?Hbo66Z=5>3Y3fr`N$$9KX|Q$#1D*B1}7> ziEb`QH$Be-^KT?Osz<= q=w5Xf3dz0Gc$?^b_hLov>RxF!OUpa)l`r|l5@ICETZ?aAx&8+mTVNCb diff --git a/django_q/locale/de/LC_MESSAGES/django.po b/django_q/locale/de/LC_MESSAGES/django.po index f2fb630..4110726 100644 --- a/django_q/locale/de/LC_MESSAGES/django.po +++ b/django_q/locale/de/LC_MESSAGES/django.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-01-15 15:53+0100\n" +"POT-Creation-Date: 2022-11-12 01:47+0000\n" "PO-Revision-Date: 2018-08-05 18:28+0200\n" "Last-Translator: Jonas Winkler\n" "Language-Team: \n" @@ -17,431 +17,471 @@ msgstr "" "X-Generator: Poedit 2.1.1\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: admin.py:40 +#: django_q/admin.py:43 msgid "Resubmit selected tasks to queue" msgstr "Ausgewählte Aufgaben erneut ausführen" -#: brokers/disque.py:59 -msgid "No Disque nodes configured" -msgstr "Keine Disque-Knoten konfiguriert" +#: django_q/admin.py:98 django_q/models.py:228 +#, fuzzy +#| msgid "Success" +msgid "success" +msgstr "erfolg" -#: brokers/disque.py:76 -msgid "Could not connect to any Disque nodes" -msgstr "Konnte zu keinem Disque-Knoten verbinden" +#: django_q/admin.py:109 django_q/models.py:230 +msgid "last_run" +msgstr "" -#: cluster.py:76 -#, fuzzy, python-brace-format -#| msgid "Q Cluster-{} starting." -msgid "Q Cluster {self.name} starting." -msgstr "Q-Cluster {self.name} wird gestartet." +#: django_q/cluster.py:77 +#, python-format +msgid "Q Cluster %(name)s starting." +msgstr "Q-Cluster %(name)s wird gestartet." -#: cluster.py:84 -#, fuzzy, python-brace-format +#: django_q/cluster.py:85 +#, fuzzy, python-format #| msgid "Q Cluster-{} stopping." -msgid "Q Cluster {self.name} stopping." -msgstr "Q-Cluster {self.name} wird gestoppt." +msgid "Q Cluster %(name)s stopping." +msgstr "Q-Cluster {name} wird gestoppt." -#: cluster.py:87 -#, fuzzy, python-brace-format -#| msgid "Q Cluster-{} has stopped." -msgid "Q Cluster {self.name} has stopped." -msgstr "Q-Cluster {self.name} wurde gestoppt." +#: django_q/cluster.py:88 +#, python-format +msgid "Q Cluster %(name)s has stopped." +msgstr "Q-Cluster %(name)s wurde gestoppt." -#: cluster.py:95 +#: django_q/cluster.py:96 +#, python-format +msgid "%(name)s got signal %(signal)s" +msgstr "%(name)s erhielt das Signal %(signal)s" + +#: django_q/cluster.py:219 +#, python-format +msgid "reincarnated monitor %(name)s after sudden death" +msgstr "Monitor %(name)s wurde nach unerwartetem Absturz neu gestartet" + +#: django_q/cluster.py:222 +#, python-format +msgid "reincarnated pusher %(name)s after sudden death" +msgstr "Pusher %(name)s wurde nach unerwartetem Absturz neu gestartet" + +#: django_q/cluster.py:229 +#, python-format +msgid "reincarnated worker %(name)s after timeout" +msgstr "Worker %(name)s wurde nach Zeitüberschreitung neu gestartet" + +#: django_q/cluster.py:231 +#, python-format +msgid "recycled worker %(name)s" +msgstr "Worker %(name)s wurde wiederverwendet" + +#: django_q/cluster.py:233 +#, python-format +msgid "reincarnated worker %(name)s after death" +msgstr "Worker %(name)s wurde nach unerwartetem Absturz neu gestartet" + +#: django_q/cluster.py:256 +#, python-format +msgid "%(name)s guarding cluster %(cluster_name)s" +msgstr "%(name)s beschützt das Cluster %(cluster_name)s" + +#: django_q/cluster.py:261 +#, python-format +msgid "Q Cluster %(cluster_name)s running." +msgstr "Q-Cluster %(cluster_name)s läuft." + +#: django_q/cluster.py:295 +#, python-format +msgid "%(name)s stopping cluster processes" +msgstr "%(name)s hält Cluster-Prozesse an" + +#: django_q/cluster.py:320 +#, python-format +msgid "%(name)s waiting for the monitor." +msgstr "%(name)s wartet auf den Monitor." + +#: django_q/cluster.py:342 +#, python-format +msgid "%(process_name)s pushing tasks at %(id)s" +msgstr "%(process_name)s veröffentlicht Aufagaben auf %(id)s" + +#: django_q/cluster.py:363 +#, python-format +msgid "queueing from %(list_key)s" +msgstr "Einreihen von %(list_key)s" + +#: django_q/cluster.py:366 +#, python-format +msgid "%(name)s stopped pushing tasks" +msgstr "%(name)s veröffentlicht keine Aufgaben mehr" + +#: django_q/cluster.py:378 +#, python-format +msgid "%(name)s monitoring at %(id)s" +msgstr "%(name)s beobachtet auf %(id)s" + +#: django_q/cluster.py:395 +#, python-format +msgid "Processed '%(info_name)s' (%(task_name)s)" +msgstr "[%(task_name)s] - '%(info_name)s' wurde verarbeitet" + +#: django_q/cluster.py:398 +#, python-format +msgid "Failed '%(info_name)s' (%(task_name)s) - %(task_result)s" +msgstr "'%(info_name)s' (%(task_name)s) ist fehlgeschlagen - %(task_result)s" + +#: django_q/cluster.py:399 +#, python-format +msgid "%(name)s stopped monitoring results" +msgstr "%(name)s überwacht keine Ergebnisse mehr" + +#: django_q/cluster.py:413 +#, python-format +msgid "%(proc_name)s ready for work at %(id)s" +msgstr "%(proc_name)s ist bereit für Arbeit auf %(id)s" + +#: django_q/cluster.py:425 +#, python-format +msgid "%(proc_name)s processing '%(func_name)s' (%(task_name)s)" +msgstr "%(proc_name)s verarbeitet '%(func_name)s' (%(task_name)s)" + +#: django_q/cluster.py:440 +#, python-format msgid "" -"{current_process().name} got signal {Conf.SIGNAL_NAMES.get(signum, \"UNKNOWN" -"\")}" +"Could not process '%(func_name)s'. Check the location of the function and " +"the args/kwargs." msgstr "" -"{current_process().name} erhielt das Signal {Conf.SIGNAL_NAMES.get(signum, " -"\"UNKNOWN\")}" +"Konnte '%(func_name)s' nicht verarbeiten. Überprüfen Sie den Ort der " +"Funktion und die args/kwargs." -#: cluster.py:216 -#, fuzzy, python-brace-format -#| msgid "reincarnated monitor {} after sudden death" -msgid "reincarnated monitor {process.name} after sudden death" -msgstr "Monitor {process.name} wurde nach unerwartetem Absturz neu gestartet" +#: django_q/cluster.py:456 +#, python-format +msgid "%(proc_name)s stopped doing work" +msgstr "%(proc_name)s hat die Arbeit beendet" -#: cluster.py:219 -#, fuzzy, python-brace-format -#| msgid "reincarnated pusher {} after sudden death" -msgid "reincarnated pusher {process.name} after sudden death" -msgstr "Pusher {process.name} wurde nach unerwartetem Absturz neu gestartet" - -#: cluster.py:226 -#, fuzzy, python-brace-format -#| msgid "reincarnated worker {} after timeout" -msgid "reincarnated worker {process.name} after timeout" -msgstr "Worker {process.name} wurde nach Zeitüberschreitung neu gestartet" - -#: cluster.py:228 -#, fuzzy, python-brace-format -#| msgid "recycled worker {}" -msgid "recycled worker {process.name}" -msgstr "Worker {process.name} wurde wiederverwendet" - -#: cluster.py:230 -#, fuzzy, python-brace-format -#| msgid "reincarnated worker {} after death" -msgid "reincarnated worker {process.name} after death" -msgstr "Worker {process.name} wurde nach unerwartetem Absturz neu gestartet" - -#: cluster.py:251 -msgid "" -"{current_process().name} guarding cluster {humanize(self.cluster_id.hex)}" -msgstr "" -"{current_process().name} beschützt das Cluster {humanize(self.cluster_id." -"hex)}" - -#: cluster.py:256 -msgid "Q Cluster {humanize(self.cluster_id.hex)} running." -msgstr "Q-Cluster {humanize(self.cluster_id.hex)} ist bereit." - -#: cluster.py:290 -#, fuzzy, python-brace-format -#| msgid "{} stopping cluster processes" -msgid "{name} stopping cluster processes" -msgstr "{name} hält Cluster-Prozesse an" - -#: cluster.py:315 -#, fuzzy, python-brace-format -#| msgid "{} waiting for the monitor." -msgid "{name} waiting for the monitor." -msgstr "{name} wartet auf den Monitor." - -#: cluster.py:337 -msgid "{current_process().name} pushing tasks at {current_process().pid}" -msgstr "" -"{current_process().name} veröffentlicht Aufagaben auf {current_process().pid}" - -#: cluster.py:358 -#, fuzzy, python-brace-format -#| msgid "queueing from {}" -msgid "queueing from {broker.list_key}" -msgstr "Einreihen von {broker.list_key}" - -#: cluster.py:361 -#, fuzzy -#| msgid "{} stopped pushing tasks" -msgid "{current_process().name} stopped pushing tasks" -msgstr "{current_process().name} veröffentlicht keine Aufgaben mehr" - -#: cluster.py:373 -#, fuzzy -#| msgid "{} monitoring at {}" -msgid "{name} monitoring at {current_process().pid}" -msgstr "{name} beobachtet auf {current_process().pid}" - -#: cluster.py:387 -#, fuzzy -#| msgid "Processed [{}]" -msgid "Processed [{task['name']}]" -msgstr "[{task['name']}] wurde verarbeitet" - -#: cluster.py:390 -msgid "Failed [{task['name']}] - {task['result']}" -msgstr "[{task['name']}] ist fehlgeschlagen - {task['result']}" - -#: cluster.py:391 -#, fuzzy, python-brace-format -#| msgid "{} stopped monitoring results" -msgid "{name} stopped monitoring results" -msgstr "{name} überwacht keine Ergebnisse mehr" - -#: cluster.py:405 -#, fuzzy -#| msgid "{} ready for work at {}" -msgid "{name} ready for work at {current_process().pid}" -msgstr "{name} ist bereit für Arbeit auf {current_process().pid}" - -#: cluster.py:415 -#, fuzzy -#| msgid "{} processing [{}]" -msgid "{name} processing [{task[\"name\"]}]" -msgstr "{name} verarbeitet [{task[\"name\"]}]" - -#: cluster.py:455 -#, fuzzy, python-brace-format -#| msgid "{} stopped doing work" -msgid "{name} stopped doing work" -msgstr "{name} hat die Arbeit beendet" - -#: cluster.py:619 models.py:143 +#: django_q/cluster.py:649 django_q/models.py:144 msgid "Please install croniter to enable cron expressions" msgstr "Bitte installieren Sie croniter, um Cron-Ausdrücke zu aktivieren" -#: cluster.py:644 -#, fuzzy -#| msgid "{} failed to create a task from schedule [{}]" -msgid "" -"{current_process().name} failed to create a task from schedule [{s.name or s." -"id}]" +#: django_q/cluster.py:672 +#, python-format +msgid "%(process_name)s failed to create a task from schedule [%(schedule)s]" msgstr "" -"{current_process().name} konnte keine Aufgabe von Zeitplan [{s.name or s." -"id}] erstellen" +"%(process_name)s konnte keine Aufgabe von Zeitplan [%(schedule)s] erstellen" -#: cluster.py:650 -#, fuzzy -#| msgid "{} created a task from schedule [{}]" -msgid "" -"{current_process().name} created a task from schedule [{s.name or s.id}]" +#: django_q/cluster.py:678 +#, python-format +msgid "%(process_name)s created a task from schedule [%(schedule)s]" msgstr "" -"{current_process().name} hat eine Aufgabe des Zeitplans [{s.name or s.id}] " -"erstellt" +"%(process_name)s hat eine Aufgabe des Zeitplans [%(schedule)s] erstellt" -#: cluster.py:716 -#, fuzzy, python-brace-format -#| msgid "{} will use cpu {}" -msgid "{pid} will use cpu {affinity}" -msgstr "{pid} wird CPU {affinity} benutzen" +#: django_q/cluster.py:718 +msgid "Skipping cpu affinity because psutil was not found." +msgstr "Cpu-Affinität wird übersprungen, da psutil nicht gefunden wurde." + +#: django_q/cluster.py:723 +msgid "Faking cpu affinity because it is not supported on this platform" +msgstr "" +"Vortäuschen von CPU-Affinität, da diese auf dieser Plattform nicht " +"unterstützt wird" + +#: django_q/cluster.py:744 +#, python-format +msgid "%(pid)s will use cpu %(affinity)s" +msgstr "%(pid)s wird CPU %(affinity)s benutzen" + +#: django_q/conf.py:85 +#, python-format +msgid "" +"SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', " +"'name', 'func' and None. Default is None." +msgstr "" +"SAVE_LIMIT_PER (%(option)s) ist keine gültige Option. Optionen sind: " +"'group', 'name', 'func' und None. Standard ist None." #. Translators: Cluster status descriptions -#: conf.py:184 +#: django_q/conf.py:194 msgid "Starting" msgstr "Wird gestartet" -#: conf.py:185 +#: django_q/conf.py:195 msgid "Working" msgstr "Arbeitet" -#: conf.py:186 +#: django_q/conf.py:196 msgid "Idle" msgstr "Leerlauf" -#: conf.py:187 +#: django_q/conf.py:197 msgid "Stopped" msgstr "Gestoppt" -#: conf.py:188 +#: django_q/conf.py:198 msgid "Stopping" msgstr "Wird gestoppt" #. Translators: help text for qcluster management command -#: management/commands/qcluster.py:9 +#: django_q/management/commands/qcluster.py:9 msgid "Starts a Django Q Cluster." msgstr "Startet ein Django-Q-Cluster." #. Translators: help text for qinfo management command -#: management/commands/qinfo.py:11 +#: django_q/management/commands/qinfo.py:11 msgid "General information over all clusters." msgstr "Allgemeine Informationen über alle Cluster" +#. Translators: help text for qmemory management command +#: django_q/management/commands/qmemory.py:9 +msgid "Monitors Q Cluster memory usage" +msgstr "Überwacht die Speichernutzung von Q Cluster" + #. Translators: help text for qmonitor management command -#: management/commands/qmonitor.py:9 +#: django_q/management/commands/qmonitor.py:9 msgid "Monitors Q Cluster activity" msgstr "Q-Cluster aktiv überwachen" -#: models.py:118 +#: django_q/models.py:119 msgid "Successful task" msgstr "Erfolgreiche Aufgabe" -#: models.py:119 +#: django_q/models.py:120 msgid "Successful tasks" msgstr "Erfolgreiche Aufgaben" -#: models.py:134 +#: django_q/models.py:135 msgid "Failed task" msgstr "Fehlgeschlagene Aufgabe" -#: models.py:135 +#: django_q/models.py:136 msgid "Failed tasks" msgstr "Fehlgeschlagene Aufgaben" -#: models.py:159 +#: django_q/models.py:160 msgid "e.g. 1, 2, 'John'" msgstr "zum Beispiel 1, 2, 'John'" -#: models.py:161 +#: django_q/models.py:162 msgid "e.g. x=1, y=2, name='John'" msgstr "zum Beispiel x=1, y=2, name='John'" -#: models.py:173 +#: django_q/models.py:176 msgid "Once" msgstr "Einmal" -#: models.py:174 +#: django_q/models.py:177 msgid "Minutes" msgstr "Minuten" -#: models.py:175 +#: django_q/models.py:178 msgid "Hourly" msgstr "Stündlich" -#: models.py:176 +#: django_q/models.py:179 msgid "Daily" msgstr "Täglich" -#: models.py:177 +#: django_q/models.py:180 msgid "Weekly" msgstr "Wöchentlich" -#: models.py:178 +#: django_q/models.py:181 +msgid "Biweekly" +msgstr "Zweiwöchentlich" + +#: django_q/models.py:182 msgid "Monthly" msgstr "Monatlich" -#: models.py:179 +#: django_q/models.py:183 +msgid "Bimonthly" +msgstr "Zweimonatlich" + +#: django_q/models.py:184 msgid "Quarterly" msgstr "Vierteljährlich" -#: models.py:180 +#: django_q/models.py:185 msgid "Yearly" msgstr "Jährlich" -#: models.py:181 +#: django_q/models.py:186 msgid "Cron" msgstr "Cron" -#: models.py:184 +#: django_q/models.py:189 msgid "Schedule Type" msgstr "Zeitplan-Typ" -#: models.py:187 +#: django_q/models.py:192 msgid "Number of minutes for the Minutes type" msgstr "Anzahl Minuten für den Typ 'Minuten'" -#: models.py:190 +#: django_q/models.py:195 msgid "Repeats" msgstr "Wiederhohlungen" -#: models.py:190 +#: django_q/models.py:195 msgid "n = n times, -1 = forever" msgstr "n = n mal, -1 = für immer" -#: models.py:193 +#: django_q/models.py:198 msgid "Next Run" msgstr "Nächste Ausführung" -#: models.py:200 +#: django_q/models.py:205 msgid "Cron expression" msgstr "Cron-Ausdruck" -#: models.py:226 +#: django_q/models.py:235 msgid "Scheduled task" msgstr "Geplante Aufgabe" -#: models.py:227 +#: django_q/models.py:236 msgid "Scheduled tasks" msgstr "Geplante Aufgaben" -#: models.py:250 +#: django_q/models.py:262 msgid "Queued task" msgstr "Eingereihte Aufgabe" -#: models.py:251 +#: django_q/models.py:263 msgid "Queued tasks" msgstr "Eingereihte Aufgaben" -#: monitor.py:35 +#: django_q/monitor.py:62 django_q/monitor.py:339 msgid "Host" msgstr "Host" -#: monitor.py:39 +#: django_q/monitor.py:66 django_q/monitor.py:343 django_q/monitor.py:450 msgid "Id" msgstr "Id" -#: monitor.py:43 +#: django_q/monitor.py:70 msgid "State" msgstr "Status" -#: monitor.py:47 +#: django_q/monitor.py:74 msgid "Pool" msgstr "Pool" -#: monitor.py:51 +#: django_q/monitor.py:78 msgid "TQ" msgstr "TQ" -#: monitor.py:55 +#: django_q/monitor.py:82 msgid "RQ" msgstr "RQ" -#: monitor.py:59 +#: django_q/monitor.py:86 msgid "RC" msgstr "RC" -#: monitor.py:63 +#: django_q/monitor.py:90 msgid "Up" msgstr "Up" -#: monitor.py:143 monitor.py:247 +#: django_q/monitor.py:170 django_q/monitor.py:279 msgid "Queued" msgstr "Eingereiht" -#: monitor.py:151 +#: django_q/monitor.py:178 msgid "Success" msgstr "Erfolg" -#: monitor.py:161 monitor.py:255 +#: django_q/monitor.py:188 django_q/monitor.py:287 msgid "Failures" msgstr "Fehlschläge" -#: monitor.py:172 +#: django_q/monitor.py:199 django_q/monitor.py:485 msgid "[Press q to quit]" msgstr "[Drücken Sie q zum Beenden]" -#: monitor.py:191 +#: django_q/monitor.py:223 msgid "day" msgstr "Tag" -#: monitor.py:212 +#: django_q/monitor.py:244 msgid "second" msgstr "Sekunde" -#: monitor.py:215 +#: django_q/monitor.py:247 msgid "minute" msgstr "Minute" -#: monitor.py:218 +#: django_q/monitor.py:250 msgid "hour" msgstr "Stunde" -#: monitor.py:228 -msgid "" -"-- {Conf.PREFIX.capitalize()} { \".\".join(str(v) for v in VERSION)} on " -"{broker.info()} --" -msgstr "" -"-- {Conf.PREFIX.capitalize()} { \".\".join(str(v) for v in VERSION)} auf " -"{broker.info()} --" +#: django_q/monitor.py:260 +#, python-format +msgid "-- %(prefix)s %(version)s on %(info)s --" +msgstr "-- %(prefix)s %(version)s auf %(info)s --" -#: monitor.py:234 +#: django_q/monitor.py:266 msgid "Clusters" msgstr "Cluster" -#: monitor.py:238 +#: django_q/monitor.py:270 msgid "Workers" msgstr "Arbeiter" -#: monitor.py:242 +#: django_q/monitor.py:274 msgid "Restarts" msgstr "Neustarts" -#: monitor.py:251 +#: django_q/monitor.py:283 msgid "Successes" msgstr "Erfolge" -#: monitor.py:260 +#: django_q/monitor.py:292 msgid "Schedules" msgstr "Zeitpläne" -#: monitor.py:264 -#, fuzzy, python-brace-format -#| msgid "Tasks/{}" -msgid "Tasks/{per}" -msgstr "Aufgaben/{per}" +#: django_q/monitor.py:296 +#, python-format +msgid "Tasks/%(per)s" +msgstr "Aufgaben/%(per)s" -#: monitor.py:268 +#: django_q/monitor.py:300 msgid "Avg time" msgstr "Durchschnittl. Zeit" -#: signals.py:22 -#, fuzzy, python-brace-format -#| msgid "malformed return hook '{}' for [{}]" -msgid "malformed return hook '{instance.hook}' for [{instance.name}]" -msgstr "Ungültiger Return-Hook '{instance.hook}' für [{instance.name}]" +#: django_q/monitor.py:348 +msgid "Available (%)" +msgstr "Verfügbar (%)" -#: signals.py:30 -#, fuzzy -#| msgid "return hook {} failed on [{}] because {}" -msgid "" -"return hook {instance.hook} failed on [{instance.name}] because {str(e)}" -msgstr "" -"Return-Hook {instance.hook} für [{instance.name}] ist gescheitert: {str(e)}" +#: django_q/monitor.py:354 +msgid "Available (MB)" +msgstr "Verfügbar (MB)" + +#: django_q/monitor.py:359 +msgid "Total (MB)" +msgstr "Insgesamt (MB)" + +#: django_q/monitor.py:364 +msgid "Sentinel (MB)" +msgstr "Sentinel (MB)" + +#: django_q/monitor.py:370 +msgid "Monitor (MB)" +msgstr "Monitor (MB)" + +#: django_q/monitor.py:376 +msgid "Workers (MB)" +msgstr "Arbeiter (MB)" + +#: django_q/monitor.py:478 +#, python-format +msgid "Available lowest (): %(memory_percent)s ((at)s)" +msgstr "Niedrigste verfügbar (): %(memory_percent)s ((at)s)" + +#: django_q/monitor.py:496 +msgid "No clusters appear to be running." +msgstr "Es scheinen keine Cluster zu laufen." + +#: django_q/signals.py:22 +#, python-format +msgid "malformed return hook '%(hook)s' for [%(name)s]" +msgstr "Ungültiger Return-Hook '%(hook)s' für [%(name)s]" + +#: django_q/signals.py:30 +#, python-format +msgid "return hook %(hook)s failed on [%(name)s] because %(error)s" +msgstr "Return-Hook %(hook)s für [%(name)s] ist gescheitert: %(error)s" diff --git a/django_q/locale/fr/LC_MESSAGES/django.mo b/django_q/locale/fr/LC_MESSAGES/django.mo deleted file mode 100644 index 347a8392b0bad5b6c5dcafb3a4f107caa35a2a93..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6405 zcmb7{Ym6jS6~`}#D2w<2e5|5e0e67i?wuLfWte4vW#727J2N}WQ(SAi?o8KicU4b4 zmK_NR(TJbaL}TJ3CWMf{kYI=yO)w;e_7O>l@9@PC0VDAX!DM695904%b-R1^(Jof{ z_OI@(bI-l^oO5rTdimn>zG=7)QZA$X>|A4(VC$XyagDyqn2X^Ud^gEbR9sC+R5B>j-p#D9m@gIkp@AskR`z+Lae(CuFWGM3@hx(7<%=lt`guP;G2f>*$o;8pP7@M?HD#+07jQ0@C+4dzh#9);5X47>!s2&MlOC_kNmABGp= z4EgU$_;Gk6{0O|$*E>-0@l~k)Pr?%{=sBoye!${UWx7!I`88z8<|QcmzT)|JsQ%~h zCx2cFH^M8R{51y=F?T`v;Rs}@rVXX{IJ_J_XOQ}BrWvAz${Pwzk{wCyS{>k4b z;Ds1L_P-WtJ^P^6e*|j1Uw|6_yT1Mul>L4IHJ?9wz6Q0vze26!O?VUh50qWEFe&Mo zgEW~CDsGQMt>?>7cK$k)|DJ}L_m83Ee+sqUKY0EL%8q}5(t84GKIh{!>AL`y@da^- zSqnA4bx?L4g&Jow)Oj-nC4Ub@l{o}I1#>9*??A=ZBT)T*1!bS#K=uC{lwHqfv76vp z&;4+O`j_Bs@F_R}--KGvH5hvgj=@`D14{2>(8A{+s?Ez#{yG8qnM)8-eLa*vZikv* z2(N%&@q8L;zx^IEqWS8LM# zzL~OvqF9t26a(uhy0jl;qurEA%6iHiWiMq5Wt?Iuz3Y?Q%uuwx?UaKQ?P2*t*G|er zd1p-BQ#e4m%GVVe)0A6%y@wmPQM|}UiU-+Fmwcf8`f182<(WN+^FYoXR)ILzG&r;5%;DXXeimPiWiVt1d_lnik*Y&=l7?6Jz+xyj4tJw!0 z)GvwkZ)-KP_1L1#qqZ~KT1A$-G&9?SsI_c%^6x@>?*k9sXVt6MkO$e()%RIhDN>i2 zT`qQM(6UjykfiM(j~FF6=29E9TDIZU*Uj!E%lRu(M%fecYdJF=#YK*a=_HQwB+cxs z_4BboBae_wtkpHMd19BO(Hv+rU0Af7o!2sZ zwMy)iYSyoF=VxBsWHzwdj|A~zGO&4Fk8)I2_Nd6B%z>gI1NMl+e9J=7sup%iJu~yO zW?s|YNC+M5m^+<2ib?KF(xZwsQHt+&fh=|J3~`j%rD}~)exC`0W#j6Lbvw4fj&HCd zw95Y z#^nykHrU!2HF`Rt)|5tOa&{q2+S&oBYb-akDef<4Uo}N>BS>Sc720+cytLb30oU8C z2tya!5WhC*y-KuGWK9I#hGc&%uk#GbP8HF1PKuln2Ww}fg=$B$Da%cL*foM8b6Q2_ z8c7@)WEv@RWhp`F&1&UYFU(4_4HOZFmH7XbUQCGKXfftsU?{pTvN1y0)gK8q$o&&< zKt1cXb*eq9w%+(Mp6b)5-%SpRtX8(L` zn|wgEwjEbY+VRn`iP|W?O?GV4dJTrgsd+8>^45*~YQz;=HCqWYXpwt{Xe8Ad0uxMl(n=mros>-&va&$fZG?Ex5F{ zBW@(}Y2NnFUuHC`X9kMX3c)@}+>_u8!@^cI=uhYxV{iGt|hfpd4Vn8M!oFwzus+xOe}qeLL(; zgmBKg;?_J~ta0CPojj{IlJ?DXu52(#JP#&wfFq~ToMAe((MfwaO>`h_Oqq9fsH)XF z%V!iH8;CRWVN&A*DZ*ee876n#KrTv?xVHHy5hbqBW)e$vZ3vMc32*V}t&spro{zW8ot>H@WNVC8Tq$ACt)5ZP`UQ&n7wk&MU zPFNVK2jk*%cH}ULajbh52aRLipwk(;qH$~+guHAu1_>yqq|VnuFF(@HdDre_b~;&h zvDuZPh=X*tNb)F*XxYK5r?Dyro$o$Mi|wv7c+GcLOjXbN4Rqe#UD1oK6>tJ%X3roM z&Fo@#CGM_p;y6-0CXgpZW>xV^%*aiNDlhhYlqZ@LCdUlRl7Mz z$Au)y%uJLu&|)|U8A5wjV&!Y`q+B+@AUU%N(zN>|H>aeoq$CZ7%4|3?m``1nYtw_% zKw4KTtedT+rqkQ8RAr|nWxKWT)rY=aT1?hj-~)modPeiUWAHOR$n5D)d}7>P>98J` zk{XBoIhOfxQnX#3V@0_tFM|Wuc2|@yV`IEcd-oCB3Qil8x1E;5tB&k`A!?MbTpv(n zD~)vThnNJbCj3y{SAEKm^M>o$(AfeTS6@8+?7GUT$;&EZ622J8I|92^&MFh??h{pF zEqb%1-IXHCqQQK64M>n-S4&rpy*prp-R^Lhw1Y5+Qa*jE464YC;&s7njbjDny==B( z*?qp;3QM*OzNI1}#MArC5oOWtcrWdK^`URw?t++EnogY{uG`}z%1XZh2{^IL%_^xX z2+FJ*Ba?_Kw8_eq8MV7BBRT^{$|1|>Jt-GgsBb7UaiU8T$;j2on@)=l`HvO*42(dm z5_Ak(p2OOMSSgCx0gK#d%%GEERC%W|H{YskBn}-JhWYSu_<#56nRnP=-m$BudA3Ov zY(y_r15OR@FZMOJ~ZYwnKK~^vaTnss!JeQnrCDu!aVy zwv2WN;(3(HqP_3Pe!5*9!aQLYsc-dRACA0j1*lJ5_whn!+eu#n9Ky$(KdV$x< zO!mM@0_9R@B@q0!VFiPuu=jc37vu=BmHLM* z&K#MnclZ%u-4%T!@SQHP)${kZ<@2>tQ3aFE^Zv5@C5g=kr?Wg>v}~ T!JDJSR!9Sxa@)*7i<$llGe`#c diff --git a/django_q/locale/fr/LC_MESSAGES/django.po b/django_q/locale/fr/LC_MESSAGES/django.po index 9740bc5..26dbaef 100644 --- a/django_q/locale/fr/LC_MESSAGES/django.po +++ b/django_q/locale/fr/LC_MESSAGES/django.po @@ -6,349 +6,489 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-08-05 15:48+0200\n" +"POT-Creation-Date: 2022-11-12 01:47+0000\n" "PO-Revision-Date: 2018-08-05 18:28+0200\n" +"Last-Translator: Thierry BOULOGNE \n" "Language-Team: \n" +"Language: fr-FR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.1.1\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -"Last-Translator: Thierry BOULOGNE \n" -"Language: fr-FR\n" -#: admin.py:48 +#: django_q/admin.py:43 msgid "Resubmit selected tasks to queue" msgstr "Resoumettre les tâches sélectionnées à la file d'attente" -#: cluster.py:54 -msgid "Q Cluster-{} starting." -msgstr "Démarrage de Q Cluster-{}." +#: django_q/admin.py:98 django_q/models.py:228 +#, fuzzy +#| msgid "Success" +msgid "success" +msgstr "succès" -#: cluster.py:62 -msgid "Q Cluster-{} stopping." -msgstr "Arrêt de Q Cluster-{}." +#: django_q/admin.py:109 django_q/models.py:230 +msgid "last_run" +msgstr "" -#: cluster.py:65 -msgid "Q Cluster-{} has stopped." -msgstr "Q Cluster-{} a été arrêté." +#: django_q/cluster.py:77 +#, python-format +msgid "Q Cluster %(name)s starting." +msgstr "Démarrage de Q Cluster-%(name)s." -#: cluster.py:71 -msgid "{} got signal {}" -msgstr "{} à reçu le signal {}" +#: django_q/cluster.py:85 +#, python-format +msgid "Q Cluster %(name)s stopping." +msgstr "Arrêt de Q Cluster-%(name)s." -#: cluster.py:169 -msgid "reincarnated monitor {} after sudden death" -msgstr "moniteur réintégré {} après un arrêt intempestif" +#: django_q/cluster.py:88 +#, python-format +msgid "Q Cluster %(name)s has stopped." +msgstr "Q Cluster-%(name)s a été arrêté." -#: cluster.py:172 -msgid "reincarnated pusher {} after sudden death" -msgstr "pousseur réintégré {} après un arrêt intempestif" +#: django_q/cluster.py:96 +#, python-format +msgid "%(name)s got signal %(signal)s" +msgstr "%(name)s à reçu le signal %(signal)s" -#: cluster.py:179 -msgid "reincarnated worker {} after timeout" -msgstr "processus réintégré {} après un arrêt une attente trop longue" +#: django_q/cluster.py:219 +#, python-format +msgid "reincarnated monitor %(name)s after sudden death" +msgstr "moniteur réintégré %(name)s après un arrêt intempestif" -#: cluster.py:181 -msgid "recycled worker {}" -msgstr "processus recyclé" +#: django_q/cluster.py:222 +#, python-format +msgid "reincarnated pusher %(name)s after sudden death" +msgstr "pousseur réintégré %(name)s après un arrêt intempestif" -#: cluster.py:183 -msgid "reincarnated worker {} after death" -msgstr "processus réintégré {} après arrêt" +#: django_q/cluster.py:229 +#, python-format +msgid "reincarnated worker %(name)s after timeout" +msgstr "processus réintégré %(name)s après un arrêt une attente trop longue" -#: cluster.py:202 -msgid "{} guarding cluster at {}" -msgstr "{} surveillance du cluster à {}" +#: django_q/cluster.py:231 +#, python-format +msgid "recycled worker %(name)s" +msgstr "processus recyclé %(name)s" -#: cluster.py:205 -msgid "Q Cluster-{} running." -msgstr "Q Cluster-{} en cours d'exécution." +#: django_q/cluster.py:233 +#, python-format +msgid "reincarnated worker %(name)s after death" +msgstr "processus réintégré %(name)s après arrêt" -#: cluster.py:239 -msgid "{} stopping cluster processes" -msgstr "{} arrêt des processus de cluster" +#: django_q/cluster.py:256 +#, python-format +msgid "%(name)s guarding cluster %(cluster_name)s" +msgstr "%(name)s surveillance du cluster à %(cluster_name)s" -#: cluster.py:264 -msgid "{} waiting for the monitor." -msgstr "{} en attente du moniteur." +#: django_q/cluster.py:261 +#, python-format +msgid "Q Cluster %(cluster_name)s running." +msgstr "Démarrage de Q Cluster-%(cluster_name)s." -#: cluster.py:285 -msgid "{} pushing tasks at {}" -msgstr "{} tâche envoyé à {}" +#: django_q/cluster.py:295 +#, python-format +msgid "%(name)s stopping cluster processes" +msgstr "%(name)s arrêt des processus de cluster" -#: cluster.py:306 -msgid "queueing from {}" -msgstr "mise en file d'attente de {}" +#: django_q/cluster.py:320 +#, python-format +msgid "%(name)s waiting for the monitor." +msgstr "%(name)s en attente du moniteur." -#: cluster.py:309 -msgid "{} stopped pushing tasks" -msgstr "{} a cessé de pousser les tâches" +#: django_q/cluster.py:342 +#, python-format +msgid "%(process_name)s pushing tasks at %(id)s" +msgstr "%(process_name)s tâche envoyé à %(id)s" -#: cluster.py:320 -msgid "{} monitoring at {}" -msgstr "{} Surveillance de {}" +#: django_q/cluster.py:363 +#, python-format +msgid "queueing from %(list_key)s" +msgstr "mise en file d'attente de %(list_key)s" -#: cluster.py:334 -msgid "Processed [{}]" -msgstr "Traitement de [{}]" +#: django_q/cluster.py:366 +#, python-format +msgid "%(name)s stopped pushing tasks" +msgstr "%(name)s a cessé de pousser les tâches" -#: cluster.py:337 -msgid "Failed [{}] - {}" -msgstr "Echec [{}] - {}" +#: django_q/cluster.py:378 +#, python-format +msgid "%(name)s monitoring at %(id)s" +msgstr "%(name)s Surveillance de %(id)s" -#: cluster.py:338 -msgid "{} stopped monitoring results" -msgstr "{} arrêt des résultats de surveillance" +#: django_q/cluster.py:395 +#, python-format +msgid "Processed '%(info_name)s' (%(task_name)s)" +msgstr "traité '%(info_name)s' (%(task_name)s)" -#: cluster.py:349 -msgid "{} ready for work at {}" -msgstr "{} prêt pour le travail à {}" +#: django_q/cluster.py:398 +#, python-format +msgid "Failed '%(info_name)s' (%(task_name)s) - %(task_result)s" +msgstr "Manqué '%(info_name)s' (%(task_name)s) - %(task_result)s" -#: cluster.py:357 -msgid "{} processing [{}]" -msgstr "{} en cours de traitement [{}]" +#: django_q/cluster.py:399 +#, python-format +msgid "%(name)s stopped monitoring results" +msgstr "%(name)s arrêt des résultats de surveillance" -#: cluster.py:398 -msgid "{} stopped doing work" -msgstr "{} arrêté de travailler" +#: django_q/cluster.py:413 +#, python-format +msgid "%(proc_name)s ready for work at %(id)s" +msgstr "%(proc_name)s prêt pour le travail à %(id)s" -#: cluster.py:543 -msgid "{} failed to create a task from schedule [{}]" -msgstr "{} Echec de la création d'une tâche à partir de Schedule [{}]" +#: django_q/cluster.py:425 +#, python-format +msgid "%(proc_name)s processing '%(func_name)s' (%(task_name)s)" +msgstr "%(proc_name)s en traitement '%(func_name)s' (%(task_name)s)" -#: cluster.py:547 -msgid "{} created a task from schedule [{}]" -msgstr "{} a créé une tâche à partir de Schedule [{}]" +#: django_q/cluster.py:440 +#, python-format +msgid "" +"Could not process '%(func_name)s'. Check the location of the function and " +"the args/kwargs." +msgstr "" +"Impossible de traiter '%(func_name)s'. Vérifiez l'emplacement de la fonction " +"et les args/kwargs." -#: cluster.py:595 -msgid "{} will use cpu {}" -msgstr "{} utilisera le CPU {}" +#: django_q/cluster.py:456 +#, python-format +msgid "%(proc_name)s stopped doing work" +msgstr "%(proc_name)s arrêté de travailler" -#: conf.py:169 +#: django_q/cluster.py:649 django_q/models.py:144 +msgid "Please install croniter to enable cron expressions" +msgstr "Veuillez installer croniter pour activer les expressions croniques." + +#: django_q/cluster.py:672 +#, python-format +msgid "%(process_name)s failed to create a task from schedule [%(schedule)s]" +msgstr "" +"%(process_name)s Echec de la création d'une tâche à partir de Schedule " +"[%(schedule)s]" + +#: django_q/cluster.py:678 +#, python-format +msgid "%(process_name)s created a task from schedule [%(schedule)s]" +msgstr "%(process_name)s a créé une tâche à partir de Schedule [%(schedule)s]" + +#: django_q/cluster.py:718 +msgid "Skipping cpu affinity because psutil was not found." +msgstr "Sauter l'affinité du processeur parce que psutil n'a pas été trouvé." + +#: django_q/cluster.py:723 +msgid "Faking cpu affinity because it is not supported on this platform" +msgstr "" +"Simulation de l'affinité du processeur parce qu'elle n'est pas supportée sur " +"cette plateforme." + +#: django_q/cluster.py:744 +#, python-format +msgid "%(pid)s will use cpu %(affinity)s" +msgstr "%(pid)s utilisera le CPU %(affinity)s" + +#: django_q/conf.py:85 +#, python-format +msgid "" +"SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', " +"'name', 'func' and None. Default is None." +msgstr "" +"SAVE_LIMIT_PER (%(option)s) n'est pas une option valide. Les options sont : " +"'group', 'name', 'func' et None. La valeur par défaut est None." + +#. Translators: Cluster status descriptions +#: django_q/conf.py:194 msgid "Starting" msgstr "Démarrage" -#: conf.py:170 +#: django_q/conf.py:195 msgid "Working" msgstr "Actif" -#: conf.py:171 +#: django_q/conf.py:196 msgid "Idle" msgstr "En attente" -#: conf.py:172 +#: django_q/conf.py:197 msgid "Stopped" msgstr "Arrêté" -#: conf.py:173 +#: django_q/conf.py:198 msgid "Stopping" msgstr "En cours d’arrêt" -#: management/commands/qcluster.py:9 +#. Translators: help text for qcluster management command +#: django_q/management/commands/qcluster.py:9 msgid "Starts a Django Q Cluster." msgstr "Démarre un cluster Django Q." -#: management/commands/qinfo.py:11 +#. Translators: help text for qinfo management command +#: django_q/management/commands/qinfo.py:11 msgid "General information over all clusters." msgstr "Informations générales sur tous les clusters." -#: management/commands/qmonitor.py:9 +#. Translators: help text for qmemory management command +#: django_q/management/commands/qmemory.py:9 +#, fuzzy +#| msgid "Monitors Q Cluster activity" +msgid "Monitors Q Cluster memory usage" +msgstr "Surveille l'utilisation de la mémoire du cluster Q" + +#. Translators: help text for qmonitor management command +#: django_q/management/commands/qmonitor.py:9 msgid "Monitors Q Cluster activity" msgstr "Activité du cluster Moniteur Q" -#: models.py:104 +#: django_q/models.py:119 msgid "Successful task" msgstr "Tâche réussie" -#: models.py:105 +#: django_q/models.py:120 msgid "Successful tasks" msgstr "Tâches réussies" -#: models.py:121 +#: django_q/models.py:135 msgid "Failed task" msgstr "Tâche échoué" -#: models.py:122 +#: django_q/models.py:136 msgid "Failed tasks" msgstr "Tâches échouées" -#: models.py:131 +#: django_q/models.py:160 msgid "e.g. 1, 2, 'John'" msgstr "ex. 1, 2, ‘Jean’" -#: models.py:132 +#: django_q/models.py:162 msgid "e.g. x=1, y=2, name='John'" msgstr "p. ex. x = 1, y = 2, Nom = ‘Jean’" -#: models.py:142 +#: django_q/models.py:176 msgid "Once" msgstr "Une fois" -#: models.py:143 +#: django_q/models.py:177 msgid "Minutes" msgstr "Minutes" -#: models.py:144 +#: django_q/models.py:178 msgid "Hourly" msgstr "Toutes les heures" -#: models.py:145 +#: django_q/models.py:179 msgid "Daily" msgstr "Quotidien" -#: models.py:146 +#: django_q/models.py:180 msgid "Weekly" msgstr "Hebdomadaire" -#: models.py:147 +#: django_q/models.py:181 +#, fuzzy +#| msgid "Weekly" +msgid "Biweekly" +msgstr "Bihebdomadaire" + +#: django_q/models.py:182 msgid "Monthly" msgstr "Mensuel" -#: models.py:148 +#: django_q/models.py:183 +#, fuzzy +#| msgid "Monthly" +msgid "Bimonthly" +msgstr "Bimestriel" + +#: django_q/models.py:184 msgid "Quarterly" msgstr "Tous les quart-d’heure" -#: models.py:149 +#: django_q/models.py:185 msgid "Yearly" msgstr "Annuel" -#: models.py:151 +#: django_q/models.py:186 +msgid "Cron" +msgstr "Cron" + +#: django_q/models.py:189 msgid "Schedule Type" msgstr "Type de plannification" -#: models.py:153 +#: django_q/models.py:192 msgid "Number of minutes for the Minutes type" msgstr "Nombre de minutes pour le type de minutes" -#: models.py:154 +#: django_q/models.py:195 msgid "Repeats" msgstr "Répéter" -#: models.py:154 +#: django_q/models.py:195 msgid "n = n times, -1 = forever" msgstr "n = n fois,-1 = Toujours" -#: models.py:155 +#: django_q/models.py:198 msgid "Next Run" msgstr "Prochaine exécution" -#: models.py:180 +#: django_q/models.py:205 +msgid "Cron expression" +msgstr "Expression du Cron" + +#: django_q/models.py:235 msgid "Scheduled task" msgstr "Tâche planifiée" -#: models.py:181 +#: django_q/models.py:236 msgid "Scheduled tasks" msgstr "Tâches planifiées" -#: models.py:204 +#: django_q/models.py:262 msgid "Queued task" msgstr "Tâche en file d'attente" -#: models.py:205 +#: django_q/models.py:263 msgid "Queued tasks" msgstr "Tâches en file d'attente" -#: monitor.py:33 +#: django_q/monitor.py:62 django_q/monitor.py:339 msgid "Host" msgstr "Hôte" -#: monitor.py:34 +#: django_q/monitor.py:66 django_q/monitor.py:343 django_q/monitor.py:450 msgid "Id" msgstr "Id" -#: monitor.py:35 +#: django_q/monitor.py:70 msgid "State" msgstr "Statut" -#: monitor.py:36 +#: django_q/monitor.py:74 msgid "Pool" msgstr "Piscine" -#: monitor.py:37 +#: django_q/monitor.py:78 msgid "TQ" msgstr "TQ" -#: monitor.py:38 +#: django_q/monitor.py:82 msgid "RQ" msgstr "RQ" -#: monitor.py:39 +#: django_q/monitor.py:86 msgid "RC" msgstr "RC" -#: monitor.py:40 +#: django_q/monitor.py:90 msgid "Up" msgstr "Haut" -#: monitor.py:90 monitor.py:165 +#: django_q/monitor.py:170 django_q/monitor.py:279 msgid "Queued" msgstr "En file d'attente" -#: monitor.py:92 +#: django_q/monitor.py:178 msgid "Success" msgstr "Succès" -#: monitor.py:95 monitor.py:173 +#: django_q/monitor.py:188 django_q/monitor.py:287 msgid "Failures" msgstr "Défaillances" -#: monitor.py:101 +#: django_q/monitor.py:199 django_q/monitor.py:485 msgid "[Press q to quit]" msgstr "[appuyez sur q pour quitter]" -#: monitor.py:120 +#: django_q/monitor.py:223 msgid "day" msgstr "jour" -#: monitor.py:137 +#: django_q/monitor.py:244 msgid "second" msgstr "seconde" -#: monitor.py:140 +#: django_q/monitor.py:247 msgid "minute" msgstr "minute" -#: monitor.py:143 +#: django_q/monitor.py:250 msgid "hour" msgstr "heure" -#: monitor.py:151 -msgid "-- {} {} on {} --" -msgstr "--{} {} sur {}--" +#: django_q/monitor.py:260 +#, python-format +msgid "-- %(prefix)s %(version)s on %(info)s --" +msgstr "--%(prefix)s %(version)s sur %(info)s --" -#: monitor.py:153 +#: django_q/monitor.py:266 msgid "Clusters" msgstr "Grappes" -#: monitor.py:157 +#: django_q/monitor.py:270 msgid "Workers" msgstr "Processus" -#: monitor.py:161 +#: django_q/monitor.py:274 msgid "Restarts" msgstr "Redémarrages" -#: monitor.py:169 +#: django_q/monitor.py:283 msgid "Successes" msgstr "Succès" -#: monitor.py:177 +#: django_q/monitor.py:292 msgid "Schedules" msgstr "Planifications" -#: monitor.py:181 -msgid "Tasks/{}" -msgstr "Tâches/{}" +#: django_q/monitor.py:296 +#, python-format +msgid "Tasks/%(per)s" +msgstr "Tâches/%(per)s" -#: monitor.py:185 +#: django_q/monitor.py:300 msgid "Avg time" msgstr "Temps Moyen" -#: signals.py:21 -msgid "malformed return hook '{}' for [{}]" -msgstr "hook de retour mal formé' {} 'pour [{}]" +#: django_q/monitor.py:348 +msgid "Available (%)" +msgstr "" -#: signals.py:26 -msgid "return hook {} failed on [{}] because {}" -msgstr "le crochet de retour {} a échoué sur [{}] parce que {}" +#: django_q/monitor.py:354 +msgid "Available (MB)" +msgstr "Disponible sur (MB)" + +#: django_q/monitor.py:359 +msgid "Total (MB)" +msgstr "Total (MB)" + +#: django_q/monitor.py:364 +msgid "Sentinel (MB)" +msgstr "Sentinel (MB)" + +#: django_q/monitor.py:370 +msgid "Monitor (MB)" +msgstr "Monitor (MB)" + +#: django_q/monitor.py:376 +#, fuzzy +#| msgid "Workers" +msgid "Workers (MB)" +msgstr "Processus (MB)" + +#: django_q/monitor.py:478 +#, python-format +msgid "Available lowest (): %(memory_percent)s ((at)s)" +msgstr "Disponible le plus bas () : %(memory_percent)s ((at)s)" + +#: django_q/monitor.py:496 +msgid "No clusters appear to be running." +msgstr "Aucun cluster ne semble être en cours d'exécution." + +#: django_q/signals.py:22 +#, python-format +msgid "malformed return hook '%(hook)s' for [%(name)s]" +msgstr "hook de retour mal formé' %(hook)s 'pour [%(name)s]" + +#: django_q/signals.py:30 +#, python-format +msgid "return hook %(hook)s failed on [%(name)s] because %(error)s" +msgstr "le crochet de retour %(hook)s a échoué sur [%(name)s] parce que %(error)s" diff --git a/django_q/locale/tr/LC_MESSAGES/django.po b/django_q/locale/tr/LC_MESSAGES/django.po index 88092ef..8b73b63 100644 --- a/django_q/locale/tr/LC_MESSAGES/django.po +++ b/django_q/locale/tr/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-06-18 23:55+0300\n" +"POT-Creation-Date: 2022-11-12 01:47+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Ethem Güner \n" "Language-Team: \n" @@ -17,166 +17,199 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: django_q/admin.py:40 + +#: django_q/admin.py:43 msgid "Resubmit selected tasks to queue" msgstr "Seçili işleri kuyruğa tekrar gönder" -#: django_q/brokers/disque.py:60 -msgid "No Disque nodes configured" -msgstr "Disque nodları konfigüre edilmemiş" +#: django_q/admin.py:98 django_q/models.py:228 +#, fuzzy +#| msgid "Success" +msgid "success" +msgstr "başarılı olanlar" -#: django_q/brokers/disque.py:77 -msgid "Could not connect to any Disque nodes" -msgstr "Herhangi bir Disque noduna bağlanılamadı" - -#: django_q/cluster.py:79 -#, python-brace-format -msgid "Q Cluster {self.name} starting." -msgstr "Q Cluster {self.name} başlatılıyor." - -#: django_q/cluster.py:87 -#, python-brace-format -msgid "Q Cluster {self.name} stopping." -msgstr "Q Cluster {self.name} durduruluyor." - -#: django_q/cluster.py:90 -#, python-brace-format -msgid "Q Cluster {self.name} has stopped." -msgstr "Q Cluster {self.name} durduruldu." - -#: django_q/cluster.py:98 -msgid "" -"{current_process().name} got signal {Conf.SIGNAL_NAMES.get(signum, \"UNKNOWN" -"\")}" +#: django_q/admin.py:109 django_q/models.py:230 +msgid "last_run" msgstr "" -"{current_process().name} şu sinyali aldı {Conf.SIGNAL_NAMES.get(signum, \"UNKNOWN" -"\")}" -#: django_q/cluster.py:220 -#, python-brace-format -msgid "reincarnated monitor {process.name} after sudden death" -msgstr "Monitor {process.name} ani ölüm sonrası tekrar dirildi" +#: django_q/cluster.py:77 +#, python-format +msgid "Q Cluster %(name)s starting." +msgstr "Q Cluster %(name)s başlatılıyor." -#: django_q/cluster.py:223 -#, python-brace-format -msgid "reincarnated pusher {process.name} after sudden death" -msgstr "Pusher {process.name} ani ölüm sonrası tekrar dirildi" +#: django_q/cluster.py:85 +#, python-format +msgid "Q Cluster %(name)s stopping." +msgstr "Q Cluster %(name)s durduruluyor." -#: django_q/cluster.py:230 -#, python-brace-format -msgid "reincarnated worker {process.name} after timeout" -msgstr "Worker {process.name} zaman aşımı sonrası tekrar dirildi" +#: django_q/cluster.py:88 +#, python-format +msgid "Q Cluster %(name)s has stopped." +msgstr "Q Cluster %(name)s durduruldu." -#: django_q/cluster.py:232 -#, python-brace-format -msgid "recycled worker {process.name}" -msgstr "Worker {process.name} geri döndürüldü" +#: django_q/cluster.py:96 +#, python-format +msgid "%(name)s got signal %(signal)s" +msgstr "%(name)s, %(signal)s pid'inde izleniyor/monitoring yapılıyor." -#: django_q/cluster.py:234 -#, python-brace-format -msgid "reincarnated worker {process.name} after death" -msgstr "Worker {process.name} ani ölüm sonrası tekrar dirildi" +#: django_q/cluster.py:219 +#, python-format +msgid "reincarnated monitor %(name)s after sudden death" +msgstr "Monitor %(name)s ani ölüm sonrası tekrar dirildi" + +#: django_q/cluster.py:222 +#, python-format +msgid "reincarnated pusher %(name)s after sudden death" +msgstr "Pusher %(name)s ani ölüm sonrası tekrar dirildi" + +#: django_q/cluster.py:229 +#, python-format +msgid "reincarnated worker %(name)s after timeout" +msgstr "Worker %(name)s zaman aşımı sonrası tekrar dirildi" + +#: django_q/cluster.py:231 +#, python-format +msgid "recycled worker %(name)s" +msgstr "Worker %(name)s geri döndürüldü" + +#: django_q/cluster.py:233 +#, python-format +msgid "reincarnated worker %(name)s after death" +msgstr "Worker %(name)s ani ölüm sonrası tekrar dirildi" #: django_q/cluster.py:256 -msgid "" -"{current_process().name} guarding cluster {humanize(self.cluster_id.hex)}" -msgstr "{current_process().name}, {humanize(self.cluster_id.hex)} cluster'ını koruyor" +#, python-format +msgid "%(name)s guarding cluster %(cluster_name)s" +msgstr "%(name)s, %(cluster_name)s cluster'ını koruyor" #: django_q/cluster.py:261 -msgid "Q Cluster {humanize(self.cluster_id.hex)} running." -msgstr "Q Cluster {humanize(self.cluster_id.hex)} çalışıyor." +#, python-format +msgid "Q Cluster %(cluster_name)s running." +msgstr "Q Cluster %(cluster_name)s başlatılıyor." #: django_q/cluster.py:295 -#, python-brace-format -msgid "{name} stopping cluster processes" -msgstr "Cluster {name} işlemleri durduruluyor." +#, python-format +msgid "%(name)s stopping cluster processes" +msgstr "Cluster %(name)s işlemleri durduruluyor." #: django_q/cluster.py:320 -#, python-brace-format -msgid "{name} waiting for the monitor." -msgstr "{name} monitor için bekliyor." +#, python-format +msgid "%(name)s waiting for the monitor." +msgstr "%(name)s monitor için bekliyor." #: django_q/cluster.py:342 -msgid "{current_process().name} pushing tasks at {current_process().pid}" -msgstr "{current_process().name, işleri {current_process().pid} pid'ine gönderiyor." +#, python-format +msgid "%(process_name)s pushing tasks at %(id)s" +msgstr "%(process_name)s, işleri %(id)s pid'ine gönderiyor." #: django_q/cluster.py:363 -#, python-brace-format -msgid "queueing from {broker.list_key}" +#, python-format +msgid "queueing from %(list_key)s" msgstr "" #: django_q/cluster.py:366 -msgid "{current_process().name} stopped pushing tasks" -msgstr "{current_process().name} işleri göndermeyi durdurdu" +#, python-format +msgid "%(name)s stopped pushing tasks" +msgstr "%(name)s işleri göndermeyi durdurdu" #: django_q/cluster.py:378 -msgid "{name} monitoring at {current_process().pid}" -msgstr "{name}, {current_process().pid} pid'inde izleniyor/monitoring yapılıyor." +#, python-format +msgid "%(name)s monitoring at %(id)s" +msgstr "%(name)s, %(id)s pid'inde izleniyor/monitoring yapılıyor." -#: django_q/cluster.py:394 -msgid "Processed [{task['name']}]" -msgstr "[{task['name']}] işlendi." - -#: django_q/cluster.py:397 -msgid "Failed [{task['name']}] - {task['result']}" -msgstr "[{task['name']}] - {task['result']} başarısız oldu" +#: django_q/cluster.py:395 +#, python-format +msgid "Processed '%(info_name)s' (%(task_name)s)" +msgstr "[%(task_name)s] - '%(info_name)s işlendi." #: django_q/cluster.py:398 -#, python-brace-format -msgid "{name} stopped monitoring results" -msgstr "{name} sonuçları göstermeyi bıraktı" +#, python-format +msgid "Failed '%(info_name)s' (%(task_name)s) - %(task_result)s" +msgstr "[%(task_name)s] - '%(info_name)s' - %(task_result)s başarısız oldu" -#: django_q/cluster.py:412 -msgid "{name} ready for work at {current_process().pid}" -msgstr "{name}, {current_process().pid} pid'inde çalışmaya hazır" +#: django_q/cluster.py:399 +#, python-format +msgid "%(name)s stopped monitoring results" +msgstr "%(name)s sonuçları göstermeyi bıraktı" -#: django_q/cluster.py:422 -msgid "{name} processing [{task[\"name\"]}]" -msgstr "{name}, [{task[\"name\"]}] işlerini işiyor" +#: django_q/cluster.py:413 +#, python-format +msgid "%(proc_name)s ready for work at %(id)s" +msgstr "%(proc_name)s, %(id)s pid'inde çalışmaya hazır" -#: django_q/cluster.py:453 -#, python-brace-format -msgid "{name} stopped doing work" -msgstr "{name} çalışmayı bıraktı" +#: django_q/cluster.py:425 +#, python-format +msgid "%(proc_name)s processing '%(func_name)s' (%(task_name)s)" +msgstr "%(proc_name)s, '%(func_name)s' [%(task_name)s] işlerini işiyor" -#: django_q/cluster.py:635 django_q/models.py:143 +#: django_q/cluster.py:440 +#, python-format +msgid "" +"Could not process '%(func_name)s'. Check the location of the function and " +"the args/kwargs." +msgstr "" +"%(func_name)s' işlenemedi. İşlevin konumunu ve args/kwargs öğelerini kontrol " +"edin." + +#: django_q/cluster.py:456 +#, python-format +msgid "%(proc_name)s stopped doing work" +msgstr "%(proc_name)s çalışmayı bıraktı" + +#: django_q/cluster.py:649 django_q/models.py:144 msgid "Please install croniter to enable cron expressions" msgstr "Cron expressions'ları açmak için croniter yükleyin" -#: django_q/cluster.py:665 -msgid "" -"{current_process().name} failed to create a task from schedule [{s.name or s." -"id}]" -msgstr "" +#: django_q/cluster.py:672 +#, python-format +msgid "%(process_name)s failed to create a task from schedule [%(schedule)s]" +msgstr "%(process_name)s programdan bir görev oluşturamadı [%(schedule)s]" -#: django_q/cluster.py:671 -msgid "" -"{current_process().name} created a task from schedule [{s.name or s.id}]" -msgstr "" +#: django_q/cluster.py:678 +#, python-format +msgid "%(process_name)s created a task from schedule [%(schedule)s]" +msgstr "%(process_name)s programdan bir görev oluşturamadı [%(schedule)s]" -#: django_q/cluster.py:737 -#, python-brace-format -msgid "{pid} will use cpu {affinity}" +#: django_q/cluster.py:718 +msgid "Skipping cpu affinity because psutil was not found." +msgstr "Psutil bulunamadığı için cpu benzeşimi atlanıyor." + +#: django_q/cluster.py:723 +msgid "Faking cpu affinity because it is not supported on this platform" +msgstr "Bu platformda desteklenmediği için sahte cpu benzeşimi" + +#: django_q/cluster.py:744 +#, python-format +msgid "%(pid)s will use cpu %(affinity)s" +msgstr "%(pid)s cpu %(affinity)s kullanacaktır" + +#: django_q/conf.py:85 +#, python-format +msgid "" +"SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', " +"'name', 'func' and None. Default is None." msgstr "" +"SAVE_LIMIT_PER (%(option)s) geçerli bir seçenek değil. Seçenekler şunlardır: " +"'group', 'name', 'func' ve None. Varsayılan değer None'dır." #. Translators: Cluster status descriptions -#: django_q/conf.py:196 +#: django_q/conf.py:194 msgid "Starting" msgstr "Başlıyor" -#: django_q/conf.py:197 +#: django_q/conf.py:195 msgid "Working" msgstr "Çalışıyor" -#: django_q/conf.py:198 +#: django_q/conf.py:196 msgid "Idle" msgstr "Boşta" -#: django_q/conf.py:199 +#: django_q/conf.py:197 msgid "Stopped" msgstr "Durdu" -#: django_q/conf.py:200 +#: django_q/conf.py:198 msgid "Stopping" msgstr "Durduruluyor" @@ -200,239 +233,255 @@ msgstr "Q Cluster'ın bellek kullanımını izler" msgid "Monitors Q Cluster activity" msgstr "Q Cluster'ın aktivitelerini izler" -#: django_q/models.py:118 +#: django_q/models.py:119 msgid "Successful task" msgstr "Başarılı iş" -#: django_q/models.py:119 +#: django_q/models.py:120 msgid "Successful tasks" msgstr "Başarılı işler" -#: django_q/models.py:134 +#: django_q/models.py:135 msgid "Failed task" msgstr "Başarısız iş" -#: django_q/models.py:135 +#: django_q/models.py:136 msgid "Failed tasks" msgstr "Başarısız işler" -#: django_q/models.py:159 +#: django_q/models.py:160 msgid "e.g. 1, 2, 'John'" msgstr "Örneğin: 1, 2, 'Melih'" -#: django_q/models.py:161 +#: django_q/models.py:162 msgid "e.g. x=1, y=2, name='John'" msgstr "Örneğin: x=1, y=2, name='Melih'" -#: django_q/models.py:173 +#: django_q/models.py:176 msgid "Once" msgstr "Bir kere" -#: django_q/models.py:174 +#: django_q/models.py:177 msgid "Minutes" msgstr "Dakika" -#: django_q/models.py:175 +#: django_q/models.py:178 msgid "Hourly" msgstr "Saatlik" -#: django_q/models.py:176 +#: django_q/models.py:179 msgid "Daily" msgstr "Günlük" -#: django_q/models.py:177 +#: django_q/models.py:180 msgid "Weekly" msgstr "Haftalık" -#: django_q/models.py:178 +#: django_q/models.py:181 +#, fuzzy +#| msgid "Weekly" +msgid "Biweekly" +msgstr "İki haftada bir" + +#: django_q/models.py:182 msgid "Monthly" msgstr "Aylık" -#: django_q/models.py:179 +#: django_q/models.py:183 +#, fuzzy +#| msgid "Monthly" +msgid "Bimonthly" +msgstr "İki ayda bir" + +#: django_q/models.py:184 msgid "Quarterly" msgstr "Bir Çeyrek (3 Ay)" -#: django_q/models.py:180 +#: django_q/models.py:185 msgid "Yearly" msgstr "Yıllık" -#: django_q/models.py:181 +#: django_q/models.py:186 msgid "Cron" msgstr "" -#: django_q/models.py:184 +#: django_q/models.py:189 msgid "Schedule Type" msgstr "Zamanlama Tipi" -#: django_q/models.py:187 +#: django_q/models.py:192 msgid "Number of minutes for the Minutes type" msgstr "Dakika tipine göre dakika sayısı" -#: django_q/models.py:190 +#: django_q/models.py:195 msgid "Repeats" msgstr "Tekrar eder" -#: django_q/models.py:190 +#: django_q/models.py:195 msgid "n = n times, -1 = forever" msgstr "n = n kere, -1 = sonsuza kadar" -#: django_q/models.py:193 +#: django_q/models.py:198 msgid "Next Run" msgstr "Bir dahaki çalışma tarihi" -#: django_q/models.py:200 +#: django_q/models.py:205 msgid "Cron expression" msgstr "" -#: django_q/models.py:227 +#: django_q/models.py:235 msgid "Scheduled task" msgstr "Zamanlanmış iş" -#: django_q/models.py:228 +#: django_q/models.py:236 msgid "Scheduled tasks" msgstr "Zamanlanmış işler" -#: django_q/models.py:251 +#: django_q/models.py:262 msgid "Queued task" msgstr "Sıraya alınmış iş" -#: django_q/models.py:252 +#: django_q/models.py:263 msgid "Queued tasks" msgstr "Sıraya alınmış işler" -#: django_q/monitor.py:54 django_q/monitor.py:322 +#: django_q/monitor.py:62 django_q/monitor.py:339 msgid "Host" msgstr "" -#: django_q/monitor.py:58 django_q/monitor.py:326 django_q/monitor.py:433 +#: django_q/monitor.py:66 django_q/monitor.py:343 django_q/monitor.py:450 msgid "Id" msgstr "" -#: django_q/monitor.py:62 +#: django_q/monitor.py:70 msgid "State" msgstr "Durum" -#: django_q/monitor.py:66 +#: django_q/monitor.py:74 msgid "Pool" msgstr "Havuz" -#: django_q/monitor.py:70 +#: django_q/monitor.py:78 msgid "TQ" msgstr "" -#: django_q/monitor.py:74 +#: django_q/monitor.py:82 msgid "RQ" msgstr "" -#: django_q/monitor.py:78 +#: django_q/monitor.py:86 msgid "RC" msgstr "" -#: django_q/monitor.py:82 +#: django_q/monitor.py:90 msgid "Up" msgstr "" -#: django_q/monitor.py:162 django_q/monitor.py:266 +#: django_q/monitor.py:170 django_q/monitor.py:279 msgid "Queued" msgstr "Sıraya alınmış" -#: django_q/monitor.py:170 +#: django_q/monitor.py:178 msgid "Success" msgstr "Başarılı olanlar" -#: django_q/monitor.py:180 django_q/monitor.py:274 +#: django_q/monitor.py:188 django_q/monitor.py:287 msgid "Failures" msgstr "Başarısız olanlar" -#: django_q/monitor.py:191 +#: django_q/monitor.py:199 django_q/monitor.py:485 msgid "[Press q to quit]" msgstr "[Çıkmak için q'ya basın]" -#: django_q/monitor.py:210 +#: django_q/monitor.py:223 msgid "day" msgstr "gün" -#: django_q/monitor.py:231 +#: django_q/monitor.py:244 msgid "second" msgstr "saniye" -#: django_q/monitor.py:234 +#: django_q/monitor.py:247 msgid "minute" msgstr "dakika" -#: django_q/monitor.py:237 +#: django_q/monitor.py:250 msgid "hour" msgstr "saat" -#: django_q/monitor.py:247 -msgid "" -"-- {Conf.PREFIX.capitalize()} { \".\".join(str(v) for v in VERSION)} on " -"{broker.info()} --" -msgstr "" +#: django_q/monitor.py:260 +#, python-format +msgid "-- %(prefix)s %(version)s on %(info)s --" +msgstr "-- %(prefix)s %(version)s üzerinde %(info)s --" -#: django_q/monitor.py:253 +#: django_q/monitor.py:266 msgid "Clusters" msgstr "" -#: django_q/monitor.py:257 +#: django_q/monitor.py:270 msgid "Workers" msgstr "" -#: django_q/monitor.py:261 +#: django_q/monitor.py:274 msgid "Restarts" msgstr "Yeniden çalıştırmalar" -#: django_q/monitor.py:270 +#: django_q/monitor.py:283 msgid "Successes" msgstr "Başarılı olanlar" -#: django_q/monitor.py:279 +#: django_q/monitor.py:292 msgid "Schedules" msgstr "Zamanlanmışlar" -#: django_q/monitor.py:283 -#, python-brace-format -msgid "Tasks/{per}" -msgstr "İş/{per}" +#: django_q/monitor.py:296 +#, python-format +msgid "Tasks/%(per)s" +msgstr "İş/%(per)s" -#: django_q/monitor.py:287 +#: django_q/monitor.py:300 msgid "Avg time" msgstr "Ortalama süre" -#: django_q/monitor.py:331 +#: django_q/monitor.py:348 msgid "Available (%)" msgstr "Müsait (%) " -#: django_q/monitor.py:337 +#: django_q/monitor.py:354 msgid "Available (MB)" msgstr "Müsait (MB)" -#: django_q/monitor.py:342 +#: django_q/monitor.py:359 msgid "Total (MB)" msgstr "Toplam (MB)" -#: django_q/monitor.py:347 +#: django_q/monitor.py:364 msgid "Sentinel (MB)" msgstr "" -#: django_q/monitor.py:353 +#: django_q/monitor.py:370 msgid "Monitor (MB)" msgstr "İzleme (MB)" -#: django_q/monitor.py:359 +#: django_q/monitor.py:376 msgid "Workers (MB)" msgstr "" -#: django_q/monitor.py:461 -msgid "Available lowest (%): {} ({})" -msgstr "Mevcut en düşük (%): {} ({})" +#: django_q/monitor.py:478 +#, python-format +msgid "Available lowest (): %(memory_percent)s ((at)s)" +msgstr "Mevcut en düşük (): %(memory_percent)s ((at)s)" + +#: django_q/monitor.py:496 +msgid "No clusters appear to be running." +msgstr "Hiçbir küme çalışıyor görünmüyor." #: django_q/signals.py:22 -#, python-brace-format -msgid "malformed return hook '{instance.hook}' for [{instance.name}]" +#, python-format +msgid "malformed return hook '%(hook)s' for [%(name)s]" msgstr "" #: django_q/signals.py:30 -msgid "" -"return hook {instance.hook} failed on [{instance.name}] because {str(e)}" +#, python-format +msgid "return hook %(hook)s failed on [%(name)s] because %(error)s" msgstr "" diff --git a/django_q/migrations/0015_alter_schedule_schedule_type.py b/django_q/migrations/0015_alter_schedule_schedule_type.py new file mode 100644 index 0000000..fd3fcec --- /dev/null +++ b/django_q/migrations/0015_alter_schedule_schedule_type.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.2 on 2022-11-10 01:35 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_q', '0014_schedule_cluster'), + ] + + operations = [ + migrations.AlterField( + model_name='schedule', + name='schedule_type', + field=models.CharField(choices=[('O', 'Once'), ('I', 'Minutes'), ('H', 'Hourly'), ('D', 'Daily'), ('W', 'Weekly'), ('BW', 'Biweekly'), ('M', 'Monthly'), ('BM', 'Bimonthly'), ('Q', 'Quarterly'), ('Y', 'Yearly'), ('C', 'Cron')], default='O', max_length=2, verbose_name='Schedule Type'), + ), + ] diff --git a/django_q/models.py b/django_q/models.py index d90c8d0..05aa0fe 100644 --- a/django_q/models.py +++ b/django_q/models.py @@ -166,7 +166,9 @@ class Schedule(models.Model): HOURLY = "H" DAILY = "D" WEEKLY = "W" + BIWEEKLY = "BW" MONTHLY = "M" + BIMONTHLY = "BM" QUARTERLY = "Q" YEARLY = "Y" CRON = "C" @@ -176,13 +178,15 @@ class Schedule(models.Model): (HOURLY, _("Hourly")), (DAILY, _("Daily")), (WEEKLY, _("Weekly")), + (BIWEEKLY, _("Biweekly")), (MONTHLY, _("Monthly")), + (BIMONTHLY, _("Bimonthly")), (QUARTERLY, _("Quarterly")), (YEARLY, _("Yearly")), (CRON, _("Cron")), ) schedule_type = models.CharField( - max_length=1, choices=TYPE, default=TYPE[0][0], verbose_name=_("Schedule Type") + max_length=2, choices=TYPE, default=TYPE[0][0], verbose_name=_("Schedule Type") ) minutes = models.PositiveSmallIntegerField( null=True, blank=True, help_text=_("Number of minutes for the Minutes type") diff --git a/django_q/monitor.py b/django_q/monitor.py index 0ce0d79..20a670d 100644 --- a/django_q/monitor.py +++ b/django_q/monitor.py @@ -257,8 +257,8 @@ def info(broker=None): term.black_on_green( term.center( _( - f'-- {Conf.PREFIX.capitalize()} { ".".join(str(v) for v in VERSION)} on {broker.info()} --' - ) + '-- %(prefix)s %(version)s on %(info)s --' + ) % {'prefix': Conf.PREFIX.capitalize(), 'version': ".".join(str(v) for v in VERSION), 'info': broker.info()} ) ) ) @@ -293,7 +293,7 @@ def info(broker=None): + term.move_x(1 * col_width) + term.white(str(models.Schedule.objects.count())) + term.move_x(2 * col_width) - + term.cyan(_(f"Tasks/{per}")) + + term.cyan(_("Tasks/%(per)s") % {'per': per}) + term.move_x(3 * col_width) + term.white(f"{tasks_per:.2f}") + term.move_x(4 * col_width) @@ -475,17 +475,14 @@ def memory(run_once=False, workers=False, broker=None): row += 1 print( term.move(row, 0) - + _("Available lowest (%): {} ({})").format( - str(MEMORY_AVAILABLE_LOWEST_PERCENTAGE), - MEMORY_AVAILABLE_LOWEST_PERCENTAGE_AT.strftime( - "%Y-%m-%d %H:%M:%S+00:00" - ), - ) + + _("Available lowest (): %(memory_percent)s ((at)s)") % { 'memory_percent': str(MEMORY_AVAILABLE_LOWEST_PERCENTAGE), 'at': MEMORY_AVAILABLE_LOWEST_PERCENTAGE_AT.strftime( + "%Y-%m-%d %H:%M:%S+00:00" + )} ) # for testing if run_once: return Stat.get_all(broker=broker) - print(term.move(row + 2, 0) + term.center("[Press q to quit]")) + print(term.move(row + 2, 0) + term.center(_("[Press q to quit]"))) val = term.inkey(timeout=1) @@ -496,5 +493,5 @@ def get_ids(): for s in stat: print(s.cluster_id) else: - print("No clusters appear to be running.") + print(_("No clusters appear to be running.")) return True diff --git a/django_q/signals.py b/django_q/signals.py index 109b473..0b7dd61 100644 --- a/django_q/signals.py +++ b/django_q/signals.py @@ -19,7 +19,7 @@ def call_hook(sender, instance, **kwargs): f = getattr(m, func) except (ValueError, ImportError, AttributeError): logger.error( - _(f"malformed return hook '{instance.hook}' for [{instance.name}]") + _("malformed return hook '%(hook)s' for [%(name)s]") % {'hook': instance.hook, 'name': instance.name} ) return try: @@ -27,8 +27,8 @@ def call_hook(sender, instance, **kwargs): except Exception as e: logger.error( _( - f"return hook {instance.hook} failed on [{instance.name}] because {str(e)}" - ) + "return hook %(hook)s failed on [%(name)s] because %(error)s" + ) % {'hook': instance.hook, 'name': instance.name, 'error': str(e)} ) diff --git a/django_q/tests/test_scheduler.py b/django_q/tests/test_scheduler.py index a9441a1..c3c0ffc 100644 --- a/django_q/tests/test_scheduler.py +++ b/django_q/tests/test_scheduler.py @@ -21,6 +21,7 @@ from django_q.tests.testing_utilities.multiple_database_routers import ( TestingMultipleAppsDatabaseRouter, TestingReplicaDatabaseRouter, ) +from django_q.utils import add_months, add_years @pytest.fixture @@ -228,6 +229,29 @@ def test_scheduler(broker, monkeypatch): # Done broker.delete_queue() + # test bimonthly + schedule = create_schedule( + "django_q.tests.tasks.word_multiply", + 2, + word="catch_up", + schedule_type=Schedule.BIMONTHLY + ) + scheduler(broker=broker) + schedule = Schedule.objects.get(pk=schedule.pk) + assert schedule.next_run.date() == add_months(timezone.now(), 2).date() + + # test biweekly + schedule = create_schedule( + "django_q.tests.tasks.word_multiply", + 2, + word="catch_up", + schedule_type=Schedule.BIWEEKLY + ) + scheduler(broker=broker) + schedule = Schedule.objects.get(pk=schedule.pk) + assert schedule.next_run.date() == (timezone.now() + timedelta(weeks=2)).date() + broker.delete_queue() + monkeypatch.setattr(Conf, "PREFIX", "some_cluster_name") # create a schedule on another cluster schedule = create_schedule( diff --git a/docs/schedules.rst b/docs/schedules.rst index 5687000..b7b4f5b 100644 --- a/docs/schedules.rst +++ b/docs/schedules.rst @@ -165,7 +165,7 @@ Reference .. py:attribute:: TYPE - :attr:`ONCE`, :attr:`MINUTES`, :attr:`HOURLY`, :attr:`DAILY`, :attr:`WEEKLY`, :attr:`MONTHLY`, :attr:`QUARTERLY`, :attr:`YEARLY`, :attr:`CRON` + :attr:`ONCE`, :attr:`MINUTES`, :attr:`HOURLY`, :attr:`DAILY`, :attr:`WEEKLY`, :attr:`BIWEEKLY`, :attr:`MONTHLY`, :attr:`BIMONTHLY`, :attr:`QUARTERLY`, :attr:`YEARLY`, :attr:`CRON` .. py:attribute:: minutes @@ -224,10 +224,23 @@ Reference `'W'` the task will run every week on they day and time of the first run. + .. py:attribute:: BIWEEKLY + + `'BW'` the task will run once every two weeks on they day and time of the first run. + .. py:attribute:: MONTHLY `'M'` the tasks runs every month on they day and time of the last run. + .. note:: + + Months are tricky. If you schedule something on the 31st of the month and the next month has only 30 days or less, the task will run on the last day of the next month. + It will however continue to run on that day, e.g. the 28th, in subsequent months. + + .. py:attribute:: BIMONTHLY + + `'BM'` the tasks runs once every two months on they day and time of the last run. + .. note:: Months are tricky. If you schedule something on the 31st of the month and the next month has only 30 days or less, the task will run on the last day of the next month. From 06ad6154e3f8a2fa7b525d36308898b509b67cc1 Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Sun, 13 Nov 2022 01:06:19 +0100 Subject: [PATCH 13/39] Release 1.4.4 (#37) --- CHANGELOG.md | 3 +++ docs/conf.py | 2 +- pyproject.toml | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4debe71..d97d44d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,10 @@ ## [Unreleased](https://github.com/GDay/django-q2/tree/HEAD) +## [v1.4.4](https://github.com/GDay/django-q2/tree/v1.4.4) (2022-11-13) + **Merged pull requests:** + - Fix: Deprecation warning for Django 5.x https://github.com/GDay/django-q2/pull/34 - Feat: Add biweekly and bimonthly https://github.com/GDay/django-q2/pull/36 - Fix: Fix all translation strings and remove compiled https://github.com/GDay/django-q2/pull/36 diff --git a/docs/conf.py b/docs/conf.py index e643bed..2a0b392 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -73,7 +73,7 @@ author = 'Ilan Steemers, Stan Triepels' # The short X.Y version. version = '1.4' # The full version, including alpha/beta/rc tags. -release = '1.4.3' +release = '1.4.4' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pyproject.toml b/pyproject.toml index de2cc15..0158ef7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "django-q2" -version = "1.4.3" +version = "1.4.4" packages = [ { include = "django_q" }, ] From cf458304cc52522d93bc412621e7688928d34492 Mon Sep 17 00:00:00 2001 From: GDay <1939656+GDay@users.noreply.github.com> Date: Sun, 13 Nov 2022 01:08:54 +0100 Subject: [PATCH 14/39] [v1.4.4] add sudo to workflow --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8e97b7a..934dfce 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,8 +22,8 @@ jobs: - name: Install dependencies run: | - apt-get update - apt-get -y install gettext + sudo apt-get update + sudo apt-get -y install gettext python -m pip install pip setuptools django poetry # compile messages to get .mo files django-admin compilemessages From b73fea49b54d561ea3792073304f6fd08dae936d Mon Sep 17 00:00:00 2001 From: GDay <1939656+GDay@users.noreply.github.com> Date: Sun, 13 Nov 2022 01:12:52 +0100 Subject: [PATCH 15/39] Release v1.4.5 --- CHANGELOG.md | 4 ++++ docs/conf.py | 2 +- pyproject.toml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d97d44d..672bb72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased](https://github.com/GDay/django-q2/tree/HEAD) +## [v1.4.5](https://github.com/GDay/django-q2/tree/v1.4.5) (2022-11-13) + +- Fix release workflow + ## [v1.4.4](https://github.com/GDay/django-q2/tree/v1.4.4) (2022-11-13) **Merged pull requests:** diff --git a/docs/conf.py b/docs/conf.py index 2a0b392..3a54996 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -73,7 +73,7 @@ author = 'Ilan Steemers, Stan Triepels' # The short X.Y version. version = '1.4' # The full version, including alpha/beta/rc tags. -release = '1.4.4' +release = '1.4.5' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pyproject.toml b/pyproject.toml index 0158ef7..d5d52b6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "django-q2" -version = "1.4.4" +version = "1.4.5" packages = [ { include = "django_q" }, ] From 3c0c32758dcf2162f71588e8023e71b6cc46c7c1 Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Wed, 16 Nov 2022 01:45:40 +0100 Subject: [PATCH 16/39] Chore: Flake8, isort and Black (#40) --- .git-blame-ignore-revs | 2 + .github/workflows/test.yml | 6 +- CHANGELOG.md | 4 + django_q/__init__.py | 4 +- django_q/admin.py | 24 ++- django_q/apps.py | 2 +- django_q/brokers/aws_sqs.py | 3 +- django_q/brokers/orm.py | 5 +- django_q/cluster.py | 179 +++++++++++++----- django_q/conf.py | 34 ++-- django_q/core_signing.py | 1 + django_q/humanhash.py | 12 +- django_q/migrations/0001_initial.py | 155 +++++++++++---- .../migrations/0002_auto_20150630_1624.py | 18 +- .../migrations/0003_auto_20150708_1326.py | 36 ++-- .../migrations/0004_auto_20150710_1043.py | 24 ++- .../migrations/0005_auto_20150718_1506.py | 10 +- .../migrations/0006_auto_20150805_1817.py | 32 +++- django_q/migrations/0007_ormq.py | 24 ++- .../migrations/0008_auto_20160224_1026.py | 6 +- .../migrations/0009_auto_20171009_0915.py | 12 +- .../migrations/0010_auto_20200610_0856.py | 26 ++- .../migrations/0011_auto_20200628_1055.py | 31 ++- .../migrations/0012_auto_20200702_1608.py | 14 +- .../migrations/0013_task_attempt_count.py | 6 +- django_q/migrations/0014_schedule_cluster.py | 6 +- .../0015_alter_schedule_schedule_type.py | 25 ++- django_q/models.py | 2 +- django_q/monitor.py | 51 +++-- django_q/queues.py | 3 +- django_q/signals.py | 8 +- django_q/tasks.py | 6 +- django_q/tests/settings.py | 4 +- django_q/tests/test_brokers.py | 3 +- django_q/tests/test_cluster.py | 22 +-- django_q/tests/test_scheduler.py | 28 +-- django_q/utils.py | 19 +- docs/conf.py | 87 ++++----- tox.ini | 2 + 39 files changed, 635 insertions(+), 301 deletions(-) create mode 100644 .git-blame-ignore-revs create mode 100644 tox.ini diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000..1d02276 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,2 @@ +# flake8, black, isort +b1d000d007f3f77069719523268a0c6256dc0860 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index af11374..f21d0c3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -73,7 +73,11 @@ jobs: - name: Upload to coveralls run: | python -m pip install --upgrade pip - python -m pip install coveralls + python -m pip install coveralls flake8 black coveralls --service=github --finish env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Check flake8/black + run: | + flake8 . + black --check . diff --git a/CHANGELOG.md b/CHANGELOG.md index 672bb72..9ce8858 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased](https://github.com/GDay/django-q2/tree/HEAD) +**Merged pull requests:** + +- Chore: flake8, isort, black https://github.com/GDay/django-q2/pull/40 + ## [v1.4.5](https://github.com/GDay/django-q2/tree/v1.4.5) (2022-11-13) - Fix release workflow diff --git a/django_q/__init__.py b/django_q/__init__.py index 57212dc..974cdc6 100644 --- a/django_q/__init__.py +++ b/django_q/__init__.py @@ -1,7 +1,7 @@ -VERSION = (1, 3, 9) - import django +VERSION = (1, 4, 5) + if django.VERSION < (3, 2): default_app_config = "django_q.apps.DjangoQConfig" diff --git a/django_q/admin.py b/django_q/admin.py index 9a34115..ae1d97e 100644 --- a/django_q/admin.py +++ b/django_q/admin.py @@ -1,9 +1,9 @@ """Admin module for Django.""" +from django.contrib import admin +from django.db.models.expressions import OuterRef, Subquery from django.urls import reverse from django.utils.html import format_html -from django.contrib import admin from django.utils.translation import gettext_lazy as _ -from django.db.models.expressions import OuterRef, Subquery from django_q.conf import Conf, croniter from django_q.models import Failure, OrmQ, Schedule, Success, Task @@ -82,18 +82,27 @@ class ScheduleAdmin(admin.ModelAdmin): readonly_fields = ("cron",) list_filter = ("next_run", "schedule_type", "cluster") - search_fields = ("name", "func",) + search_fields = ( + "name", + "func", + ) list_display_links = ("id", "name") def get_queryset(self, request): qs = super().get_queryset(request) - task_query = Task.objects.filter(id=OuterRef('task')).values('id', 'name', 'success') - qs = qs.annotate(task_id=Subquery(task_query.values('id')), task_name=Subquery(task_query.values('name')), - task_success=Subquery(task_query.values('success'))) + task_query = Task.objects.filter(id=OuterRef("task")).values( + "id", "name", "success" + ) + qs = qs.annotate( + task_id=Subquery(task_query.values("id")), + task_name=Subquery(task_query.values("name")), + task_success=Subquery(task_query.values("success")), + ) return qs def get_success(self, obj): return obj.task_success + get_success.boolean = True get_success.short_description = _("success") @@ -105,6 +114,7 @@ class ScheduleAdmin(admin.ModelAdmin): url = reverse("admin:django_q_failure_change", args=(obj.task_id,)) return format_html(f'[{obj.task_name}]') return None + get_last_run.allow_tags = True get_last_run.short_description = _("last_run") @@ -112,7 +122,7 @@ class ScheduleAdmin(admin.ModelAdmin): class QueueAdmin(admin.ModelAdmin): """queue admin for ORM broker""" - list_display = ("id", "key", "name", "group", "func", "lock", "task_id") + list_display = ("id", "key", "name", "group", "func", "lock", "task_id") def save_model(self, request, obj, form, change): obj.save(using=Conf.ORM) diff --git a/django_q/apps.py b/django_q/apps.py index abfb0b2..29faaf6 100644 --- a/django_q/apps.py +++ b/django_q/apps.py @@ -9,4 +9,4 @@ class DjangoQConfig(AppConfig): default_auto_field = "django.db.models.AutoField" def ready(self): - from django_q.signals import call_hook + from django_q.signals import call_hook # noqa: F401 diff --git a/django_q/brokers/aws_sqs.py b/django_q/brokers/aws_sqs.py index 6e6da73..c6f69d9 100644 --- a/django_q/brokers/aws_sqs.py +++ b/django_q/brokers/aws_sqs.py @@ -39,7 +39,8 @@ class Sqs(Broker): raise ValueError("receive_message_wait_time_seconds should be int") if wait_time_second > 20: raise ValueError( - "receive_message_wait_time_seconds is invalid. Reason: Must be >= 0 and <= 20" + "receive_message_wait_time_seconds is invalid. Reason: Must be >= 0" + " and <= 20" ) params.update({"WaitTimeSeconds": wait_time_second}) diff --git a/django_q/brokers/orm.py b/django_q/brokers/orm.py index 345eff1..de209b4 100644 --- a/django_q/brokers/orm.py +++ b/django_q/brokers/orm.py @@ -62,7 +62,7 @@ class ORM(Broker): def dequeue(self): tasks = self.get_connection().filter(key=self.list_key, lock__lt=_timeout())[ - 0 : Conf.BULK + 0 : Conf.BULK # noqa: E203 ] if tasks: task_list = [] @@ -73,7 +73,8 @@ class ORM(Broker): .update(lock=timezone.now()) ): task_list.append((task.pk, task.payload)) - # else don't process, as another cluster has been faster than us on that task + # else don't process, as another cluster has been faster than us on + # that task return task_list # empty queue, spare the cpu sleep(Conf.POLL) diff --git a/django_q/cluster.py b/django_q/cluster.py index 1e95390..e33a0a2 100644 --- a/django_q/cluster.py +++ b/django_q/cluster.py @@ -74,7 +74,7 @@ class Cluster: ), ) self.sentinel.start() - logger.info(_("Q Cluster %(name)s starting.") % {'name': self.name}) + logger.info(_("Q Cluster %(name)s starting.") % {"name": self.name}) while not self.start_event.is_set(): sleep(0.1) return self.pid @@ -82,19 +82,21 @@ class Cluster: def stop(self) -> bool: if not self.sentinel.is_alive(): return False - logger.info(_("Q Cluster %(name)s stopping.") % {'name': self.name}) + logger.info(_("Q Cluster %(name)s stopping.") % {"name": self.name}) self.stop_event.set() self.sentinel.join() - logger.info(_("Q Cluster %(name)s has stopped.") % {'name': self.name}) + logger.info(_("Q Cluster %(name)s has stopped.") % {"name": self.name}) self.start_event = None self.stop_event = None return True def sig_handler(self, signum, frame): logger.debug( - _( - '%(name)s got signal %(signal)s' - ) % {'name': current_process().name, 'signal': Conf.SIGNAL_NAMES.get(signum, "UNKNOWN")} + _("%(name)s got signal %(signal)s") + % { + "name": current_process().name, + "signal": Conf.SIGNAL_NAMES.get(signum, "UNKNOWN"), + } ) self.stop() @@ -216,21 +218,34 @@ class Sentinel: db.connections.close_all() if process == self.monitor: self.monitor = self.spawn_monitor() - logger.error(_("reincarnated monitor %(name)s after sudden death") % {'name': process.name}) + logger.error( + _("reincarnated monitor %(name)s after sudden death") + % {"name": process.name} + ) elif process == self.pusher: self.pusher = self.spawn_pusher() - logger.error(_("reincarnated pusher %(name)s after sudden death") % {'name': process.name}) + logger.error( + _("reincarnated pusher %(name)s after sudden death") + % {"name": process.name} + ) else: self.pool.remove(process) self.spawn_worker() if process.timer.value == 0: - # only need to terminate on timeout, otherwise we risk destabilizing the queues + # only need to terminate on timeout, otherwise we risk destabilizing + # the queues process.terminate() - logger.warning(_("reincarnated worker %(name)s after timeout") % {'name': process.name}) + logger.warning( + _("reincarnated worker %(name)s after timeout") + % {"name": process.name} + ) elif int(process.timer.value) == -2: - logger.info(_("recycled worker %(name)s") % {'name': process.name}) + logger.info(_("recycled worker %(name)s") % {"name": process.name}) else: - logger.error(_("reincarnated worker %(name)s after death") % {'name': process.name}) + logger.error( + _("reincarnated worker %(name)s after death") + % {"name": process.name} + ) self.reincarnations += 1 @@ -252,13 +267,18 @@ class Sentinel: def guard(self): logger.info( - _( - "%(name)s guarding cluster %(cluster_name)s" - ) % {'name': current_process().name, 'cluster_name': humanize(self.cluster_id.hex)} + _("%(name)s guarding cluster %(cluster_name)s") + % { + "name": current_process().name, + "cluster_name": humanize(self.cluster_id.hex), + } ) self.start_event.set() Stat(self).save() - logger.info(_("Q Cluster %(cluster_name)s running.") % {'cluster_name': humanize(self.cluster_id.hex)}) + logger.info( + _("Q Cluster %(cluster_name)s running.") + % {"cluster_name": humanize(self.cluster_id.hex)} + ) counter = 0 cycle = Conf.GUARD_CYCLE # guard loop sleep in seconds # Guard loop. Runs at least once @@ -292,7 +312,7 @@ class Sentinel: def stop(self): Stat(self).save() name = current_process().name - logger.info(_("%(name)s stopping cluster processes") % {'name': name}) + logger.info(_("%(name)s stopping cluster processes") % {"name": name}) # Stopping pusher self.event_out.set() # Wait for it to stop @@ -317,7 +337,7 @@ class Sentinel: self.result_queue.close() # Wait for the result queue to empty self.result_queue.join_thread() - logger.info(_("%(name)s waiting for the monitor.") % {'name': name}) + logger.info(_("%(name)s waiting for the monitor.") % {"name": name}) # Wait for everything to close or time out count = 0 if not self.timeout: @@ -339,7 +359,10 @@ def pusher(task_queue: Queue, event: Event, broker: Broker = None): """ if not broker: broker = get_broker() - logger.info(_("%(process_name)s pushing tasks at %(id)s") % {'process_name': current_process().name, 'id': current_process().pid}) + logger.info( + _("%(process_name)s pushing tasks at %(id)s") + % {"process_name": current_process().name, "id": current_process().pid} + ) while True: try: task_set = broker.dequeue() @@ -360,10 +383,12 @@ def pusher(task_queue: Queue, event: Event, broker: Broker = None): continue task["ack_id"] = ack_id task_queue.put(task) - logger.debug(_("queueing from %(list_key)s") % {'list_key': broker.list_key}) + logger.debug( + _("queueing from %(list_key)s") % {"list_key": broker.list_key} + ) if event.is_set(): break - logger.info(_("%(name)s stopped pushing tasks") % {'name': current_process().name}) + logger.info(_("%(name)s stopped pushing tasks") % {"name": current_process().name}) def monitor(result_queue: Queue, broker: Broker = None): @@ -375,7 +400,9 @@ def monitor(result_queue: Queue, broker: Broker = None): if not broker: broker = get_broker() name = current_process().name - logger.info(_("%(name)s monitoring at %(id)s") % {'name': name, 'id': current_process().pid}) + logger.info( + _("%(name)s monitoring at %(id)s") % {"name": name, "id": current_process().pid} + ) for task in iter(result_queue.get, "STOP"): # save the result if task.get("cached", False): @@ -389,28 +416,42 @@ def monitor(result_queue: Queue, broker: Broker = None): # signal execution done post_execute.send(sender="django_q", task=task) # log the result - info_name = get_func_repr(task['func']) + info_name = get_func_repr(task["func"]) if task["success"]: # log success - logger.info(_("Processed '%(info_name)s' (%(task_name)s)") % {'info_name': info_name, 'task_name': task['name']}) + logger.info( + _("Processed '%(info_name)s' (%(task_name)s)") + % {"info_name": info_name, "task_name": task["name"]} + ) else: # log failure - logger.error(_("Failed '%(info_name)s' (%(task_name)s) - %(task_result)s") % {'info_name': info_name, 'task_name': task['name'], 'task_result': task['result']}) - logger.info(_("%(name)s stopped monitoring results") % {'name': name}) + logger.error( + _("Failed '%(info_name)s' (%(task_name)s) - %(task_result)s") + % { + "info_name": info_name, + "task_name": task["name"], + "task_result": task["result"], + } + ) + logger.info(_("%(name)s stopped monitoring results") % {"name": name}) def worker( task_queue: Queue, result_queue: Queue, timer: Value, timeout: int = Conf.TIMEOUT ): """ - Takes a task from the task queue, tries to execute it and puts the result back in the result queue + Takes a task from the task queue, tries to execute it and puts the result back in + the result queue :param timeout: number of seconds wait for a worker to finish. :type task_queue: multiprocessing.Queue :type result_queue: multiprocessing.Queue :type timer: multiprocessing.Value """ proc_name = current_process().name - logger.info(_("%(proc_name)s ready for work at %(id)s") % {'proc_name': proc_name, 'id': current_process().pid}) + logger.info( + _("%(proc_name)s ready for work at %(id)s") + % {"proc_name": proc_name, "id": current_process().pid} + ) task_count = 0 if timeout is None: timeout = -1 @@ -422,7 +463,14 @@ def worker( # Get the function from the task func = task["func"] func_name = get_func_repr(func) - logger.info(_("%(proc_name)s processing '%(func_name)s' (%(task_name)s)") % {'proc_name': proc_name, 'func_name': func_name, 'task_name': task['name']}) + logger.info( + _("%(proc_name)s processing '%(func_name)s' (%(task_name)s)") + % { + "proc_name": proc_name, + "func_name": func_name, + "task_name": task["name"], + } + ) f = task["func"] # if it's not an instance try to get it from the string if not callable(task["func"]): @@ -437,7 +485,14 @@ def worker( res = f(*task["args"], **task["kwargs"]) result = (res, True) except Exception: - result = (_("Could not process '%(func_name)s'. Check the location of the function and the args/kwargs.") % {'func_name': func_name}, False) + result = ( + _( + "Could not process '%(func_name)s'. Check the location of the " + "function and the args/kwargs." + ) + % {"func_name": func_name}, + False, + ) if error_reporter: error_reporter.report() if task.get("sync", False): @@ -453,7 +508,8 @@ def worker( if task_count == Conf.RECYCLE or rss_check(): timer.value = -2 # Recycled break - logger.info(_("%(proc_name)s stopped doing work") % {'proc_name': proc_name}) + logger.info(_("%(proc_name)s stopped doing work") % {"proc_name": proc_name}) + def save_task(task, broker: Broker): """ @@ -478,16 +534,27 @@ def save_task(task, broker: Broker): try: filters = {} - if Conf.SAVE_LIMIT_PER and Conf.SAVE_LIMIT_PER in {"group", "name", "func"} and Conf.SAVE_LIMIT_PER in task: + if ( + Conf.SAVE_LIMIT_PER + and Conf.SAVE_LIMIT_PER in {"group", "name", "func"} + and Conf.SAVE_LIMIT_PER in task + ): value = task[Conf.SAVE_LIMIT_PER] if Conf.SAVE_LIMIT_PER == "func": value = get_func_repr(value) filters[Conf.SAVE_LIMIT_PER] = value - database_to_use = {"using": Conf.ORM if Conf.ORM else Schedule.objects.db} if not Conf.HAS_REPLICA else {} + database_to_use = ( + {"using": Conf.ORM if Conf.ORM else Schedule.objects.db} + if not Conf.HAS_REPLICA + else {} + ) with db.transaction.atomic(**database_to_use): last = Success.objects.filter(**filters).select_for_update().last() - if task["success"] and 0 < Conf.SAVE_LIMIT <= Success.objects.filter(**filters).count(): + if ( + task["success"] + and 0 < Conf.SAVE_LIMIT <= Success.objects.filter(**filters).count() + ): last.delete() # check if this task has previous results @@ -588,7 +655,11 @@ def scheduler(broker: Broker = None): broker = get_broker() close_old_django_connections() try: - database_to_use = {"using": Conf.ORM if Conf.ORM else Schedule.objects.db} if not Conf.HAS_REPLICA else {} + database_to_use = ( + {"using": Conf.ORM if Conf.ORM else Schedule.objects.db} + if not Conf.HAS_REPLICA + else {} + ) with db.transaction.atomic(**database_to_use): for s in ( Schedule.objects.select_for_update() @@ -608,8 +679,13 @@ def scheduler(broker: Broker = None): except (SyntaxError, ValueError): # else use the kwargs syntax try: - parsed_kwargs = ast.parse(f"f({s.kwargs})").body[0].value.keywords - kwargs = {kwarg.arg: ast.literal_eval(kwarg.value) for kwarg in parsed_kwargs} + parsed_kwargs = ( + ast.parse(f"f({s.kwargs})").body[0].value.keywords + ) + kwargs = { + kwarg.arg: ast.literal_eval(kwarg.value) + for kwarg in parsed_kwargs + } except (SyntaxError, ValueError): kwargs = {} if s.args: @@ -646,7 +722,8 @@ def scheduler(broker: Broker = None): if not croniter: raise ImportError( _( - "Please install croniter to enable cron expressions" + "Please install croniter to enable cron " + "expressions" ) ) next_run = croniter(s.cron, localtime()).get_next(datetime) @@ -659,7 +736,8 @@ def scheduler(broker: Broker = None): scheduled_broker = broker try: scheduled_broker = get_broker(q_options["broker_name"]) - except: # invalid broker_name or non existing broker with broker_name + except: # noqa: E722 + # invalid broker_name or non existing broker with broker_name pass q_options["broker"] = scheduled_broker q_options["group"] = q_options.get("group", s.name or s.id) @@ -669,14 +747,24 @@ def scheduler(broker: Broker = None): if not s.task: logger.error( _( - "%(process_name)s failed to create a task from schedule [%(schedule)s]" - ) % {'process_name': current_process().name, 'schedule': s.name or s.id} + "%(process_name)s failed to create a task from schedule " + "[%(schedule)s]" + ) + % { + "process_name": current_process().name, + "schedule": s.name or s.id, + } ) else: logger.info( _( - "%(process_name)s created a task from schedule [%(schedule)s]" - ) % {'process_name': current_process().name, 'schedule': s.name or s.id} + "%(process_name)s created a task from schedule " + "[%(schedule)s]" + ) + % { + "process_name": current_process().name, + "schedule": s.name or s.id, + } ) # default behavior is to delete a ONCE schedule if s.schedule_type == s.ONCE: @@ -741,7 +829,10 @@ def set_cpu_affinity(n: int, process_ids: list, actual: bool = not Conf.TESTING) p = psutil.Process(pid) if actual: p.cpu_affinity(affinity) - logger.info(_("%(pid)s will use cpu %(affinity)s") % {'pid': pid, 'affinity': affinity}) + logger.info( + _("%(pid)s will use cpu %(affinity)s") + % {"pid": pid, "affinity": affinity} + ) def rss_check(): diff --git a/django_q/conf.py b/django_q/conf.py index 886a58e..77ef602 100644 --- a/django_q/conf.py +++ b/django_q/conf.py @@ -73,7 +73,8 @@ class Conf: # Log output level LOG_LEVEL = conf.get("log_level", "INFO") - # Maximum number of successful tasks kept in the database. 0 saves everything. -1 saves none + # Maximum number of successful tasks kept in the database. 0 saves everything. + # -1 saves none # Failures are always saved SAVE_LIMIT = conf.get("save_limit", 250) @@ -82,7 +83,13 @@ class Conf: # Verify SAVE_LIMIT_PER is valid if SAVE_LIMIT_PER not in ["group", "name", "func", None]: - warn(_("SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', 'name', 'func' and None. Default is None.") % {'option': SAVE_LIMIT_PER}) + warn( + _( + "SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: " + "'group', 'name', 'func' and None. Default is None." + ) + % {"option": SAVE_LIMIT_PER} + ) # Guard loop sleep in seconds. Should be between 0 and 60 seconds. GUARD_CYCLE = conf.get("guard_cycle", 0.5) @@ -113,11 +120,12 @@ class Conf: # Sets compression of redis packages COMPRESSED = conf.get("compress", False) - # Number of tasks each worker can handle before it gets recycled. Useful for releasing memory + # Number of tasks each worker can handle before it gets recycled. + # Useful for releasing memory RECYCLE = conf.get("recycle", 500) - # The maximum resident set size in kilobytes before a worker will recycle. Useful for limiting memory usage - # Not available on all platforms + # The maximum resident set size in kilobytes before a worker will recycle. + # Useful for limiting memory usage. Not available on all platforms MAX_RSS = conf.get("max_rss", None) # Number of seconds to wait for a worker to finish. @@ -135,9 +143,10 @@ class Conf: # Verify if retry and timeout settings are correct if not TIMEOUT or (TIMEOUT > RETRY): warn( - """Retry and timeout are misconfigured. Set retry larger than timeout, - failure to do so will cause the tasks to be retriggered before completion. - See https://django-q2.readthedocs.io/en/master/configure.html#retry for details.""" + "Retry and timeout are misconfigured. Set retry larger than timeout," + "failure to do so will cause the tasks to be retriggered before completion." + "See https://django-q2.readthedocs.io/en/master/configure.html#retry " + "for details." ) # Sets the amount of tasks the cluster will try to pop off the broker. @@ -156,12 +165,14 @@ class Conf: # The Django cache to use CACHE = conf.get("cache", "default") - # Use the cache as result backend. Can be 'True' or an integer representing the global cache timeout. + # Use the cache as result backend. Can be 'True' or an integer representing the + # global cache timeout. # i.e 'cached: 60' , will make all results go the cache and expire in 60 seconds. CACHED = conf.get("cached", False) # If set to False the scheduler won't execute tasks in the past. - # Instead it will run once and reschedule the next run in the future. Defaults to True. + # Instead it will run once and reschedule the next run in the future. Defaults to + # True. CATCH_UP = conf.get("catch_up", True) # Use the secret key for package signing @@ -257,5 +268,6 @@ def get_ppid(): return psutil.Process(os.getpid()).ppid() else: raise OSError( - "Your OS does not support `os.getppid`. Please install `psutil` as an alternative provider." + "Your OS does not support `os.getppid`. Please install `psutil` as an " + "alternative provider." ) diff --git a/django_q/core_signing.py b/django_q/core_signing.py index 6d2d899..d451ba4 100644 --- a/django_q/core_signing.py +++ b/django_q/core_signing.py @@ -6,6 +6,7 @@ from django.core.signing import BadSignature, JSONSerializer, SignatureExpired from django.core.signing import Signer as Sgnr from django.core.signing import TimestampSigner as TsS from django.core.signing import b64_decode, dumps + try: from django.core.signing import base62 except ImportError: diff --git a/django_q/humanhash.py b/django_q/humanhash.py index 72238c1..7878af7 100644 --- a/django_q/humanhash.py +++ b/django_q/humanhash.py @@ -337,12 +337,18 @@ class HumanHasher: # Split `bytes` into `target` segments. seg_size = length // target - segments = [bytes[i * seg_size : (i + 1) * seg_size] for i in range(target)] + # fmt: off + segments = [ + bytes[i * seg_size : (i + 1) * seg_size] for i in range(target) # noqa: E203 E501 + ] + # fmt: on # Catch any left-over bytes in the last segment. - segments[-1].extend(bytes[target * seg_size :]) + segments[-1].extend(bytes[target * seg_size :]) # noqa: E203 E501 # Use a simple XOR checksum-like function for compression. - checksum = lambda bytes: reduce(operator.xor, bytes, 0) + def checksum(bytes): + return reduce(operator.xor, bytes, 0) + checksums = list(map(checksum, segments)) return checksums diff --git a/django_q/migrations/0001_initial.py b/django_q/migrations/0001_initial.py index 63c0ec4..04d0776 100644 --- a/django_q/migrations/0001_initial.py +++ b/django_q/migrations/0001_initial.py @@ -5,61 +5,142 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='Schedule', + name="Schedule", fields=[ - ('id', models.AutoField(verbose_name='ID', auto_created=True, serialize=False, primary_key=True)), - ('func', models.CharField(max_length=256, help_text='e.g. module.tasks.function')), - ('hook', models.CharField(null=True, blank=True, max_length=256, help_text='e.g. module.tasks.result_function')), - ('args', models.CharField(null=True, blank=True, max_length=256, help_text="e.g. 1, 2, 'John'")), - ('kwargs', models.CharField(null=True, blank=True, max_length=256, help_text="e.g. x=1, y=2, name='John'")), - ('schedule_type', models.CharField(verbose_name='Schedule Type', choices=[('O', 'Once'), ('H', 'Hourly'), ('D', 'Daily'), ('W', 'Weekly'), ('M', 'Monthly'), ('Q', 'Quarterly'), ('Y', 'Yearly')], default='O', max_length=1)), - ('repeats', models.SmallIntegerField(verbose_name='Repeats', default=-1, help_text='n = n times, -1 = forever')), - ('next_run', models.DateTimeField(verbose_name='Next Run', default=django.utils.timezone.now, null=True)), - ('task', models.CharField(editable=False, null=True, max_length=100)), + ( + "id", + models.AutoField( + verbose_name="ID", + auto_created=True, + serialize=False, + primary_key=True, + ), + ), + ( + "func", + models.CharField( + max_length=256, help_text="e.g. module.tasks.function" + ), + ), + ( + "hook", + models.CharField( + null=True, + blank=True, + max_length=256, + help_text="e.g. module.tasks.result_function", + ), + ), + ( + "args", + models.CharField( + null=True, + blank=True, + max_length=256, + help_text="e.g. 1, 2, 'John'", + ), + ), + ( + "kwargs", + models.CharField( + null=True, + blank=True, + max_length=256, + help_text="e.g. x=1, y=2, name='John'", + ), + ), + ( + "schedule_type", + models.CharField( + verbose_name="Schedule Type", + choices=[ + ("O", "Once"), + ("H", "Hourly"), + ("D", "Daily"), + ("W", "Weekly"), + ("M", "Monthly"), + ("Q", "Quarterly"), + ("Y", "Yearly"), + ], + default="O", + max_length=1, + ), + ), + ( + "repeats", + models.SmallIntegerField( + verbose_name="Repeats", + default=-1, + help_text="n = n times, -1 = forever", + ), + ), + ( + "next_run", + models.DateTimeField( + verbose_name="Next Run", + default=django.utils.timezone.now, + null=True, + ), + ), + ("task", models.CharField(editable=False, null=True, max_length=100)), ], options={ - 'verbose_name': 'Scheduled task', - 'ordering': ['next_run'], + "verbose_name": "Scheduled task", + "ordering": ["next_run"], }, ), migrations.CreateModel( - name='Task', + name="Task", fields=[ - ('id', models.AutoField(verbose_name='ID', auto_created=True, serialize=False, primary_key=True)), - ('name', models.CharField(editable=False, max_length=100)), - ('func', models.CharField(max_length=256)), - ('hook', models.CharField(null=True, max_length=256)), - ('args', picklefield.fields.PickledObjectField(editable=False, null=True)), - ('kwargs', picklefield.fields.PickledObjectField(editable=False, null=True)), - ('result', picklefield.fields.PickledObjectField(editable=False, null=True)), - ('started', models.DateTimeField(editable=False)), - ('stopped', models.DateTimeField(editable=False)), - ('success', models.BooleanField(editable=False, default=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + auto_created=True, + serialize=False, + primary_key=True, + ), + ), + ("name", models.CharField(editable=False, max_length=100)), + ("func", models.CharField(max_length=256)), + ("hook", models.CharField(null=True, max_length=256)), + ( + "args", + picklefield.fields.PickledObjectField(editable=False, null=True), + ), + ( + "kwargs", + picklefield.fields.PickledObjectField(editable=False, null=True), + ), + ( + "result", + picklefield.fields.PickledObjectField(editable=False, null=True), + ), + ("started", models.DateTimeField(editable=False)), + ("stopped", models.DateTimeField(editable=False)), + ("success", models.BooleanField(editable=False, default=True)), ], ), migrations.CreateModel( - name='Failure', - fields=[ - ], + name="Failure", + fields=[], options={ - 'verbose_name': 'Failed task', - 'proxy': True, + "verbose_name": "Failed task", + "proxy": True, }, - bases=('django_q.task',), + bases=("django_q.task",), ), migrations.CreateModel( - name='Success', - fields=[ - ], + name="Success", + fields=[], options={ - 'verbose_name': 'Successful task', - 'proxy': True, + "verbose_name": "Successful task", + "proxy": True, }, - bases=('django_q.task',), + bases=("django_q.task",), ), ] diff --git a/django_q/migrations/0002_auto_20150630_1624.py b/django_q/migrations/0002_auto_20150630_1624.py index 5dd37e5..bdbc7b2 100644 --- a/django_q/migrations/0002_auto_20150630_1624.py +++ b/django_q/migrations/0002_auto_20150630_1624.py @@ -4,18 +4,22 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('django_q', '0001_initial'), + ("django_q", "0001_initial"), ] operations = [ migrations.AlterField( - model_name='schedule', - name='args', - field=models.TextField(help_text="e.g. 1, 2, 'John'", blank=True, null=True), + model_name="schedule", + name="args", + field=models.TextField( + help_text="e.g. 1, 2, 'John'", blank=True, null=True + ), ), migrations.AlterField( - model_name='schedule', - name='kwargs', - field=models.TextField(help_text="e.g. x=1, y=2, name='John'", blank=True, null=True), + model_name="schedule", + name="kwargs", + field=models.TextField( + help_text="e.g. x=1, y=2, name='John'", blank=True, null=True + ), ), ] diff --git a/django_q/migrations/0003_auto_20150708_1326.py b/django_q/migrations/0003_auto_20150708_1326.py index 2aa5279..b667416 100644 --- a/django_q/migrations/0003_auto_20150708_1326.py +++ b/django_q/migrations/0003_auto_20150708_1326.py @@ -4,29 +4,41 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('django_q', '0002_auto_20150630_1624'), + ("django_q", "0002_auto_20150630_1624"), ] operations = [ migrations.AlterModelOptions( - name='failure', - options={'verbose_name_plural': 'Failed tasks', 'verbose_name': 'Failed task'}, + name="failure", + options={ + "verbose_name_plural": "Failed tasks", + "verbose_name": "Failed task", + }, ), migrations.AlterModelOptions( - name='schedule', - options={'verbose_name_plural': 'Scheduled tasks', 'ordering': ['next_run'], 'verbose_name': 'Scheduled task'}, + name="schedule", + options={ + "verbose_name_plural": "Scheduled tasks", + "ordering": ["next_run"], + "verbose_name": "Scheduled task", + }, ), migrations.AlterModelOptions( - name='success', - options={'verbose_name_plural': 'Successful tasks', 'verbose_name': 'Successful task'}, + name="success", + options={ + "verbose_name_plural": "Successful tasks", + "verbose_name": "Successful task", + }, ), migrations.RemoveField( - model_name='task', - name='id', + model_name="task", + name="id", ), migrations.AddField( - model_name='task', - name='id', - field=models.CharField(max_length=32, primary_key=True, editable=False, serialize=False), + model_name="task", + name="id", + field=models.CharField( + max_length=32, primary_key=True, editable=False, serialize=False + ), ), ] diff --git a/django_q/migrations/0004_auto_20150710_1043.py b/django_q/migrations/0004_auto_20150710_1043.py index 0197cfa..0d2391a 100644 --- a/django_q/migrations/0004_auto_20150710_1043.py +++ b/django_q/migrations/0004_auto_20150710_1043.py @@ -1,23 +1,31 @@ -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('django_q', '0003_auto_20150708_1326'), + ("django_q", "0003_auto_20150708_1326"), ] operations = [ migrations.AlterModelOptions( - name='failure', - options={'verbose_name_plural': 'Failed tasks', 'verbose_name': 'Failed task', 'ordering': ['-stopped']}, + name="failure", + options={ + "verbose_name_plural": "Failed tasks", + "verbose_name": "Failed task", + "ordering": ["-stopped"], + }, ), migrations.AlterModelOptions( - name='success', - options={'verbose_name_plural': 'Successful tasks', 'verbose_name': 'Successful task', 'ordering': ['-stopped']}, + name="success", + options={ + "verbose_name_plural": "Successful tasks", + "verbose_name": "Successful task", + "ordering": ["-stopped"], + }, ), migrations.AlterModelOptions( - name='task', - options={'ordering': ['-stopped']}, + name="task", + options={"ordering": ["-stopped"]}, ), ] diff --git a/django_q/migrations/0005_auto_20150718_1506.py b/django_q/migrations/0005_auto_20150718_1506.py index 105c5d6..ba96219 100644 --- a/django_q/migrations/0005_auto_20150718_1506.py +++ b/django_q/migrations/0005_auto_20150718_1506.py @@ -4,18 +4,18 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('django_q', '0004_auto_20150710_1043'), + ("django_q", "0004_auto_20150710_1043"), ] operations = [ migrations.AddField( - model_name='schedule', - name='name', + model_name="schedule", + name="name", field=models.CharField(max_length=100, null=True), ), migrations.AddField( - model_name='task', - name='group', + model_name="task", + name="group", field=models.CharField(max_length=100, null=True, editable=False), ), ] diff --git a/django_q/migrations/0006_auto_20150805_1817.py b/django_q/migrations/0006_auto_20150805_1817.py index 5c74bb6..c6c23a1 100644 --- a/django_q/migrations/0006_auto_20150805_1817.py +++ b/django_q/migrations/0006_auto_20150805_1817.py @@ -4,18 +4,36 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('django_q', '0005_auto_20150718_1506'), + ("django_q", "0005_auto_20150718_1506"), ] operations = [ migrations.AddField( - model_name='schedule', - name='minutes', - field=models.PositiveSmallIntegerField(help_text='Number of minutes for the Minutes type', blank=True, null=True), + model_name="schedule", + name="minutes", + field=models.PositiveSmallIntegerField( + help_text="Number of minutes for the Minutes type", + blank=True, + null=True, + ), ), migrations.AlterField( - model_name='schedule', - name='schedule_type', - field=models.CharField(max_length=1, choices=[('O', 'Once'), ('I', 'Minutes'), ('H', 'Hourly'), ('D', 'Daily'), ('W', 'Weekly'), ('M', 'Monthly'), ('Q', 'Quarterly'), ('Y', 'Yearly')], default='O', verbose_name='Schedule Type'), + model_name="schedule", + name="schedule_type", + field=models.CharField( + max_length=1, + choices=[ + ("O", "Once"), + ("I", "Minutes"), + ("H", "Hourly"), + ("D", "Daily"), + ("W", "Weekly"), + ("M", "Monthly"), + ("Q", "Quarterly"), + ("Y", "Yearly"), + ], + default="O", + verbose_name="Schedule Type", + ), ), ] diff --git a/django_q/migrations/0007_ormq.py b/django_q/migrations/0007_ormq.py index dfc4cd3..8f635b3 100644 --- a/django_q/migrations/0007_ormq.py +++ b/django_q/migrations/0007_ormq.py @@ -4,21 +4,29 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('django_q', '0006_auto_20150805_1817'), + ("django_q", "0006_auto_20150805_1817"), ] operations = [ migrations.CreateModel( - name='OrmQ', + name="OrmQ", fields=[ - ('id', models.AutoField(primary_key=True, auto_created=True, verbose_name='ID', serialize=False)), - ('key', models.CharField(max_length=100)), - ('payload', models.TextField()), - ('lock', models.DateTimeField(null=True)), + ( + "id", + models.AutoField( + primary_key=True, + auto_created=True, + verbose_name="ID", + serialize=False, + ), + ), + ("key", models.CharField(max_length=100)), + ("payload", models.TextField()), + ("lock", models.DateTimeField(null=True)), ], options={ - 'verbose_name_plural': 'Queued tasks', - 'verbose_name': 'Queued task', + "verbose_name_plural": "Queued tasks", + "verbose_name": "Queued task", }, ), ] diff --git a/django_q/migrations/0008_auto_20160224_1026.py b/django_q/migrations/0008_auto_20160224_1026.py index 02954a4..d94c586 100644 --- a/django_q/migrations/0008_auto_20160224_1026.py +++ b/django_q/migrations/0008_auto_20160224_1026.py @@ -4,13 +4,13 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('django_q', '0007_ormq'), + ("django_q", "0007_ormq"), ] operations = [ migrations.AlterField( - model_name='schedule', - name='name', + model_name="schedule", + name="name", field=models.CharField(blank=True, max_length=100, null=True), ), ] diff --git a/django_q/migrations/0009_auto_20171009_0915.py b/django_q/migrations/0009_auto_20171009_0915.py index 0b6d14f..2c4b266 100644 --- a/django_q/migrations/0009_auto_20171009_0915.py +++ b/django_q/migrations/0009_auto_20171009_0915.py @@ -4,13 +4,17 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('django_q', '0008_auto_20160224_1026'), + ("django_q", "0008_auto_20160224_1026"), ] operations = [ migrations.AlterField( - model_name='schedule', - name='repeats', - field=models.IntegerField(default=-1, help_text='n = n times, -1 = forever', verbose_name='Repeats'), + model_name="schedule", + name="repeats", + field=models.IntegerField( + default=-1, + help_text="n = n times, -1 = forever", + verbose_name="Repeats", + ), ), ] diff --git a/django_q/migrations/0010_auto_20200610_0856.py b/django_q/migrations/0010_auto_20200610_0856.py index b87e08a..783b895 100644 --- a/django_q/migrations/0010_auto_20200610_0856.py +++ b/django_q/migrations/0010_auto_20200610_0856.py @@ -5,23 +5,29 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('django_q', '0009_auto_20171009_0915'), + ("django_q", "0009_auto_20171009_0915"), ] operations = [ migrations.AlterField( - model_name='task', - name='args', - field=picklefield.fields.PickledObjectField(editable=False, null=True, protocol=-1), + model_name="task", + name="args", + field=picklefield.fields.PickledObjectField( + editable=False, null=True, protocol=-1 + ), ), migrations.AlterField( - model_name='task', - name='kwargs', - field=picklefield.fields.PickledObjectField(editable=False, null=True, protocol=-1), + model_name="task", + name="kwargs", + field=picklefield.fields.PickledObjectField( + editable=False, null=True, protocol=-1 + ), ), migrations.AlterField( - model_name='task', - name='result', - field=picklefield.fields.PickledObjectField(editable=False, null=True, protocol=-1), + model_name="task", + name="result", + field=picklefield.fields.PickledObjectField( + editable=False, null=True, protocol=-1 + ), ), ] diff --git a/django_q/migrations/0011_auto_20200628_1055.py b/django_q/migrations/0011_auto_20200628_1055.py index f4997c3..1616b8a 100644 --- a/django_q/migrations/0011_auto_20200628_1055.py +++ b/django_q/migrations/0011_auto_20200628_1055.py @@ -6,18 +6,35 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('django_q', '0010_auto_20200610_0856'), + ("django_q", "0010_auto_20200610_0856"), ] operations = [ migrations.AddField( - model_name='schedule', - name='cron', - field=models.CharField(blank=True, help_text='Cron expression', max_length=100, null=True), + model_name="schedule", + name="cron", + field=models.CharField( + blank=True, help_text="Cron expression", max_length=100, null=True + ), ), migrations.AlterField( - model_name='schedule', - name='schedule_type', - field=models.CharField(choices=[('O', 'Once'), ('I', 'Minutes'), ('H', 'Hourly'), ('D', 'Daily'), ('W', 'Weekly'), ('M', 'Monthly'), ('Q', 'Quarterly'), ('Y', 'Yearly'), ('C', 'Cron')], default='O', max_length=1, verbose_name='Schedule Type'), + model_name="schedule", + name="schedule_type", + field=models.CharField( + choices=[ + ("O", "Once"), + ("I", "Minutes"), + ("H", "Hourly"), + ("D", "Daily"), + ("W", "Weekly"), + ("M", "Monthly"), + ("Q", "Quarterly"), + ("Y", "Yearly"), + ("C", "Cron"), + ], + default="O", + max_length=1, + verbose_name="Schedule Type", + ), ), ] diff --git a/django_q/migrations/0012_auto_20200702_1608.py b/django_q/migrations/0012_auto_20200702_1608.py index 397631f..0bc1fbf 100644 --- a/django_q/migrations/0012_auto_20200702_1608.py +++ b/django_q/migrations/0012_auto_20200702_1608.py @@ -8,13 +8,19 @@ import django_q.models class Migration(migrations.Migration): dependencies = [ - ('django_q', '0011_auto_20200628_1055'), + ("django_q", "0011_auto_20200628_1055"), ] operations = [ migrations.AlterField( - model_name='schedule', - name='cron', - field=models.CharField(blank=True, help_text='Cron expression', max_length=100, null=True, validators=[django_q.models.validate_cron]), + model_name="schedule", + name="cron", + field=models.CharField( + blank=True, + help_text="Cron expression", + max_length=100, + null=True, + validators=[django_q.models.validate_cron], + ), ), ] diff --git a/django_q/migrations/0013_task_attempt_count.py b/django_q/migrations/0013_task_attempt_count.py index 30d03be..4e0eba7 100644 --- a/django_q/migrations/0013_task_attempt_count.py +++ b/django_q/migrations/0013_task_attempt_count.py @@ -6,13 +6,13 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('django_q', '0012_auto_20200702_1608'), + ("django_q", "0012_auto_20200702_1608"), ] operations = [ migrations.AddField( - model_name='task', - name='attempt_count', + model_name="task", + name="attempt_count", field=models.IntegerField(default=0), ), ] diff --git a/django_q/migrations/0014_schedule_cluster.py b/django_q/migrations/0014_schedule_cluster.py index a2ce109..165cf99 100644 --- a/django_q/migrations/0014_schedule_cluster.py +++ b/django_q/migrations/0014_schedule_cluster.py @@ -6,13 +6,13 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('django_q', '0013_task_attempt_count'), + ("django_q", "0013_task_attempt_count"), ] operations = [ migrations.AddField( - model_name='schedule', - name='cluster', + model_name="schedule", + name="cluster", field=models.CharField(blank=True, default=None, max_length=100, null=True), ), ] diff --git a/django_q/migrations/0015_alter_schedule_schedule_type.py b/django_q/migrations/0015_alter_schedule_schedule_type.py index fd3fcec..4bb7b5f 100644 --- a/django_q/migrations/0015_alter_schedule_schedule_type.py +++ b/django_q/migrations/0015_alter_schedule_schedule_type.py @@ -6,13 +6,30 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('django_q', '0014_schedule_cluster'), + ("django_q", "0014_schedule_cluster"), ] operations = [ migrations.AlterField( - model_name='schedule', - name='schedule_type', - field=models.CharField(choices=[('O', 'Once'), ('I', 'Minutes'), ('H', 'Hourly'), ('D', 'Daily'), ('W', 'Weekly'), ('BW', 'Biweekly'), ('M', 'Monthly'), ('BM', 'Bimonthly'), ('Q', 'Quarterly'), ('Y', 'Yearly'), ('C', 'Cron')], default='O', max_length=2, verbose_name='Schedule Type'), + model_name="schedule", + name="schedule_type", + field=models.CharField( + choices=[ + ("O", "Once"), + ("I", "Minutes"), + ("H", "Hourly"), + ("D", "Daily"), + ("W", "Weekly"), + ("BW", "Biweekly"), + ("M", "Monthly"), + ("BM", "Bimonthly"), + ("Q", "Quarterly"), + ("Y", "Yearly"), + ("C", "Cron"), + ], + default="O", + max_length=2, + verbose_name="Schedule Type", + ), ), ] diff --git a/django_q/models.py b/django_q/models.py index 05aa0fe..eed8901 100644 --- a/django_q/models.py +++ b/django_q/models.py @@ -15,6 +15,7 @@ from picklefield.fields import dbsafe_decode # Local from django_q.conf import croniter from django_q.signing import SignedPackage + from .utils import get_func_repr @@ -229,7 +230,6 @@ class Schedule(models.Model): last_run.allow_tags = True last_run.short_description = _("last_run") - class Meta: app_label = "django_q" verbose_name = _("Scheduled task") diff --git a/django_q/monitor.py b/django_q/monitor.py index 20a670d..1c89f6e 100644 --- a/django_q/monitor.py +++ b/django_q/monitor.py @@ -19,28 +19,30 @@ try: except ImportError: psutil = None -# optional -try: - from blessed import Terminal -except ImportError: - pass def get_process_mb(pid): try: process = psutil.Process(pid) - mb_used = round(process.memory_info().rss / 1024 ** 2, 2) + mb_used = round(process.memory_info().rss / 1024**2, 2) except psutil.NoSuchProcess: mb_used = "NO_PROCESS_FOUND" return mb_used -BLESSED_INSTALL_MESSAGE = "Blessed is not installed. Please install blessed to use this: https://pypi.org/project/blessed/" + +BLESSED_INSTALL_MESSAGE = ( + "Blessed is not installed. Please install blessed to use this: " + "https://pypi.org/project/blessed/" +) + def monitor(run_once=False, broker=None): if not broker: broker = get_broker() try: + from blessed import Terminal + term = Terminal() - except: + except ImportError: print(BLESSED_INSTALL_MESSAGE) return @@ -204,8 +206,10 @@ def info(broker=None): if not broker: broker = get_broker() try: + from blessed import Terminal + term = Terminal() - except: + except ImportError: print(BLESSED_INSTALL_MESSAGE) return @@ -256,9 +260,12 @@ def info(broker=None): print( term.black_on_green( term.center( - _( - '-- %(prefix)s %(version)s on %(info)s --' - ) % {'prefix': Conf.PREFIX.capitalize(), 'version': ".".join(str(v) for v in VERSION), 'info': broker.info()} + _("-- %(prefix)s %(version)s on %(info)s --") + % { + "prefix": Conf.PREFIX.capitalize(), + "version": ".".join(str(v) for v in VERSION), + "info": broker.info(), + } ) ) ) @@ -293,7 +300,7 @@ def info(broker=None): + term.move_x(1 * col_width) + term.white(str(models.Schedule.objects.count())) + term.move_x(2 * col_width) - + term.cyan(_("Tasks/%(per)s") % {'per': per}) + + term.cyan(_("Tasks/%(per)s") % {"per": per}) + term.move_x(3 * col_width) + term.white(f"{tasks_per:.2f}") + term.move_x(4 * col_width) @@ -308,8 +315,10 @@ def memory(run_once=False, workers=False, broker=None): if not broker: broker = get_broker() try: + from blessed import Terminal + term = Terminal() - except: + except ImportError: print(BLESSED_INSTALL_MESSAGE) return broker.ping() @@ -389,7 +398,7 @@ def memory(run_once=False, workers=False, broker=None): ) # memory available (MB) memory_available = round( - psutil.virtual_memory().available / 1024 ** 2, 2 + psutil.virtual_memory().available / 1024**2, 2 ) if memory_available_percentage < MEMORY_AVAILABLE_LOWEST_PERCENTAGE: MEMORY_AVAILABLE_LOWEST_PERCENTAGE = memory_available_percentage @@ -413,7 +422,7 @@ def memory(run_once=False, workers=False, broker=None): print( term.move(row, 4 * col_width) + term.center( - round(psutil.virtual_memory().total / 1024 ** 2, 2), + round(psutil.virtual_memory().total / 1024**2, 2), width=col_width - 1, ) ) @@ -475,9 +484,13 @@ def memory(run_once=False, workers=False, broker=None): row += 1 print( term.move(row, 0) - + _("Available lowest (): %(memory_percent)s ((at)s)") % { 'memory_percent': str(MEMORY_AVAILABLE_LOWEST_PERCENTAGE), 'at': MEMORY_AVAILABLE_LOWEST_PERCENTAGE_AT.strftime( - "%Y-%m-%d %H:%M:%S+00:00" - )} + + _("Available lowest (): %(memory_percent)s ((at)s)") + % { + "memory_percent": str(MEMORY_AVAILABLE_LOWEST_PERCENTAGE), + "at": MEMORY_AVAILABLE_LOWEST_PERCENTAGE_AT.strftime( + "%Y-%m-%d %H:%M:%S+00:00" + ), + } ) # for testing if run_once: diff --git a/django_q/queues.py b/django_q/queues.py index ef3ea71..5af9a5a 100644 --- a/django_q/queues.py +++ b/django_q/queues.py @@ -1,5 +1,6 @@ """ -The code is derived from https://github.com/althonos/pronto/commit/3384010dfb4fc7c66a219f59276adef3288a886b +The code is derived from +https://github.com/althonos/pronto/commit/3384010dfb4fc7c66a219f59276adef3288a886b """ import multiprocessing import multiprocessing.queues diff --git a/django_q/signals.py b/django_q/signals.py index 0b7dd61..e52bfa0 100644 --- a/django_q/signals.py +++ b/django_q/signals.py @@ -19,16 +19,16 @@ def call_hook(sender, instance, **kwargs): f = getattr(m, func) except (ValueError, ImportError, AttributeError): logger.error( - _("malformed return hook '%(hook)s' for [%(name)s]") % {'hook': instance.hook, 'name': instance.name} + _("malformed return hook '%(hook)s' for [%(name)s]") + % {"hook": instance.hook, "name": instance.name} ) return try: f(instance) except Exception as e: logger.error( - _( - "return hook %(hook)s failed on [%(name)s] because %(error)s" - ) % {'hook': instance.hook, 'name': instance.name, 'error': str(e)} + _("return hook %(hook)s failed on [%(name)s] because %(error)s") + % {"hook": instance.hook, "name": instance.name, "error": str(e)} ) diff --git a/django_q/tasks.py b/django_q/tasks.py index a6694e1..b2aa7cf 100644 --- a/django_q/tasks.py +++ b/django_q/tasks.py @@ -600,7 +600,8 @@ class Chain: def result(self, wait=0): """ - return the full list of results from the chain when it finishes. blocks until timeout. + return the full list of results from the chain when it finishes. blocks until + timeout. :param int wait: how many milliseconds to wait for a result :return: an unsorted list of results """ @@ -611,7 +612,8 @@ class Chain: def fetch(self, failures=True, wait=0): """ - get the task result objects from the chain when it finishes. blocks until timeout. + get the task result objects from the chain when it finishes. blocks until + timeout. :param failures: include failed tasks :param int wait: how many milliseconds to wait for a result :return: an unsorted list of task objects diff --git a/django_q/tests/settings.py b/django_q/tests/settings.py index 9933ffb..b651adb 100644 --- a/django_q/tests/settings.py +++ b/django_q/tests/settings.py @@ -1,7 +1,5 @@ import os -import django - BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -130,5 +128,5 @@ Q_CLUSTER = { "testing": True, "log_level": "DEBUG", "django_redis": "default", - "redis": f"redis://{REDIS_HOST}:6379/0" + "redis": f"redis://{REDIS_HOST}:6379/0", } diff --git a/django_q/tests/test_brokers.py b/django_q/tests/test_brokers.py index 5f8c4da..c8d581b 100644 --- a/django_q/tests/test_brokers.py +++ b/django_q/tests/test_brokers.py @@ -2,12 +2,11 @@ import os from time import sleep import pytest -import redis from django_q.brokers import Broker, get_broker from django_q.conf import Conf from django_q.humanhash import uuid -from django_q.tests.settings import REDIS_HOST, MONGO_HOST +from django_q.tests.settings import MONGO_HOST, REDIS_HOST def test_broker(monkeypatch): diff --git a/django_q/tests/test_cluster.py b/django_q/tests/test_cluster.py index 57500ec..e973c67 100644 --- a/django_q/tests/test_cluster.py +++ b/django_q/tests/test_cluster.py @@ -1,8 +1,8 @@ -from datetime import datetime import os import sys import threading import uuid as uuidlib +from datetime import datetime from math import copysign from multiprocessing import Event, Value from time import sleep @@ -11,9 +11,6 @@ from typing import Optional import pytest from django.utils import timezone -myPath = os.path.dirname(os.path.abspath(__file__)) -sys.path.insert(0, myPath + "/../") - from django_q.brokers import Broker, get_broker from django_q.cluster import Cluster, Sentinel, monitor, pusher, save_task, worker from django_q.conf import Conf @@ -32,9 +29,12 @@ from django_q.tasks import ( result, result_group, ) -from django_q.tests.tasks import TaskError, multiply +from django_q.tests.tasks import multiply from django_q.utils import add_months, add_years +myPath = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, myPath + "/../") + class WordClass: def __init__(self): @@ -409,6 +409,7 @@ def test_recycle(broker, monkeypatch): assert Success.objects.count() == Conf.SAVE_LIMIT broker.delete_queue() + @pytest.mark.django_db def test_save_limit_per_func(broker, monkeypatch): # set up the Sentinel @@ -442,15 +443,14 @@ def test_save_limit_per_func(broker, monkeypatch): # run monitor monitor(result_queue) assert Success.objects.count() == 3 - assert set(Success.objects.filter().values_list('func', flat=True)) == { - 'django_q.tests.tasks.countdown', - 'django_q.tests.tasks.hello', - 'django_q.tests.tasks.multiply', + assert set(Success.objects.filter().values_list("func", flat=True)) == { + "django_q.tests.tasks.countdown", + "django_q.tests.tasks.hello", + "django_q.tests.tasks.multiply", } broker.delete_queue() - @pytest.mark.django_db def test_max_rss(broker, monkeypatch): # set up the Sentinel @@ -538,7 +538,6 @@ def test_attempt_count(broker, monkeypatch): assert saved_task.attempt_count == 1 sleep(0.5) # second save - old_stopped = task["stopped"] task["stopped"] = timezone.now() save_task(task, broker) saved_task = Task.objects.get(id=task["id"]) @@ -770,6 +769,7 @@ def test_add_months(): assert new_date.month == 2 assert new_date.day == 29 + @pytest.mark.django_db def test_add_years(): # add some months diff --git a/django_q/tests/test_scheduler.py b/django_q/tests/test_scheduler.py index c3c0ffc..82ecb22 100644 --- a/django_q/tests/test_scheduler.py +++ b/django_q/tests/test_scheduler.py @@ -11,7 +11,7 @@ from django.utils import timezone from django.utils.timezone import is_naive from django_q.brokers import Broker, get_broker -from django_q.cluster import monitor, pusher, scheduler, worker, localtime +from django_q.cluster import localtime, monitor, pusher, scheduler, worker from django_q.conf import Conf from django_q.queues import Queue from django_q.tasks import Schedule, fetch @@ -21,12 +21,15 @@ from django_q.tests.testing_utilities.multiple_database_routers import ( TestingMultipleAppsDatabaseRouter, TestingReplicaDatabaseRouter, ) -from django_q.utils import add_months, add_years +from django_q.utils import add_months @pytest.fixture def broker(monkeypatch) -> Broker: - """Patches the Conf object setting the DJANGO_REDIS attribute allowing a default redis configuration.""" + """ + Patches the Conf object setting the DJANGO_REDIS attribute allowing a default + redis configuration. + """ monkeypatch.setattr(Conf, "DJANGO_REDIS", "default") return get_broker() @@ -66,7 +69,7 @@ REPLICA_DATABASES = { } MULTIPLE_APPS_DATABASE_ROUTERS = [ - f"{TestingMultipleAppsDatabaseRouter.__module__}.{TestingMultipleAppsDatabaseRouter.__name__}" + f"{TestingMultipleAppsDatabaseRouter.__module__}.{TestingMultipleAppsDatabaseRouter.__name__}" # noqa: E501 ] MULTIPLE_APPS_DATABASES = { "default": { @@ -234,7 +237,7 @@ def test_scheduler(broker, monkeypatch): "django_q.tests.tasks.word_multiply", 2, word="catch_up", - schedule_type=Schedule.BIMONTHLY + schedule_type=Schedule.BIMONTHLY, ) scheduler(broker=broker) schedule = Schedule.objects.get(pk=schedule.pk) @@ -245,7 +248,7 @@ def test_scheduler(broker, monkeypatch): "django_q.tests.tasks.word_multiply", 2, word="catch_up", - schedule_type=Schedule.BIWEEKLY + schedule_type=Schedule.BIWEEKLY, ) scheduler(broker=broker) schedule = Schedule.objects.get(pk=schedule.pk) @@ -311,7 +314,8 @@ def test_scheduler_atomic_transaction_must_specify_a_database_when_no_replicas_a """ GIVEN a environment without a read replica database WHEN the scheduler is called - THEN the transaction atomic must be called using the configured database in the Conf.ORM settings. + THEN the transaction atomic must be called using the configured database in the + Conf.ORM settings. """ broker = orm_no_replica_broker with mock.patch("django_q.cluster.db") as mocked_db: @@ -324,13 +328,14 @@ def test_scheduler_atomic_transaction_must_specify_a_database_when_no_replicas_a DATABASE_ROUTERS=REPLICA_DATABASE_ROUTERS, DATABASES=REPLICA_DATABASES ) @pytest.mark.django_db -def test_scheduler_atomic_transaction_must_specify_no_database_when_read_write_replicas_are_used( +def test_scheduler_atomic_must_specify_no_db_when_read_write_replicas_are_used( orm_replica_broker: Broker, ): """ GIVEN a environment with a read/write configured replica database WHEN the scheduler is called - THEN the transaction must be called without a specific database, thus letting the database router pick. + THEN the transaction must be called without a specific database, thus letting the + database router pick. """ with mock.patch("django_q.cluster.db") as mocked_db: scheduler(broker=orm_replica_broker) @@ -342,13 +347,14 @@ def test_scheduler_atomic_transaction_must_specify_no_database_when_read_write_r DATABASE_ROUTERS=MULTIPLE_APPS_DATABASE_ROUTERS, DATABASES=MULTIPLE_APPS_DATABASES ) @pytest.mark.django_db -def test_scheduler_atomic_transaction_must_specify_the_database_based_on_router_redirection( +def test_scheduler_atomic_must_specify_the_database_based_on_router_redirection( orm_no_replica_broker: Broker, ): """ GIVEN a environment without a read replica database WHEN the scheduler is called - THEN the transaction atomic must be called using the configured database in the Conf.ORM settings. + THEN the transaction atomic must be called using the configured database in the + Conf.ORM settings. """ broker = orm_no_replica_broker with mock.patch("django_q.cluster.db") as mocked_db: diff --git a/django_q/utils.py b/django_q/utils.py index eed72be..c0c6f7f 100644 --- a/django_q/utils.py +++ b/django_q/utils.py @@ -1,6 +1,7 @@ +import calendar import inspect from datetime import date -import calendar + # credits: https://stackoverflow.com/a/4131114 # Made them aware of timezone @@ -8,21 +9,21 @@ def add_months(d, months): month = d.month - 1 + months year = d.year + month // 12 month = month % 12 + 1 - day = min(d.day, calendar.monthrange(year,month)[1]) + day = min(d.day, calendar.monthrange(year, month)[1]) return d.replace(year=year, month=month, day=day) + # credits: https://stackoverflow.com/a/15743908 -# Changed the last line to make it a little easier to read and changed it to move February 29 to 28 next year -# Also made them aware of timezone +# Changed the last line to make it a little easier to read and changed it to move +# February 29 to 28 next year. def add_years(d, years): """Return a date that's `years` years after the date (or datetime) object `d`. Return the same calendar date (month and day) in the destination year, if it exists, otherwise use the previous day (thus changing February 29 to February 28). - """ try: - return d.replace(year = d.year + years) + return d.replace(year=d.year + years) except ValueError: new_date = d + (date(d.year + years, 3, 1) - date(d.year, 3, 1)) return d.replace(year=new_date.year, month=new_date.month, day=new_date.day) @@ -32,11 +33,9 @@ def get_func_repr(func): # convert func to string if inspect.isfunction(func): return f"{func.__module__}.{func.__name__}" - elif inspect.ismethod(func) and hasattr(func.__self__, '__name__'): + elif inspect.ismethod(func) and hasattr(func.__self__, "__name__"): return ( - f"{func.__self__.__module__}." - f"{func.__self__.__name__}.{func.__name__}" + f"{func.__self__.__module__}." f"{func.__self__.__name__}.{func.__name__}" ) else: return str(func) - diff --git a/docs/conf.py b/docs/conf.py index 3a54996..7e47334 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -16,12 +16,10 @@ import os import sys -import sphinx_rtd_theme - myPath = os.path.dirname(os.path.abspath(__file__)) -sys.path.insert(0, myPath + '/../') -os.environ['DJANGO_SETTINGS_MODULE'] = 'django_q.tests.settings' -nitpick_ignore = [('py:class', 'datetime')] +sys.path.insert(0, myPath + "/../") +os.environ["DJANGO_SETTINGS_MODULE"] = "django_q.tests.settings" +nitpick_ignore = [("py:class", "datetime")] # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -37,50 +35,54 @@ nitpick_ignore = [('py:class', 'datetime')] # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx_rtd_theme', - 'sphinx.ext.todo', - 'sphinx.ext.intersphinx', + "sphinx_rtd_theme", + "sphinx.ext.todo", + "sphinx.ext.intersphinx", # 'sphinx.ext.autodoc' ] -intersphinx_mapping = {'python': ('https://docs.python.org/3.8', None), - 'django': ('https://docs.djangoproject.com/en/2.2/', - 'https://docs.djangoproject.com/en/2.2/_objects/')} +intersphinx_mapping = { + "python": ("https://docs.python.org/3.8", None), + "django": ( + "https://docs.djangoproject.com/en/2.2/", + "https://docs.djangoproject.com/en/2.2/_objects/", + ), +} # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # source_suffix = ['.rst', '.md'] -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. # source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = 'Django Q2' -copyright = '2015-2021, Ilan Steemers - 2022, Stan Triepels' -author = 'Ilan Steemers, Stan Triepels' +project = "Django Q2" +copyright = "2015-2021, Ilan Steemers - 2022, Stan Triepels" +author = "Ilan Steemers, Stan Triepels" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = '1.4' +version = "1.4" # The full version, including alpha/beta/rc tags. -release = '1.4.5' +release = "1.4.5" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = 'en' +language = "en" # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: @@ -90,7 +92,7 @@ language = 'en' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['_build'] +exclude_patterns = ["_build"] # The reST default role (used for this markup: `text`) to use for all # documents. @@ -108,7 +110,7 @@ add_module_names = False # show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] @@ -124,7 +126,7 @@ todo_include_todos = True # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'sphinx_rtd_theme' +html_theme = "sphinx_rtd_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -136,11 +138,11 @@ html_theme_options = { # 'github_banner': True, } html_sidebars = { - '**': [ - 'about.html', - 'navigation.html', - 'relations.html', - 'searchbox.html', + "**": [ + "about.html", + "navigation.html", + "relations.html", + "searchbox.html", ] } # Add any paths that contain custom themes here, relative to this directory. @@ -161,12 +163,12 @@ html_sidebars = { # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -html_favicon = '_static/favicon.ico' +html_favicon = "_static/favicon.ico" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied @@ -229,20 +231,17 @@ html_static_path = ['_static'] # html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. -htmlhelp_basename = 'DjangoQ2doc' +htmlhelp_basename = "DjangoQ2doc" # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. # 'preamble': '', - # Latex figure (float) alignment # 'figure_align': 'htbp', } @@ -251,8 +250,7 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'DjangoQ2.tex', 'Django Q2 Documentation', - 'Ilan Steemers', 'manual'), + (master_doc, "DjangoQ2.tex", "Django Q2 Documentation", "Ilan Steemers", "manual"), ] # The name of an image file (relative to this directory) to place at the top of @@ -280,10 +278,7 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'djangoq2', 'Django Q2 Documentation', - [author], 1) -] +man_pages = [(master_doc, "djangoq2", "Django Q2 Documentation", [author], 1)] # If true, show URL addresses after external links. @@ -296,9 +291,15 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'DjangoQ2', 'Django Q2 Documentation', - author, 'DjangoQ2', 'A multiprocessing distributed task queue for Django.', - 'Miscellaneous'), + ( + master_doc, + "DjangoQ2", + "Django Q2 Documentation", + author, + "DjangoQ2", + "A multiprocessing distributed task queue for Django.", + "Miscellaneous", + ), ] # Documents to append as an appendix to all manuals. diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..e14b761 --- /dev/null +++ b/tox.ini @@ -0,0 +1,2 @@ +[flake8] +max-line-length=88 From 256695578234a0fde9dd5760aa540941b60673b2 Mon Sep 17 00:00:00 2001 From: Andreas Andersen Date: Wed, 30 Nov 2022 15:03:20 +0100 Subject: [PATCH 17/39] Log exceptions with logger.exception (#42) Co-authored-by: Andreas Bok Andersen --- django_q/cluster.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/django_q/cluster.py b/django_q/cluster.py index e33a0a2..f34c81d 100644 --- a/django_q/cluster.py +++ b/django_q/cluster.py @@ -367,7 +367,7 @@ def pusher(task_queue: Queue, event: Event, broker: Broker = None): try: task_set = broker.dequeue() except Exception as e: - logger.error(e, traceback.format_exc()) + logger.exception("Failed to pull task from broker") # broker probably crashed. Let the sentinel handle it. sleep(10) break @@ -378,7 +378,7 @@ def pusher(task_queue: Queue, event: Event, broker: Broker = None): try: task = SignedPackage.loads(task[1]) except (TypeError, BadSignature) as e: - logger.error(e, traceback.format_exc()) + logger.exception("Failed to push task to queue") broker.fail(ack_id) continue task["ack_id"] = ack_id From c1d4858f622c7b05c825cc1f9d39cef6243ae3dc Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Wed, 30 Nov 2022 15:09:49 +0100 Subject: [PATCH 18/39] Release 1.4.6 (#43) --- CHANGELOG.md | 4 ++++ django_q/__init__.py | 2 +- docs/conf.py | 2 +- pyproject.toml | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ce8858..e458981 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,12 @@ ## [Unreleased](https://github.com/GDay/django-q2/tree/HEAD) + +## [v1.4.6](https://github.com/GDay/django-q2/tree/v1.4.6) (2022-11-30) + **Merged pull requests:** +- Fix: Log exceptions with logger.exception https://github.com/GDay/django-q2/pull/42 - Chore: flake8, isort, black https://github.com/GDay/django-q2/pull/40 ## [v1.4.5](https://github.com/GDay/django-q2/tree/v1.4.5) (2022-11-13) diff --git a/django_q/__init__.py b/django_q/__init__.py index 974cdc6..cd2e4bf 100644 --- a/django_q/__init__.py +++ b/django_q/__init__.py @@ -1,6 +1,6 @@ import django -VERSION = (1, 4, 5) +VERSION = (1, 4, 6) if django.VERSION < (3, 2): default_app_config = "django_q.apps.DjangoQConfig" diff --git a/docs/conf.py b/docs/conf.py index 7e47334..842f7b9 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -75,7 +75,7 @@ author = "Ilan Steemers, Stan Triepels" # The short X.Y version. version = "1.4" # The full version, including alpha/beta/rc tags. -release = "1.4.5" +release = "1.4.6" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pyproject.toml b/pyproject.toml index d5d52b6..8a109d2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "django-q2" -version = "1.4.5" +version = "1.4.6" packages = [ { include = "django_q" }, ] From 134a54dbeba0bbae8151cb9b7a3eb5f12951a5ef Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Wed, 21 Dec 2022 01:43:51 +0100 Subject: [PATCH 19/39] Chore: Fix badge and add download badge (#52) --- README.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 6a3c022..4667cbc 100644 --- a/README.rst +++ b/README.rst @@ -1,7 +1,7 @@ A multiprocessing distributed task queue for Django --------------------------------------------------- -|image0| |image1| |docs| +|image0| |image1| |docs| |downloads| :: @@ -245,4 +245,6 @@ Acknowledgements .. |docs| image:: https://readthedocs.org/projects/docs/badge/?version=latest :alt: Documentation Status :scale: 100 - :target: https://django-q.readthedocs.org/ + :target: https://django-q2.readthedocs.org/ +.. |downloads| image:: https://img.shields.io/pypi/dm/django-q2 + :target: https://img.shields.io/pypi/dm/django-q2 From cf3389129175e88e28a4f9935cfa4c9c7a3f797f Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Wed, 21 Dec 2022 01:44:10 +0100 Subject: [PATCH 20/39] Chore: Remove release drafter (#53) --- .github/release-drafter.yml | 37 ------------------------------- .github/workflows/release_log.yml | 14 ------------ 2 files changed, 51 deletions(-) delete mode 100755 .github/release-drafter.yml delete mode 100644 .github/workflows/release_log.yml diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml deleted file mode 100755 index 5ae4b0f..0000000 --- a/.github/release-drafter.yml +++ /dev/null @@ -1,37 +0,0 @@ -categories: - - - label: breaking - title: Breaking - - - label: feature - title: New - - - label: bug - title: "Bug Fixes" - - - label: dependencies - title: "Dependency Updates" - - - label: security - title: Security -name-template: v$NEXT_PATCH_VERSION -tag-template: v$NEXT_PATCH_VERSION -template: | - # Changes - $CHANGES -version-resolver: - major: - labels: - - breaking - - major - minor: - labels: - - feature - - minor - patch: - labels: - - bug - - dependencies - - security - - patch - default: patch \ No newline at end of file diff --git a/.github/workflows/release_log.yml b/.github/workflows/release_log.yml deleted file mode 100644 index 8c62eee..0000000 --- a/.github/workflows/release_log.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: Update release draft -on: - push: - branches: - - master -jobs: - update_release_draft: - runs-on: ubuntu-latest - steps: - - uses: release-drafter/release-drafter@v5 - with: - config-name: release-drafter.yml - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file From 4d454e4001d7600ca6e8a69282dd91da1f148ed9 Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Wed, 21 Dec 2022 01:44:34 +0100 Subject: [PATCH 21/39] Fix: Daylight saving time issue with scheduler (#47) --- django_q/cluster.py | 38 ++------------------ django_q/conf.py | 5 +++ django_q/models.py | 59 ++++++++++++++++++++++++++++++- django_q/tests/settings.py | 2 +- django_q/tests/test_scheduler.py | 60 +++++++++++++++++++++++++++++++- django_q/utils.py | 16 +++++++++ docs/configure.rst | 7 ++++ 7 files changed, 149 insertions(+), 38 deletions(-) diff --git a/django_q/cluster.py b/django_q/cluster.py index f34c81d..ba3408a 100644 --- a/django_q/cluster.py +++ b/django_q/cluster.py @@ -6,6 +6,7 @@ import socket import traceback import uuid from datetime import datetime, timedelta +from pytz import timezone as pytz_timezone from multiprocessing import Event, Process, Value, current_process from time import sleep @@ -43,7 +44,7 @@ from django_q.signals import post_execute, pre_execute from django_q.signing import BadSignature, SignedPackage from django_q.status import Stat, Status -from .utils import add_months, add_years, get_func_repr +from .utils import get_func_repr, localtime class Cluster: @@ -700,33 +701,7 @@ def scheduler(broker: Broker = None): if s.schedule_type != s.ONCE: next_run = s.next_run while True: - if s.schedule_type == s.MINUTES: - next_run = next_run + timedelta(minutes=(s.minutes or 1)) - elif s.schedule_type == s.HOURLY: - next_run = next_run + timedelta(hours=1) - elif s.schedule_type == s.DAILY: - next_run = next_run + timedelta(days=1) - elif s.schedule_type == s.WEEKLY: - next_run = next_run + timedelta(weeks=1) - elif s.schedule_type == s.BIWEEKLY: - next_run = next_run + timedelta(weeks=2) - elif s.schedule_type == s.MONTHLY: - next_run = add_months(next_run, 1) - elif s.schedule_type == s.BIMONTHLY: - next_run = add_months(next_run, 2) - elif s.schedule_type == s.QUARTERLY: - next_run = add_months(next_run, 3) - elif s.schedule_type == s.YEARLY: - next_run = add_years(next_run, 1) - elif s.schedule_type == s.CRON: - if not croniter: - raise ImportError( - _( - "Please install croniter to enable cron " - "expressions" - ) - ) - next_run = croniter(s.cron, localtime()).get_next(datetime) + next_run = s.calculate_next_run(next_run) if Conf.CATCH_UP or next_run > localtime(): break @@ -842,10 +817,3 @@ def rss_check(): elif psutil: return psutil.Process().memory_info().rss >= Conf.MAX_RSS * 1024 return False - - -def localtime() -> datetime: - """Override for timezone.localtime to deal with naive times and local times""" - if settings.USE_TZ: - return timezone.localtime() - return datetime.now() diff --git a/django_q/conf.py b/django_q/conf.py index 77ef602..3d32f0b 100644 --- a/django_q/conf.py +++ b/django_q/conf.py @@ -211,6 +211,11 @@ class Conf: # to manage workarounds during testing TESTING = conf.get("testing", False) + # Timezone for next_run, overrules Django timezone + TIME_ZONE = None + if settings.USE_TZ: + TIME_ZONE = conf.get("time_zone", settings.TIME_ZONE) + # logger logger = logging.getLogger("django-q") diff --git a/django_q/models.py b/django_q/models.py index eed8901..1e5048a 100644 --- a/django_q/models.py +++ b/django_q/models.py @@ -1,3 +1,5 @@ +from datetime import datetime, timedelta + # Django from django import get_version from django.core.exceptions import ValidationError @@ -5,6 +7,7 @@ from django.db import models from django.template.defaultfilters import truncatechars from django.urls import reverse from django.utils import timezone +from django.utils.timezone import is_aware from django.utils.html import format_html from django.utils.translation import gettext_lazy as _ @@ -13,8 +16,9 @@ from picklefield import PickledObjectField from picklefield.fields import dbsafe_decode # Local -from django_q.conf import croniter +from django_q.conf import croniter, Conf from django_q.signing import SignedPackage +from django_q.utils import localtime, add_months, add_years from .utils import get_func_repr @@ -208,6 +212,59 @@ class Schedule(models.Model): task = models.CharField(max_length=100, null=True, editable=False) cluster = models.CharField(max_length=100, default=None, null=True, blank=True) + def calculate_next_run(self, next_run=None): + # next run is always in UTC + next_run = next_run or self.next_run + + if self.schedule_type == self.CRON: + if not croniter: + raise ImportError( + _("Please install croniter to enable cron expressions") + ) + return croniter(self.cron, localtime()).get_next(datetime) + + if self.schedule_type == self.MINUTES: + add = timedelta(minutes=(self.minutes or 1)) + elif self.schedule_type == self.HOURLY: + add = timedelta(hours=1) + elif self.schedule_type == self.DAILY: + add = timedelta(days=1) + elif self.schedule_type == self.WEEKLY: + add = timedelta(weeks=1) + elif self.schedule_type == self.BIWEEKLY: + add = timedelta(weeks=2) + elif self.schedule_type == self.MONTHLY: + add = timedelta(days=(add_months(next_run, 1) - next_run).days) + elif self.schedule_type == self.BIMONTHLY: + add = timedelta(days=(add_months(next_run, 2) - next_run).days) + elif self.schedule_type == self.QUARTERLY: + add = timedelta(days=(add_months(next_run, 3) - next_run).days) + elif self.schedule_type == self.YEARLY: + add = timedelta(days=(add_years(next_run, 1) - next_run).days) + + # add normal timedelta, we will correct this later based on timezone + next_run += add + + # DST differencers don't matter with minutes, hourly or yearly, so skip those + if self.schedule_type not in [self.MINUTES, self.HOURLY, self.YEARLY]: + # Get localtimes and then remove the tzinfo, so we can get the actual difference + current_next_run = localtime(next_run - add).replace(tzinfo=None) + new_next_run = localtime(next_run).replace(tzinfo=None) + + # get the difference between them, this should be (-)1 or (-)0.5 hour + # based on DST active or not + extra_diff = (new_next_run - current_next_run) - add + + # if we have one positive hour difference, then subtract it, so we are even + # and vice versa. In most cases, this will be 0, as there won't be a + # timezone diff + if extra_diff > timedelta(hours=0): + next_run -= extra_diff + else: + next_run += extra_diff + + return next_run + def success(self): if self.task and Task.objects.filter(id=self.task): return Task.objects.get(id=self.task).success diff --git a/django_q/tests/settings.py b/django_q/tests/settings.py index b651adb..b624644 100644 --- a/django_q/tests/settings.py +++ b/django_q/tests/settings.py @@ -75,7 +75,7 @@ DATABASES = { LANGUAGE_CODE = "en-us" -TIME_ZONE = "UTC" +TIME_ZONE = "Europe/Amsterdam" USE_I18N = True diff --git a/django_q/tests/test_scheduler.py b/django_q/tests/test_scheduler.py index 82ecb22..f53e7b4 100644 --- a/django_q/tests/test_scheduler.py +++ b/django_q/tests/test_scheduler.py @@ -1,5 +1,6 @@ import os -from datetime import timedelta +import pytz +from datetime import datetime, timedelta from multiprocessing import Event, Value from unittest import mock @@ -83,6 +84,63 @@ MULTIPLE_APPS_DATABASES = { } +@pytest.mark.django_db +def test_scheduler_daylight_saving_time_daily(broker, monkeypatch): + # Set up a startdate in the Amsterdam timezone (without dst 1 hour ahead). The + # 28th of March 2021 is the day when sunlight saving starts (at 2 am) + + monkeypatch.setattr(Conf, "TIME_ZONE", "Europe/Amsterdam") + tz = pytz.timezone('Europe/Amsterdam') + broker.list_key = "scheduler_test:q" + # Let's start a schedule at 1 am on the 27th of March. This is in AMS timezone. + # So, 2021-03-27 00:00:00 when saved (due to TZ being Amsterdam and saved in UTC) + start_date = datetime(2021, 3, 27, 1, 0, 0) + + # Create schedule with the next run date on the start date. It will move one day + # forward when we run the scheduler + schedule = create_schedule( + "math.copysign", + 1, + -1, + name="test math", + schedule_type=Schedule.DAILY, + next_run=start_date, + ) + + # Run scheduler so we get the next run date + scheduler(broker=broker) + schedule.refresh_from_db() + + # It's now the day after exactly at midnight UTC + next_run = schedule.next_run + assert str(next_run) == "2021-03-28 00:00:00+00:00" + + # In the Amsterdam timezone, it's 1 hour over midnight (+01) + next_run = next_run.astimezone(tz) + assert str(next_run) == "2021-03-28 01:00:00+01:00" + + # Run scheduler so we get the next run date + scheduler(broker=broker) + schedule.refresh_from_db() + + next_run = schedule.next_run + + assert str(next_run) == "2021-03-28 23:00:00+00:00" + next_run = next_run.astimezone(tz) + # In the Amsterdam timezone, it's 1 hour over midnight (+02) + assert str(next_run) == "2021-03-29 01:00:00+02:00" + + # Run scheduler so we get the next run date + scheduler(broker=broker) + schedule.refresh_from_db() + + next_run = schedule.next_run + + assert str(next_run) == "2021-03-29 23:00:00+00:00" + next_run = next_run.astimezone(tz) + assert str(next_run) == "2021-03-30 01:00:00+02:00" + + @pytest.mark.django_db def test_scheduler(broker, monkeypatch): broker.list_key = "scheduler_test:q" diff --git a/django_q/utils.py b/django_q/utils.py index c0c6f7f..8c2d293 100644 --- a/django_q/utils.py +++ b/django_q/utils.py @@ -1,7 +1,13 @@ +from datetime import datetime +import pytz import calendar import inspect from datetime import date +from django.utils import timezone +from django.conf import settings + +from django_q.conf import Conf # credits: https://stackoverflow.com/a/4131114 # Made them aware of timezone @@ -39,3 +45,13 @@ def get_func_repr(func): ) else: return str(func) + + +def localtime(value=None) -> datetime: + """Override for timezone.localtime to deal with naive times and local times""" + if settings.USE_TZ: + return timezone.localtime(value=value, timezone=pytz.timezone(Conf.TIME_ZONE)) + if value is None: + return datetime.now() + else: + return value diff --git a/docs/configure.rst b/docs/configure.rst index 32d6f11..1b83fe6 100644 --- a/docs/configure.rst +++ b/docs/configure.rst @@ -70,6 +70,13 @@ Set this to something that makes sense for your project. Can be overridden for i See :ref:`retry` for details how to set values for timeout and retry. +.. _time_zone: + +time_zone +~~~~~~~ + +The timezone that is used for task scheduling. Use this if you are having issue with DST. The scheduler uses UTC to calculate the next date and will therefore ignore any DST changes. This will cause 1 hour or 0.5 hour changes in the schedule when time is moved one hour ahead or back. Defaults to `settings.TIME_ZONE` if `USE_TZ` is enabled. + .. _ack_failures: ack_failures From e78e473be3d131d786e2b50b854466390d4916a9 Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Wed, 21 Dec 2022 01:44:59 +0100 Subject: [PATCH 22/39] Fix: handling exceptions inside job function (#51) --- django_q/cluster.py | 13 +++---------- django_q/tests/test_cluster.py | 4 ++-- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/django_q/cluster.py b/django_q/cluster.py index ba3408a..235bd64 100644 --- a/django_q/cluster.py +++ b/django_q/cluster.py @@ -485,19 +485,12 @@ def worker( try: res = f(*task["args"], **task["kwargs"]) result = (res, True) - except Exception: - result = ( - _( - "Could not process '%(func_name)s'. Check the location of the " - "function and the args/kwargs." - ) - % {"func_name": func_name}, - False, - ) + except Exception as e: + result = (f"{e} : {traceback.format_exc()}", False) if error_reporter: error_reporter.report() if task.get("sync", False): - raise Exception(result) + raise with timer.get_lock(): # Process result task["result"] = result[0] diff --git a/django_q/tests/test_cluster.py b/django_q/tests/test_cluster.py index e973c67..da240e8 100644 --- a/django_q/tests/test_cluster.py +++ b/django_q/tests/test_cluster.py @@ -29,7 +29,7 @@ from django_q.tasks import ( result, result_group, ) -from django_q.tests.tasks import multiply +from django_q.tests.tasks import multiply, TaskError from django_q.utils import add_months, add_years myPath = os.path.dirname(os.path.abspath(__file__)) @@ -64,7 +64,7 @@ def test_sync(broker): @pytest.mark.django_db def test_sync_raise_exception(broker): - with pytest.raises(Exception): + with pytest.raises(TaskError): async_task("django_q.tests.tasks.raise_exception", broker=broker, sync=True) From cf33275d92ecb510aa0a63ac1432dd92b06856ef Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Wed, 21 Dec 2022 01:53:10 +0100 Subject: [PATCH 23/39] Release v1.4.7 (#54) --- CHANGELOG.md | 8 ++++++++ django_q/__init__.py | 2 +- docs/conf.py | 2 +- pyproject.toml | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e458981..7a1bcc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ ## [Unreleased](https://github.com/GDay/django-q2/tree/HEAD) +## [v1.4.7](https://github.com/GDay/django-q2/tree/v1.4.7) (2022-12-21) + +**Merged pull requests:** + +- Fix: handling exceptions inside job function https://github.com/GDay/django-q2/pull/51 +- Fix: Daylight saving time issue with scheduler https://github.com/GDay/django-q2/pull/47 +- Chore: Fix badge and add download badge https://github.com/GDay/django-q2/pull/52 +- Chore: Remove release drafter https://github.com/GDay/django-q2/pull/53 ## [v1.4.6](https://github.com/GDay/django-q2/tree/v1.4.6) (2022-11-30) diff --git a/django_q/__init__.py b/django_q/__init__.py index cd2e4bf..f4e426d 100644 --- a/django_q/__init__.py +++ b/django_q/__init__.py @@ -1,6 +1,6 @@ import django -VERSION = (1, 4, 6) +VERSION = (1, 4, 7) if django.VERSION < (3, 2): default_app_config = "django_q.apps.DjangoQConfig" diff --git a/docs/conf.py b/docs/conf.py index 842f7b9..fe5cde1 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -75,7 +75,7 @@ author = "Ilan Steemers, Stan Triepels" # The short X.Y version. version = "1.4" # The full version, including alpha/beta/rc tags. -release = "1.4.6" +release = "1.4.7" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pyproject.toml b/pyproject.toml index 8a109d2..1340f41 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "django-q2" -version = "1.4.6" +version = "1.4.7" packages = [ { include = "django_q" }, ] From ce81059da831677989075d89a9845dc7d615c203 Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Wed, 21 Dec 2022 03:42:38 +0100 Subject: [PATCH 24/39] Fix: allow both ZoneInfo and Pytz depending on django version (#55) --- django_q/cluster.py | 1 - django_q/tests/test_scheduler.py | 13 +++++++++++-- django_q/utils.py | 21 +++++++++++++++++++-- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/django_q/cluster.py b/django_q/cluster.py index 235bd64..7bd9f53 100644 --- a/django_q/cluster.py +++ b/django_q/cluster.py @@ -6,7 +6,6 @@ import socket import traceback import uuid from datetime import datetime, timedelta -from pytz import timezone as pytz_timezone from multiprocessing import Event, Process, Value, current_process from time import sleep diff --git a/django_q/tests/test_scheduler.py b/django_q/tests/test_scheduler.py index f53e7b4..c4a3f73 100644 --- a/django_q/tests/test_scheduler.py +++ b/django_q/tests/test_scheduler.py @@ -1,10 +1,10 @@ import os -import pytz from datetime import datetime, timedelta from multiprocessing import Event, Value from unittest import mock import pytest +import django from django.core.exceptions import ValidationError from django.db import IntegrityError from django.test import override_settings @@ -24,6 +24,15 @@ from django_q.tests.testing_utilities.multiple_database_routers import ( ) from django_q.utils import add_months +if django.VERSION < (4, 0): + # pytz is the default in django 3.2. Remove when no support for 3.2 + from pytz import timezone as ZoneInfo +else: + try: + from zoneinfo import ZoneInfo + except ImportError: + from backports.zoneinfo import ZoneInfo + @pytest.fixture def broker(monkeypatch) -> Broker: @@ -90,7 +99,7 @@ def test_scheduler_daylight_saving_time_daily(broker, monkeypatch): # 28th of March 2021 is the day when sunlight saving starts (at 2 am) monkeypatch.setattr(Conf, "TIME_ZONE", "Europe/Amsterdam") - tz = pytz.timezone('Europe/Amsterdam') + tz = ZoneInfo('Europe/Amsterdam') broker.list_key = "scheduler_test:q" # Let's start a schedule at 1 am on the 27th of March. This is in AMS timezone. # So, 2021-03-27 00:00:00 when saved (due to TZ being Amsterdam and saved in UTC) diff --git a/django_q/utils.py b/django_q/utils.py index 8c2d293..936214d 100644 --- a/django_q/utils.py +++ b/django_q/utils.py @@ -1,14 +1,24 @@ from datetime import datetime -import pytz import calendar import inspect from datetime import date +import django from django.utils import timezone from django.conf import settings from django_q.conf import Conf +if django.VERSION < (4, 0): + # pytz is the default in django 3.2. Remove when no support for 3.2 + from pytz import timezone as ZoneInfo +else: + try: + from zoneinfo import ZoneInfo + except ImportError: + from backports.zoneinfo import ZoneInfo + + # credits: https://stackoverflow.com/a/4131114 # Made them aware of timezone def add_months(d, months): @@ -50,7 +60,14 @@ def get_func_repr(func): def localtime(value=None) -> datetime: """Override for timezone.localtime to deal with naive times and local times""" if settings.USE_TZ: - return timezone.localtime(value=value, timezone=pytz.timezone(Conf.TIME_ZONE)) + if django.VERSION >= (4, 0) and settings.USE_DEPRECATED_PYTZ: + import pytz + + convert_to_tz = pytz.timezone(Conf.TIME_ZONE) + else: + convert_to_tz = ZoneInfo(Conf.TIME_ZONE) + + return timezone.localtime(value=value, timezone=convert_to_tz) if value is None: return datetime.now() else: From 08baaab1251a4920154d3cc467e0a92422cb7d15 Mon Sep 17 00:00:00 2001 From: GDay <1939656+GDay@users.noreply.github.com> Date: Wed, 21 Dec 2022 03:44:56 +0100 Subject: [PATCH 25/39] Release v1.4.8 --- CHANGELOG.md | 6 ++++++ django_q/__init__.py | 2 +- docs/conf.py | 2 +- pyproject.toml | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a1bcc5..e49ea26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## [Unreleased](https://github.com/GDay/django-q2/tree/HEAD) +## [v1.4.8](https://github.com/GDay/django-q2/tree/v1.4.8) (2022-12-21) + +**Merged pull requests:** + +- Fix: allow both ZoneInfo and Pytz depending on django version https://github.com/GDay/django-q2/pull/55 + ## [v1.4.7](https://github.com/GDay/django-q2/tree/v1.4.7) (2022-12-21) **Merged pull requests:** diff --git a/django_q/__init__.py b/django_q/__init__.py index f4e426d..7bb46cd 100644 --- a/django_q/__init__.py +++ b/django_q/__init__.py @@ -1,6 +1,6 @@ import django -VERSION = (1, 4, 7) +VERSION = (1, 4, 8) if django.VERSION < (3, 2): default_app_config = "django_q.apps.DjangoQConfig" diff --git a/docs/conf.py b/docs/conf.py index fe5cde1..8155302 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -75,7 +75,7 @@ author = "Ilan Steemers, Stan Triepels" # The short X.Y version. version = "1.4" # The full version, including alpha/beta/rc tags. -release = "1.4.7" +release = "1.4.8" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pyproject.toml b/pyproject.toml index 1340f41..576912d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "django-q2" -version = "1.4.7" +version = "1.4.8" packages = [ { include = "django_q" }, ] From b66dfbd3af3e5a928e7b78fb633f8062d7b67008 Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Thu, 22 Dec 2022 03:02:53 +0100 Subject: [PATCH 26/39] Fix DST timezone change (move from DST to normal jump) (#56) --- django_q/models.py | 9 ++----- django_q/tests/test_scheduler.py | 46 ++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/django_q/models.py b/django_q/models.py index 1e5048a..9a03019 100644 --- a/django_q/models.py +++ b/django_q/models.py @@ -255,13 +255,8 @@ class Schedule(models.Model): # based on DST active or not extra_diff = (new_next_run - current_next_run) - add - # if we have one positive hour difference, then subtract it, so we are even - # and vice versa. In most cases, this will be 0, as there won't be a - # timezone diff - if extra_diff > timedelta(hours=0): - next_run -= extra_diff - else: - next_run += extra_diff + # subtract difference + next_run -= extra_diff return next_run diff --git a/django_q/tests/test_scheduler.py b/django_q/tests/test_scheduler.py index c4a3f73..d1fbf77 100644 --- a/django_q/tests/test_scheduler.py +++ b/django_q/tests/test_scheduler.py @@ -149,6 +149,52 @@ def test_scheduler_daylight_saving_time_daily(broker, monkeypatch): next_run = next_run.astimezone(tz) assert str(next_run) == "2021-03-30 01:00:00+02:00" + # Create second schedule with the next run date on the start date. It will move + # one day forward when we run the scheduler + start_date = datetime(2021, 10, 29, 1, 0, 0) + schedule = create_schedule( + "django_q.tests.tasks.word_multiply", + 2, + name="multiply", + schedule_type=Schedule.DAILY, + next_run=start_date, + ) + + # Run scheduler so we get the next run date + scheduler(broker=broker) + schedule.refresh_from_db() + + next_run = schedule.next_run + + assert str(next_run) == "2021-10-29 23:00:00+00:00" + # In the Amsterdam timezone, it's 1 hour over midnight (+02) + next_run = next_run.astimezone(tz) + assert str(next_run) == "2021-10-30 01:00:00+02:00" + + # Run scheduler so we get the next run date + scheduler(broker=broker) + schedule.refresh_from_db() + + next_run = schedule.next_run + + assert str(next_run) == "2021-10-30 23:00:00+00:00" + # In the Amsterdam timezone, it's 1 hour over midnight (+02) + next_run = next_run.astimezone(tz) + assert str(next_run) == "2021-10-31 01:00:00+02:00" + + # Run scheduler so we get the next run date + scheduler(broker=broker) + schedule.refresh_from_db() + + next_run = schedule.next_run + + assert str(next_run) == "2021-11-01 00:00:00+00:00" + # In the Amsterdam timezone, it's 1 hour over midnight (+01) + # Switch of DST + next_run = next_run.astimezone(tz) + assert str(next_run) == "2021-11-01 01:00:00+01:00" + + @pytest.mark.django_db def test_scheduler(broker, monkeypatch): From 31e82ad028eda093fc07b75aabcef8bc8f1d7011 Mon Sep 17 00:00:00 2001 From: GDay <1939656+GDay@users.noreply.github.com> Date: Thu, 22 Dec 2022 03:05:35 +0100 Subject: [PATCH 27/39] Release v1.4.9 --- CHANGELOG.md | 6 ++++++ django_q/__init__.py | 2 +- docs/conf.py | 2 +- pyproject.toml | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e49ea26..bb51b1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## [Unreleased](https://github.com/GDay/django-q2/tree/HEAD) +## [v1.4.9](https://github.com/GDay/django-q2/tree/v1.4.9) (2022-12-22) + +**Merged pull requests:** + +- Fix DST timezone change (move from DST to normal jump) https://github.com/GDay/django-q2/pull/56 + ## [v1.4.8](https://github.com/GDay/django-q2/tree/v1.4.8) (2022-12-21) **Merged pull requests:** diff --git a/django_q/__init__.py b/django_q/__init__.py index 7bb46cd..2657991 100644 --- a/django_q/__init__.py +++ b/django_q/__init__.py @@ -1,6 +1,6 @@ import django -VERSION = (1, 4, 8) +VERSION = (1, 4, 9) if django.VERSION < (3, 2): default_app_config = "django_q.apps.DjangoQConfig" diff --git a/docs/conf.py b/docs/conf.py index 8155302..5216862 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -75,7 +75,7 @@ author = "Ilan Steemers, Stan Triepels" # The short X.Y version. version = "1.4" # The full version, including alpha/beta/rc tags. -release = "1.4.8" +release = "1.4.9" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pyproject.toml b/pyproject.toml index 576912d..9d7afc2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "django-q2" -version = "1.4.8" +version = "1.4.9" packages = [ { include = "django_q" }, ] From 8cd1028391f35acafca3b92a4cf3e02cb28e9e7f Mon Sep 17 00:00:00 2001 From: msabatier <37879561+msabatier@users.noreply.github.com> Date: Wed, 11 Jan 2023 00:36:35 +0100 Subject: [PATCH 28/39] More explicit log messages in exception handling (#59) --- django_q/cluster.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/django_q/cluster.py b/django_q/cluster.py index 7bd9f53..d64a676 100644 --- a/django_q/cluster.py +++ b/django_q/cluster.py @@ -366,7 +366,7 @@ def pusher(task_queue: Queue, event: Event, broker: Broker = None): while True: try: task_set = broker.dequeue() - except Exception as e: + except Exception: logger.exception("Failed to pull task from broker") # broker probably crashed. Let the sentinel handle it. sleep(10) @@ -377,7 +377,7 @@ def pusher(task_queue: Queue, event: Event, broker: Broker = None): # unpack the task try: task = SignedPackage.loads(task[1]) - except (TypeError, BadSignature) as e: + except (TypeError, BadSignature): logger.exception("Failed to push task to queue") broker.fail(ack_id) continue @@ -473,7 +473,8 @@ def worker( ) f = task["func"] # if it's not an instance try to get it from the string - if not callable(task["func"]): + if not callable(f): + # locate() returns None if f cannot be loaded f = pydoc.locate(f) close_old_django_connections() timer_value = task.pop("timeout", timeout) @@ -482,6 +483,9 @@ def worker( # execute the payload timer.value = timer_value # Busy try: + if f is None: + # raise a meaningfull error if task["func"] is not a valid function + raise ValueError(f"Function {task['func']} is not defined") res = f(*task["args"], **task["kwargs"]) result = (res, True) except Exception as e: @@ -584,8 +588,8 @@ def save_task(task, broker: Broker): success=task["success"], attempt_count=1, ) - except Exception as e: - logger.error(e) + except Exception: + logger.exception("Could not save task result") def save_cached(task, broker: Broker): @@ -636,8 +640,8 @@ def save_cached(task, broker: Broker): ) # save the task broker.cache.set(task_key, SignedPackage.dumps(task), timeout) - except Exception as e: - logger.error(e) + except Exception: + logger.exception("Could not save task result") def scheduler(broker: Broker = None): @@ -725,11 +729,12 @@ def scheduler(broker: Broker = None): else: logger.info( _( - "%(process_name)s created a task from schedule " + "%(process_name)s created task %(task_name)s from schedule " "[%(schedule)s]" ) % { "process_name": current_process().name, + "task_name": humanize(s.task), "schedule": s.name or s.id, } ) @@ -742,8 +747,8 @@ def scheduler(broker: Broker = None): s.repeats = 0 # save the schedule s.save() - except Exception as e: - logger.error(e) + except Exception: + logger.exception("Could not create task from schedule") def close_old_django_connections(): From 865b1a5ba8ba41b60885c6d5276263e55b00fdd3 Mon Sep 17 00:00:00 2001 From: msabatier <37879561+msabatier@users.noreply.github.com> Date: Wed, 11 Jan 2023 01:48:57 +0100 Subject: [PATCH 29/39] Change task timeout logic to have now() as execution time (#58) --- django_q/brokers/orm.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/django_q/brokers/orm.py b/django_q/brokers/orm.py index de209b4..3c11261 100644 --- a/django_q/brokers/orm.py +++ b/django_q/brokers/orm.py @@ -11,7 +11,7 @@ from django_q.models import OrmQ def _timeout(): - return timezone.now() - timedelta(seconds=Conf.RETRY) + return timezone.now() + timedelta(seconds=Conf.RETRY) class ORM(Broker): @@ -31,13 +31,13 @@ class ORM(Broker): def queue_size(self) -> int: return ( self.get_connection() - .filter(key=self.list_key, lock__lte=_timeout()) + .filter(key=self.list_key, lock__lte=timezone.now()) .count() ) def lock_size(self) -> int: return ( - self.get_connection().filter(key=self.list_key, lock__gt=_timeout()).count() + self.get_connection().filter(key=self.list_key, lock__gt=timezone.now()).count() ) def purge_queue(self): @@ -56,12 +56,12 @@ class ORM(Broker): def enqueue(self, task): package = self.get_connection().create( - key=self.list_key, payload=task, lock=_timeout() + key=self.list_key, payload=task, lock=timezone.now() ) return package.pk def dequeue(self): - tasks = self.get_connection().filter(key=self.list_key, lock__lt=_timeout())[ + tasks = self.get_connection().filter(key=self.list_key, lock__lt=timezone.now())[ 0 : Conf.BULK # noqa: E203 ] if tasks: @@ -70,7 +70,7 @@ class ORM(Broker): if ( self.get_connection() .filter(id=task.id, lock=task.lock) - .update(lock=timezone.now()) + .update(lock=_timeout()) ): task_list.append((task.pk, task.payload)) # else don't process, as another cluster has been faster than us on From a013591de533be0c30a400313ca9e5f6cf7c6d70 Mon Sep 17 00:00:00 2001 From: msabatier <37879561+msabatier@users.noreply.github.com> Date: Tue, 17 Jan 2023 22:52:11 +0100 Subject: [PATCH 30/39] Add intended_date_kwarg field to Schedule (#62) Co-authored-by: Marc Sabatier --- django_q/cluster.py | 2 + django_q/locale/de/LC_MESSAGES/django.po | 241 ++++++++--------- django_q/locale/fr/LC_MESSAGES/django.po | 243 +++++++++--------- django_q/locale/tr/LC_MESSAGES/django.po | 241 ++++++++--------- .../0016_schedule_intended_date_kwarg.py | 25 ++ django_q/models.py | 12 + django_q/tasks.py | 3 + django_q/tests/test_scheduler.py | 32 +++ docs/schedules.rst | 13 +- 9 files changed, 455 insertions(+), 357 deletions(-) create mode 100644 django_q/migrations/0016_schedule_intended_date_kwarg.py diff --git a/django_q/cluster.py b/django_q/cluster.py index d64a676..7a52c34 100644 --- a/django_q/cluster.py +++ b/django_q/cluster.py @@ -691,6 +691,8 @@ def scheduler(broker: Broker = None): if type(args) != tuple: args = (args,) q_options = kwargs.get("q_options", {}) + if s.intended_date_kwarg: + kwargs[s.intended_date_kwarg] = s.next_run.isoformat() if s.hook: q_options["hook"] = s.hook # set up the next run time diff --git a/django_q/locale/de/LC_MESSAGES/django.po b/django_q/locale/de/LC_MESSAGES/django.po index 4110726..915b8df 100644 --- a/django_q/locale/de/LC_MESSAGES/django.po +++ b/django_q/locale/de/LC_MESSAGES/django.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-11-12 01:47+0000\n" +"POT-Creation-Date: 2023-01-15 23:35+0100\n" "PO-Revision-Date: 2018-08-05 18:28+0200\n" "Last-Translator: Jonas Winkler\n" "Language-Team: \n" @@ -17,177 +17,166 @@ msgstr "" "X-Generator: Poedit 2.1.1\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: django_q/admin.py:43 +#: admin.py:43 msgid "Resubmit selected tasks to queue" msgstr "Ausgewählte Aufgaben erneut ausführen" -#: django_q/admin.py:98 django_q/models.py:228 +#: admin.py:107 models.py:293 #, fuzzy #| msgid "Success" msgid "success" msgstr "erfolg" -#: django_q/admin.py:109 django_q/models.py:230 +#: admin.py:119 models.py:295 msgid "last_run" msgstr "" -#: django_q/cluster.py:77 +#: cluster.py:76 #, python-format msgid "Q Cluster %(name)s starting." msgstr "Q-Cluster %(name)s wird gestartet." -#: django_q/cluster.py:85 +#: cluster.py:84 #, fuzzy, python-format #| msgid "Q Cluster-{} stopping." msgid "Q Cluster %(name)s stopping." msgstr "Q-Cluster {name} wird gestoppt." -#: django_q/cluster.py:88 +#: cluster.py:87 #, python-format msgid "Q Cluster %(name)s has stopped." msgstr "Q-Cluster %(name)s wurde gestoppt." -#: django_q/cluster.py:96 +#: cluster.py:94 #, python-format msgid "%(name)s got signal %(signal)s" msgstr "%(name)s erhielt das Signal %(signal)s" -#: django_q/cluster.py:219 +#: cluster.py:221 #, python-format msgid "reincarnated monitor %(name)s after sudden death" msgstr "Monitor %(name)s wurde nach unerwartetem Absturz neu gestartet" -#: django_q/cluster.py:222 +#: cluster.py:227 #, python-format msgid "reincarnated pusher %(name)s after sudden death" msgstr "Pusher %(name)s wurde nach unerwartetem Absturz neu gestartet" -#: django_q/cluster.py:229 +#: cluster.py:238 #, python-format msgid "reincarnated worker %(name)s after timeout" msgstr "Worker %(name)s wurde nach Zeitüberschreitung neu gestartet" -#: django_q/cluster.py:231 +#: cluster.py:242 #, python-format msgid "recycled worker %(name)s" msgstr "Worker %(name)s wurde wiederverwendet" -#: django_q/cluster.py:233 +#: cluster.py:245 #, python-format msgid "reincarnated worker %(name)s after death" msgstr "Worker %(name)s wurde nach unerwartetem Absturz neu gestartet" -#: django_q/cluster.py:256 +#: cluster.py:269 #, python-format msgid "%(name)s guarding cluster %(cluster_name)s" msgstr "%(name)s beschützt das Cluster %(cluster_name)s" -#: django_q/cluster.py:261 +#: cluster.py:278 #, python-format msgid "Q Cluster %(cluster_name)s running." msgstr "Q-Cluster %(cluster_name)s läuft." -#: django_q/cluster.py:295 +#: cluster.py:314 #, python-format msgid "%(name)s stopping cluster processes" msgstr "%(name)s hält Cluster-Prozesse an" -#: django_q/cluster.py:320 +#: cluster.py:339 #, python-format msgid "%(name)s waiting for the monitor." msgstr "%(name)s wartet auf den Monitor." -#: django_q/cluster.py:342 +#: cluster.py:362 #, python-format msgid "%(process_name)s pushing tasks at %(id)s" msgstr "%(process_name)s veröffentlicht Aufagaben auf %(id)s" -#: django_q/cluster.py:363 +#: cluster.py:386 #, python-format msgid "queueing from %(list_key)s" msgstr "Einreihen von %(list_key)s" -#: django_q/cluster.py:366 +#: cluster.py:390 #, python-format msgid "%(name)s stopped pushing tasks" msgstr "%(name)s veröffentlicht keine Aufgaben mehr" -#: django_q/cluster.py:378 +#: cluster.py:403 #, python-format msgid "%(name)s monitoring at %(id)s" msgstr "%(name)s beobachtet auf %(id)s" -#: django_q/cluster.py:395 +#: cluster.py:422 #, python-format msgid "Processed '%(info_name)s' (%(task_name)s)" msgstr "[%(task_name)s] - '%(info_name)s' wurde verarbeitet" -#: django_q/cluster.py:398 +#: cluster.py:428 #, python-format msgid "Failed '%(info_name)s' (%(task_name)s) - %(task_result)s" msgstr "'%(info_name)s' (%(task_name)s) ist fehlgeschlagen - %(task_result)s" -#: django_q/cluster.py:399 +#: cluster.py:435 #, python-format msgid "%(name)s stopped monitoring results" msgstr "%(name)s überwacht keine Ergebnisse mehr" -#: django_q/cluster.py:413 +#: cluster.py:451 #, python-format msgid "%(proc_name)s ready for work at %(id)s" msgstr "%(proc_name)s ist bereit für Arbeit auf %(id)s" -#: django_q/cluster.py:425 +#: cluster.py:466 #, python-format msgid "%(proc_name)s processing '%(func_name)s' (%(task_name)s)" msgstr "%(proc_name)s verarbeitet '%(func_name)s' (%(task_name)s)" -#: django_q/cluster.py:440 -#, python-format -msgid "" -"Could not process '%(func_name)s'. Check the location of the function and " -"the args/kwargs." -msgstr "" -"Konnte '%(func_name)s' nicht verarbeiten. Überprüfen Sie den Ort der " -"Funktion und die args/kwargs." - -#: django_q/cluster.py:456 +#: cluster.py:507 #, python-format msgid "%(proc_name)s stopped doing work" msgstr "%(proc_name)s hat die Arbeit beendet" -#: django_q/cluster.py:649 django_q/models.py:144 -msgid "Please install croniter to enable cron expressions" -msgstr "Bitte installieren Sie croniter, um Cron-Ausdrücke zu aktivieren" - -#: django_q/cluster.py:672 +#: cluster.py:712 #, python-format msgid "%(process_name)s failed to create a task from schedule [%(schedule)s]" msgstr "" "%(process_name)s konnte keine Aufgabe von Zeitplan [%(schedule)s] erstellen" -#: django_q/cluster.py:678 -#, python-format -msgid "%(process_name)s created a task from schedule [%(schedule)s]" +#: cluster.py:723 +#, fuzzy, python-format +#| msgid "%(process_name)s created a task from schedule [%(schedule)s]" +msgid "" +"%(process_name)s created task %(task_name)s from schedule [%(schedule)s]" msgstr "" "%(process_name)s hat eine Aufgabe des Zeitplans [%(schedule)s] erstellt" -#: django_q/cluster.py:718 +#: cluster.py:769 msgid "Skipping cpu affinity because psutil was not found." msgstr "Cpu-Affinität wird übersprungen, da psutil nicht gefunden wurde." -#: django_q/cluster.py:723 +#: cluster.py:774 msgid "Faking cpu affinity because it is not supported on this platform" msgstr "" "Vortäuschen von CPU-Affinität, da diese auf dieser Plattform nicht " "unterstützt wird" -#: django_q/cluster.py:744 +#: cluster.py:796 #, python-format msgid "%(pid)s will use cpu %(affinity)s" msgstr "%(pid)s wird CPU %(affinity)s benutzen" -#: django_q/conf.py:85 +#: conf.py:85 #, python-format msgid "" "SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', " @@ -197,291 +186,307 @@ msgstr "" "'group', 'name', 'func' und None. Standard ist None." #. Translators: Cluster status descriptions -#: django_q/conf.py:194 +#: conf.py:202 msgid "Starting" msgstr "Wird gestartet" -#: django_q/conf.py:195 +#: conf.py:203 msgid "Working" msgstr "Arbeitet" -#: django_q/conf.py:196 +#: conf.py:204 msgid "Idle" msgstr "Leerlauf" -#: django_q/conf.py:197 +#: conf.py:205 msgid "Stopped" msgstr "Gestoppt" -#: django_q/conf.py:198 +#: conf.py:206 msgid "Stopping" msgstr "Wird gestoppt" #. Translators: help text for qcluster management command -#: django_q/management/commands/qcluster.py:9 +#: management/commands/qcluster.py:9 msgid "Starts a Django Q Cluster." msgstr "Startet ein Django-Q-Cluster." #. Translators: help text for qinfo management command -#: django_q/management/commands/qinfo.py:11 +#: management/commands/qinfo.py:11 msgid "General information over all clusters." msgstr "Allgemeine Informationen über alle Cluster" #. Translators: help text for qmemory management command -#: django_q/management/commands/qmemory.py:9 +#: management/commands/qmemory.py:9 msgid "Monitors Q Cluster memory usage" msgstr "Überwacht die Speichernutzung von Q Cluster" #. Translators: help text for qmonitor management command -#: django_q/management/commands/qmonitor.py:9 +#: management/commands/qmonitor.py:9 msgid "Monitors Q Cluster activity" msgstr "Q-Cluster aktiv überwachen" -#: django_q/models.py:119 +#: models.py:125 msgid "Successful task" msgstr "Erfolgreiche Aufgabe" -#: django_q/models.py:120 +#: models.py:126 msgid "Successful tasks" msgstr "Erfolgreiche Aufgaben" -#: django_q/models.py:135 +#: models.py:141 msgid "Failed task" msgstr "Fehlgeschlagene Aufgabe" -#: django_q/models.py:136 +#: models.py:142 msgid "Failed tasks" msgstr "Fehlgeschlagene Aufgaben" -#: django_q/models.py:160 +#: models.py:150 models.py:234 +msgid "Please install croniter to enable cron expressions" +msgstr "Bitte installieren Sie croniter, um Cron-Ausdrücke zu aktivieren" + +#: models.py:170 msgid "e.g. 1, 2, 'John'" msgstr "zum Beispiel 1, 2, 'John'" -#: django_q/models.py:162 +#: models.py:172 msgid "e.g. x=1, y=2, name='John'" msgstr "zum Beispiel x=1, y=2, name='John'" -#: django_q/models.py:176 +#: models.py:186 msgid "Once" msgstr "Einmal" -#: django_q/models.py:177 +#: models.py:187 msgid "Minutes" msgstr "Minuten" -#: django_q/models.py:178 +#: models.py:188 msgid "Hourly" msgstr "Stündlich" -#: django_q/models.py:179 +#: models.py:189 msgid "Daily" msgstr "Täglich" -#: django_q/models.py:180 +#: models.py:190 msgid "Weekly" msgstr "Wöchentlich" -#: django_q/models.py:181 +#: models.py:191 msgid "Biweekly" msgstr "Zweiwöchentlich" -#: django_q/models.py:182 +#: models.py:192 msgid "Monthly" msgstr "Monatlich" -#: django_q/models.py:183 +#: models.py:193 msgid "Bimonthly" msgstr "Zweimonatlich" -#: django_q/models.py:184 +#: models.py:194 msgid "Quarterly" msgstr "Vierteljährlich" -#: django_q/models.py:185 +#: models.py:195 msgid "Yearly" msgstr "Jährlich" -#: django_q/models.py:186 +#: models.py:196 msgid "Cron" msgstr "Cron" -#: django_q/models.py:189 +#: models.py:199 msgid "Schedule Type" msgstr "Zeitplan-Typ" -#: django_q/models.py:192 +#: models.py:202 msgid "Number of minutes for the Minutes type" msgstr "Anzahl Minuten für den Typ 'Minuten'" -#: django_q/models.py:195 +#: models.py:205 msgid "Repeats" msgstr "Wiederhohlungen" -#: django_q/models.py:195 +#: models.py:205 msgid "n = n times, -1 = forever" msgstr "n = n mal, -1 = für immer" -#: django_q/models.py:198 +#: models.py:208 msgid "Next Run" msgstr "Nächste Ausführung" -#: django_q/models.py:205 +#: models.py:215 msgid "Cron expression" msgstr "Cron-Ausdruck" -#: django_q/models.py:235 +#: models.py:224 +msgid "Name of kwarg to pass intended schedule date" +msgstr "" + +#: models.py:299 msgid "Scheduled task" msgstr "Geplante Aufgabe" -#: django_q/models.py:236 +#: models.py:300 msgid "Scheduled tasks" msgstr "Geplante Aufgaben" -#: django_q/models.py:262 +#: models.py:326 msgid "Queued task" msgstr "Eingereihte Aufgabe" -#: django_q/models.py:263 +#: models.py:327 msgid "Queued tasks" msgstr "Eingereihte Aufgaben" -#: django_q/monitor.py:62 django_q/monitor.py:339 +#: monitor.py:64 monitor.py:348 msgid "Host" msgstr "Host" -#: django_q/monitor.py:66 django_q/monitor.py:343 django_q/monitor.py:450 +#: monitor.py:68 monitor.py:352 monitor.py:459 msgid "Id" msgstr "Id" -#: django_q/monitor.py:70 +#: monitor.py:72 msgid "State" msgstr "Status" -#: django_q/monitor.py:74 +#: monitor.py:76 msgid "Pool" msgstr "Pool" -#: django_q/monitor.py:78 +#: monitor.py:80 msgid "TQ" msgstr "TQ" -#: django_q/monitor.py:82 +#: monitor.py:84 msgid "RQ" msgstr "RQ" -#: django_q/monitor.py:86 +#: monitor.py:88 msgid "RC" msgstr "RC" -#: django_q/monitor.py:90 +#: monitor.py:92 msgid "Up" msgstr "Up" -#: django_q/monitor.py:170 django_q/monitor.py:279 +#: monitor.py:172 monitor.py:286 msgid "Queued" msgstr "Eingereiht" -#: django_q/monitor.py:178 +#: monitor.py:180 msgid "Success" msgstr "Erfolg" -#: django_q/monitor.py:188 django_q/monitor.py:287 +#: monitor.py:190 monitor.py:294 msgid "Failures" msgstr "Fehlschläge" -#: django_q/monitor.py:199 django_q/monitor.py:485 +#: monitor.py:201 monitor.py:498 msgid "[Press q to quit]" msgstr "[Drücken Sie q zum Beenden]" -#: django_q/monitor.py:223 +#: monitor.py:227 msgid "day" msgstr "Tag" -#: django_q/monitor.py:244 +#: monitor.py:248 msgid "second" msgstr "Sekunde" -#: django_q/monitor.py:247 +#: monitor.py:251 msgid "minute" msgstr "Minute" -#: django_q/monitor.py:250 +#: monitor.py:254 msgid "hour" msgstr "Stunde" -#: django_q/monitor.py:260 +#: monitor.py:263 #, python-format msgid "-- %(prefix)s %(version)s on %(info)s --" msgstr "-- %(prefix)s %(version)s auf %(info)s --" -#: django_q/monitor.py:266 +#: monitor.py:273 msgid "Clusters" msgstr "Cluster" -#: django_q/monitor.py:270 +#: monitor.py:277 msgid "Workers" msgstr "Arbeiter" -#: django_q/monitor.py:274 +#: monitor.py:281 msgid "Restarts" msgstr "Neustarts" -#: django_q/monitor.py:283 +#: monitor.py:290 msgid "Successes" msgstr "Erfolge" -#: django_q/monitor.py:292 +#: monitor.py:299 msgid "Schedules" msgstr "Zeitpläne" -#: django_q/monitor.py:296 +#: monitor.py:303 #, python-format msgid "Tasks/%(per)s" msgstr "Aufgaben/%(per)s" -#: django_q/monitor.py:300 +#: monitor.py:307 msgid "Avg time" msgstr "Durchschnittl. Zeit" -#: django_q/monitor.py:348 +#: monitor.py:357 msgid "Available (%)" msgstr "Verfügbar (%)" -#: django_q/monitor.py:354 +#: monitor.py:363 msgid "Available (MB)" msgstr "Verfügbar (MB)" -#: django_q/monitor.py:359 +#: monitor.py:368 msgid "Total (MB)" msgstr "Insgesamt (MB)" -#: django_q/monitor.py:364 +#: monitor.py:373 msgid "Sentinel (MB)" msgstr "Sentinel (MB)" -#: django_q/monitor.py:370 +#: monitor.py:379 msgid "Monitor (MB)" msgstr "Monitor (MB)" -#: django_q/monitor.py:376 +#: monitor.py:385 msgid "Workers (MB)" msgstr "Arbeiter (MB)" -#: django_q/monitor.py:478 +#: monitor.py:487 #, python-format msgid "Available lowest (): %(memory_percent)s ((at)s)" msgstr "Niedrigste verfügbar (): %(memory_percent)s ((at)s)" -#: django_q/monitor.py:496 +#: monitor.py:509 msgid "No clusters appear to be running." msgstr "Es scheinen keine Cluster zu laufen." -#: django_q/signals.py:22 +#: signals.py:22 #, python-format msgid "malformed return hook '%(hook)s' for [%(name)s]" msgstr "Ungültiger Return-Hook '%(hook)s' für [%(name)s]" -#: django_q/signals.py:30 +#: signals.py:30 #, python-format msgid "return hook %(hook)s failed on [%(name)s] because %(error)s" msgstr "Return-Hook %(hook)s für [%(name)s] ist gescheitert: %(error)s" + +#, python-format +#~ msgid "" +#~ "Could not process '%(func_name)s'. Check the location of the function and " +#~ "the args/kwargs." +#~ msgstr "" +#~ "Konnte '%(func_name)s' nicht verarbeiten. Überprüfen Sie den Ort der " +#~ "Funktion und die args/kwargs." diff --git a/django_q/locale/fr/LC_MESSAGES/django.po b/django_q/locale/fr/LC_MESSAGES/django.po index 26dbaef..762fd2f 100644 --- a/django_q/locale/fr/LC_MESSAGES/django.po +++ b/django_q/locale/fr/LC_MESSAGES/django.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-11-12 01:47+0000\n" +"POT-Creation-Date: 2023-01-15 23:35+0100\n" "PO-Revision-Date: 2018-08-05 18:28+0200\n" "Last-Translator: Thierry BOULOGNE \n" "Language-Team: \n" @@ -17,176 +17,164 @@ msgstr "" "X-Generator: Poedit 2.1.1\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: django_q/admin.py:43 +#: admin.py:43 msgid "Resubmit selected tasks to queue" msgstr "Resoumettre les tâches sélectionnées à la file d'attente" -#: django_q/admin.py:98 django_q/models.py:228 +#: admin.py:107 models.py:293 #, fuzzy #| msgid "Success" msgid "success" msgstr "succès" -#: django_q/admin.py:109 django_q/models.py:230 +#: admin.py:119 models.py:295 msgid "last_run" msgstr "" -#: django_q/cluster.py:77 +#: cluster.py:76 #, python-format msgid "Q Cluster %(name)s starting." msgstr "Démarrage de Q Cluster-%(name)s." -#: django_q/cluster.py:85 +#: cluster.py:84 #, python-format msgid "Q Cluster %(name)s stopping." msgstr "Arrêt de Q Cluster-%(name)s." -#: django_q/cluster.py:88 +#: cluster.py:87 #, python-format msgid "Q Cluster %(name)s has stopped." msgstr "Q Cluster-%(name)s a été arrêté." -#: django_q/cluster.py:96 +#: cluster.py:94 #, python-format msgid "%(name)s got signal %(signal)s" msgstr "%(name)s à reçu le signal %(signal)s" -#: django_q/cluster.py:219 +#: cluster.py:221 #, python-format msgid "reincarnated monitor %(name)s after sudden death" msgstr "moniteur réintégré %(name)s après un arrêt intempestif" -#: django_q/cluster.py:222 +#: cluster.py:227 #, python-format msgid "reincarnated pusher %(name)s after sudden death" msgstr "pousseur réintégré %(name)s après un arrêt intempestif" -#: django_q/cluster.py:229 +#: cluster.py:238 #, python-format msgid "reincarnated worker %(name)s after timeout" msgstr "processus réintégré %(name)s après un arrêt une attente trop longue" -#: django_q/cluster.py:231 +#: cluster.py:242 #, python-format msgid "recycled worker %(name)s" msgstr "processus recyclé %(name)s" -#: django_q/cluster.py:233 +#: cluster.py:245 #, python-format msgid "reincarnated worker %(name)s after death" msgstr "processus réintégré %(name)s après arrêt" -#: django_q/cluster.py:256 +#: cluster.py:269 #, python-format msgid "%(name)s guarding cluster %(cluster_name)s" msgstr "%(name)s surveillance du cluster à %(cluster_name)s" -#: django_q/cluster.py:261 +#: cluster.py:278 #, python-format msgid "Q Cluster %(cluster_name)s running." msgstr "Démarrage de Q Cluster-%(cluster_name)s." -#: django_q/cluster.py:295 +#: cluster.py:314 #, python-format msgid "%(name)s stopping cluster processes" msgstr "%(name)s arrêt des processus de cluster" -#: django_q/cluster.py:320 +#: cluster.py:339 #, python-format msgid "%(name)s waiting for the monitor." msgstr "%(name)s en attente du moniteur." -#: django_q/cluster.py:342 +#: cluster.py:362 #, python-format msgid "%(process_name)s pushing tasks at %(id)s" msgstr "%(process_name)s tâche envoyé à %(id)s" -#: django_q/cluster.py:363 +#: cluster.py:386 #, python-format msgid "queueing from %(list_key)s" msgstr "mise en file d'attente de %(list_key)s" -#: django_q/cluster.py:366 +#: cluster.py:390 #, python-format msgid "%(name)s stopped pushing tasks" msgstr "%(name)s a cessé de pousser les tâches" -#: django_q/cluster.py:378 +#: cluster.py:403 #, python-format msgid "%(name)s monitoring at %(id)s" msgstr "%(name)s Surveillance de %(id)s" -#: django_q/cluster.py:395 +#: cluster.py:422 #, python-format msgid "Processed '%(info_name)s' (%(task_name)s)" msgstr "traité '%(info_name)s' (%(task_name)s)" -#: django_q/cluster.py:398 +#: cluster.py:428 #, python-format msgid "Failed '%(info_name)s' (%(task_name)s) - %(task_result)s" msgstr "Manqué '%(info_name)s' (%(task_name)s) - %(task_result)s" -#: django_q/cluster.py:399 +#: cluster.py:435 #, python-format msgid "%(name)s stopped monitoring results" msgstr "%(name)s arrêt des résultats de surveillance" -#: django_q/cluster.py:413 +#: cluster.py:451 #, python-format msgid "%(proc_name)s ready for work at %(id)s" msgstr "%(proc_name)s prêt pour le travail à %(id)s" -#: django_q/cluster.py:425 +#: cluster.py:466 #, python-format msgid "%(proc_name)s processing '%(func_name)s' (%(task_name)s)" msgstr "%(proc_name)s en traitement '%(func_name)s' (%(task_name)s)" -#: django_q/cluster.py:440 -#, python-format -msgid "" -"Could not process '%(func_name)s'. Check the location of the function and " -"the args/kwargs." -msgstr "" -"Impossible de traiter '%(func_name)s'. Vérifiez l'emplacement de la fonction " -"et les args/kwargs." - -#: django_q/cluster.py:456 +#: cluster.py:507 #, python-format msgid "%(proc_name)s stopped doing work" msgstr "%(proc_name)s arrêté de travailler" -#: django_q/cluster.py:649 django_q/models.py:144 -msgid "Please install croniter to enable cron expressions" -msgstr "Veuillez installer croniter pour activer les expressions croniques." - -#: django_q/cluster.py:672 +#: cluster.py:712 #, python-format msgid "%(process_name)s failed to create a task from schedule [%(schedule)s]" msgstr "" "%(process_name)s Echec de la création d'une tâche à partir de Schedule " "[%(schedule)s]" -#: django_q/cluster.py:678 +#: cluster.py:723 #, python-format -msgid "%(process_name)s created a task from schedule [%(schedule)s]" -msgstr "%(process_name)s a créé une tâche à partir de Schedule [%(schedule)s]" +msgid "" +"%(process_name)s created task %(task_name)s from schedule [%(schedule)s]" +msgstr "%(process_name)s a créé la tâche %(task_name)s à partir de Schedule [%(schedule)s]" -#: django_q/cluster.py:718 +#: cluster.py:769 msgid "Skipping cpu affinity because psutil was not found." msgstr "Sauter l'affinité du processeur parce que psutil n'a pas été trouvé." -#: django_q/cluster.py:723 +#: cluster.py:774 msgid "Faking cpu affinity because it is not supported on this platform" msgstr "" "Simulation de l'affinité du processeur parce qu'elle n'est pas supportée sur " "cette plateforme." -#: django_q/cluster.py:744 +#: cluster.py:796 #, python-format msgid "%(pid)s will use cpu %(affinity)s" msgstr "%(pid)s utilisera le CPU %(affinity)s" -#: django_q/conf.py:85 +#: conf.py:85 #, python-format msgid "" "SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', " @@ -196,299 +184,316 @@ msgstr "" "'group', 'name', 'func' et None. La valeur par défaut est None." #. Translators: Cluster status descriptions -#: django_q/conf.py:194 +#: conf.py:202 msgid "Starting" msgstr "Démarrage" -#: django_q/conf.py:195 +#: conf.py:203 msgid "Working" msgstr "Actif" -#: django_q/conf.py:196 +#: conf.py:204 msgid "Idle" msgstr "En attente" -#: django_q/conf.py:197 +#: conf.py:205 msgid "Stopped" msgstr "Arrêté" -#: django_q/conf.py:198 +#: conf.py:206 msgid "Stopping" msgstr "En cours d’arrêt" #. Translators: help text for qcluster management command -#: django_q/management/commands/qcluster.py:9 +#: management/commands/qcluster.py:9 msgid "Starts a Django Q Cluster." msgstr "Démarre un cluster Django Q." #. Translators: help text for qinfo management command -#: django_q/management/commands/qinfo.py:11 +#: management/commands/qinfo.py:11 msgid "General information over all clusters." msgstr "Informations générales sur tous les clusters." #. Translators: help text for qmemory management command -#: django_q/management/commands/qmemory.py:9 +#: management/commands/qmemory.py:9 #, fuzzy #| msgid "Monitors Q Cluster activity" msgid "Monitors Q Cluster memory usage" msgstr "Surveille l'utilisation de la mémoire du cluster Q" #. Translators: help text for qmonitor management command -#: django_q/management/commands/qmonitor.py:9 +#: management/commands/qmonitor.py:9 msgid "Monitors Q Cluster activity" msgstr "Activité du cluster Moniteur Q" -#: django_q/models.py:119 +#: models.py:125 msgid "Successful task" msgstr "Tâche réussie" -#: django_q/models.py:120 +#: models.py:126 msgid "Successful tasks" msgstr "Tâches réussies" -#: django_q/models.py:135 +#: models.py:141 msgid "Failed task" msgstr "Tâche échoué" -#: django_q/models.py:136 +#: models.py:142 msgid "Failed tasks" msgstr "Tâches échouées" -#: django_q/models.py:160 +#: models.py:150 models.py:234 +msgid "Please install croniter to enable cron expressions" +msgstr "Veuillez installer croniter pour activer les expressions croniques." + +#: models.py:170 msgid "e.g. 1, 2, 'John'" msgstr "ex. 1, 2, ‘Jean’" -#: django_q/models.py:162 +#: models.py:172 msgid "e.g. x=1, y=2, name='John'" msgstr "p. ex. x = 1, y = 2, Nom = ‘Jean’" -#: django_q/models.py:176 +#: models.py:186 msgid "Once" msgstr "Une fois" -#: django_q/models.py:177 +#: models.py:187 msgid "Minutes" msgstr "Minutes" -#: django_q/models.py:178 +#: models.py:188 msgid "Hourly" msgstr "Toutes les heures" -#: django_q/models.py:179 +#: models.py:189 msgid "Daily" msgstr "Quotidien" -#: django_q/models.py:180 +#: models.py:190 msgid "Weekly" msgstr "Hebdomadaire" -#: django_q/models.py:181 +#: models.py:191 #, fuzzy #| msgid "Weekly" msgid "Biweekly" msgstr "Bihebdomadaire" -#: django_q/models.py:182 +#: models.py:192 msgid "Monthly" msgstr "Mensuel" -#: django_q/models.py:183 +#: models.py:193 #, fuzzy #| msgid "Monthly" msgid "Bimonthly" msgstr "Bimestriel" -#: django_q/models.py:184 +#: models.py:194 msgid "Quarterly" msgstr "Tous les quart-d’heure" -#: django_q/models.py:185 +#: models.py:195 msgid "Yearly" msgstr "Annuel" -#: django_q/models.py:186 +#: models.py:196 msgid "Cron" msgstr "Cron" -#: django_q/models.py:189 +#: models.py:199 msgid "Schedule Type" msgstr "Type de plannification" -#: django_q/models.py:192 +#: models.py:202 msgid "Number of minutes for the Minutes type" msgstr "Nombre de minutes pour le type de minutes" -#: django_q/models.py:195 +#: models.py:205 msgid "Repeats" msgstr "Répéter" -#: django_q/models.py:195 +#: models.py:205 msgid "n = n times, -1 = forever" msgstr "n = n fois,-1 = Toujours" -#: django_q/models.py:198 +#: models.py:208 msgid "Next Run" msgstr "Prochaine exécution" -#: django_q/models.py:205 +#: models.py:215 msgid "Cron expression" msgstr "Expression du Cron" -#: django_q/models.py:235 +#: models.py:224 +msgid "Name of kwarg to pass intended schedule date" +msgstr "Nom du kwarg pour passer la date d'éxecution prévue" + +#: models.py:299 msgid "Scheduled task" msgstr "Tâche planifiée" -#: django_q/models.py:236 +#: models.py:300 msgid "Scheduled tasks" msgstr "Tâches planifiées" -#: django_q/models.py:262 +#: models.py:326 msgid "Queued task" msgstr "Tâche en file d'attente" -#: django_q/models.py:263 +#: models.py:327 msgid "Queued tasks" msgstr "Tâches en file d'attente" -#: django_q/monitor.py:62 django_q/monitor.py:339 +#: monitor.py:64 monitor.py:348 msgid "Host" msgstr "Hôte" -#: django_q/monitor.py:66 django_q/monitor.py:343 django_q/monitor.py:450 +#: monitor.py:68 monitor.py:352 monitor.py:459 msgid "Id" msgstr "Id" -#: django_q/monitor.py:70 +#: monitor.py:72 msgid "State" msgstr "Statut" -#: django_q/monitor.py:74 +#: monitor.py:76 msgid "Pool" msgstr "Piscine" -#: django_q/monitor.py:78 +#: monitor.py:80 msgid "TQ" msgstr "TQ" -#: django_q/monitor.py:82 +#: monitor.py:84 msgid "RQ" msgstr "RQ" -#: django_q/monitor.py:86 +#: monitor.py:88 msgid "RC" msgstr "RC" -#: django_q/monitor.py:90 +#: monitor.py:92 msgid "Up" msgstr "Haut" -#: django_q/monitor.py:170 django_q/monitor.py:279 +#: monitor.py:172 monitor.py:286 msgid "Queued" msgstr "En file d'attente" -#: django_q/monitor.py:178 +#: monitor.py:180 msgid "Success" msgstr "Succès" -#: django_q/monitor.py:188 django_q/monitor.py:287 +#: monitor.py:190 monitor.py:294 msgid "Failures" msgstr "Défaillances" -#: django_q/monitor.py:199 django_q/monitor.py:485 +#: monitor.py:201 monitor.py:498 msgid "[Press q to quit]" msgstr "[appuyez sur q pour quitter]" -#: django_q/monitor.py:223 +#: monitor.py:227 msgid "day" msgstr "jour" -#: django_q/monitor.py:244 +#: monitor.py:248 msgid "second" msgstr "seconde" -#: django_q/monitor.py:247 +#: monitor.py:251 msgid "minute" msgstr "minute" -#: django_q/monitor.py:250 +#: monitor.py:254 msgid "hour" msgstr "heure" -#: django_q/monitor.py:260 +#: monitor.py:263 #, python-format msgid "-- %(prefix)s %(version)s on %(info)s --" msgstr "--%(prefix)s %(version)s sur %(info)s --" -#: django_q/monitor.py:266 +#: monitor.py:273 msgid "Clusters" msgstr "Grappes" -#: django_q/monitor.py:270 +#: monitor.py:277 msgid "Workers" msgstr "Processus" -#: django_q/monitor.py:274 +#: monitor.py:281 msgid "Restarts" msgstr "Redémarrages" -#: django_q/monitor.py:283 +#: monitor.py:290 msgid "Successes" msgstr "Succès" -#: django_q/monitor.py:292 +#: monitor.py:299 msgid "Schedules" msgstr "Planifications" -#: django_q/monitor.py:296 +#: monitor.py:303 #, python-format msgid "Tasks/%(per)s" msgstr "Tâches/%(per)s" -#: django_q/monitor.py:300 +#: monitor.py:307 msgid "Avg time" msgstr "Temps Moyen" -#: django_q/monitor.py:348 +#: monitor.py:357 msgid "Available (%)" msgstr "" -#: django_q/monitor.py:354 +#: monitor.py:363 msgid "Available (MB)" msgstr "Disponible sur (MB)" -#: django_q/monitor.py:359 +#: monitor.py:368 msgid "Total (MB)" msgstr "Total (MB)" -#: django_q/monitor.py:364 +#: monitor.py:373 msgid "Sentinel (MB)" msgstr "Sentinel (MB)" -#: django_q/monitor.py:370 +#: monitor.py:379 msgid "Monitor (MB)" msgstr "Monitor (MB)" -#: django_q/monitor.py:376 +#: monitor.py:385 #, fuzzy #| msgid "Workers" msgid "Workers (MB)" msgstr "Processus (MB)" -#: django_q/monitor.py:478 +#: monitor.py:487 #, python-format msgid "Available lowest (): %(memory_percent)s ((at)s)" msgstr "Disponible le plus bas () : %(memory_percent)s ((at)s)" -#: django_q/monitor.py:496 +#: monitor.py:509 msgid "No clusters appear to be running." msgstr "Aucun cluster ne semble être en cours d'exécution." -#: django_q/signals.py:22 +#: signals.py:22 #, python-format msgid "malformed return hook '%(hook)s' for [%(name)s]" msgstr "hook de retour mal formé' %(hook)s 'pour [%(name)s]" -#: django_q/signals.py:30 +#: signals.py:30 #, python-format msgid "return hook %(hook)s failed on [%(name)s] because %(error)s" -msgstr "le crochet de retour %(hook)s a échoué sur [%(name)s] parce que %(error)s" +msgstr "" +"le crochet de retour %(hook)s a échoué sur [%(name)s] parce que %(error)s" + +#, python-format +#~ msgid "" +#~ "Could not process '%(func_name)s'. Check the location of the function and " +#~ "the args/kwargs." +#~ msgstr "" +#~ "Impossible de traiter '%(func_name)s'. Vérifiez l'emplacement de la " +#~ "fonction et les args/kwargs." diff --git a/django_q/locale/tr/LC_MESSAGES/django.po b/django_q/locale/tr/LC_MESSAGES/django.po index 8b73b63..eff3bd9 100644 --- a/django_q/locale/tr/LC_MESSAGES/django.po +++ b/django_q/locale/tr/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-11-12 01:47+0000\n" +"POT-Creation-Date: 2023-01-15 23:35+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Ethem Güner \n" "Language-Team: \n" @@ -18,172 +18,161 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: django_q/admin.py:43 +#: admin.py:43 msgid "Resubmit selected tasks to queue" msgstr "Seçili işleri kuyruğa tekrar gönder" -#: django_q/admin.py:98 django_q/models.py:228 +#: admin.py:107 models.py:293 #, fuzzy #| msgid "Success" msgid "success" msgstr "başarılı olanlar" -#: django_q/admin.py:109 django_q/models.py:230 +#: admin.py:119 models.py:295 msgid "last_run" msgstr "" -#: django_q/cluster.py:77 +#: cluster.py:76 #, python-format msgid "Q Cluster %(name)s starting." msgstr "Q Cluster %(name)s başlatılıyor." -#: django_q/cluster.py:85 +#: cluster.py:84 #, python-format msgid "Q Cluster %(name)s stopping." msgstr "Q Cluster %(name)s durduruluyor." -#: django_q/cluster.py:88 +#: cluster.py:87 #, python-format msgid "Q Cluster %(name)s has stopped." msgstr "Q Cluster %(name)s durduruldu." -#: django_q/cluster.py:96 +#: cluster.py:94 #, python-format msgid "%(name)s got signal %(signal)s" msgstr "%(name)s, %(signal)s pid'inde izleniyor/monitoring yapılıyor." -#: django_q/cluster.py:219 +#: cluster.py:221 #, python-format msgid "reincarnated monitor %(name)s after sudden death" msgstr "Monitor %(name)s ani ölüm sonrası tekrar dirildi" -#: django_q/cluster.py:222 +#: cluster.py:227 #, python-format msgid "reincarnated pusher %(name)s after sudden death" msgstr "Pusher %(name)s ani ölüm sonrası tekrar dirildi" -#: django_q/cluster.py:229 +#: cluster.py:238 #, python-format msgid "reincarnated worker %(name)s after timeout" msgstr "Worker %(name)s zaman aşımı sonrası tekrar dirildi" -#: django_q/cluster.py:231 +#: cluster.py:242 #, python-format msgid "recycled worker %(name)s" msgstr "Worker %(name)s geri döndürüldü" -#: django_q/cluster.py:233 +#: cluster.py:245 #, python-format msgid "reincarnated worker %(name)s after death" msgstr "Worker %(name)s ani ölüm sonrası tekrar dirildi" -#: django_q/cluster.py:256 +#: cluster.py:269 #, python-format msgid "%(name)s guarding cluster %(cluster_name)s" msgstr "%(name)s, %(cluster_name)s cluster'ını koruyor" -#: django_q/cluster.py:261 +#: cluster.py:278 #, python-format msgid "Q Cluster %(cluster_name)s running." msgstr "Q Cluster %(cluster_name)s başlatılıyor." -#: django_q/cluster.py:295 +#: cluster.py:314 #, python-format msgid "%(name)s stopping cluster processes" msgstr "Cluster %(name)s işlemleri durduruluyor." -#: django_q/cluster.py:320 +#: cluster.py:339 #, python-format msgid "%(name)s waiting for the monitor." msgstr "%(name)s monitor için bekliyor." -#: django_q/cluster.py:342 +#: cluster.py:362 #, python-format msgid "%(process_name)s pushing tasks at %(id)s" msgstr "%(process_name)s, işleri %(id)s pid'ine gönderiyor." -#: django_q/cluster.py:363 +#: cluster.py:386 #, python-format msgid "queueing from %(list_key)s" msgstr "" -#: django_q/cluster.py:366 +#: cluster.py:390 #, python-format msgid "%(name)s stopped pushing tasks" msgstr "%(name)s işleri göndermeyi durdurdu" -#: django_q/cluster.py:378 +#: cluster.py:403 #, python-format msgid "%(name)s monitoring at %(id)s" msgstr "%(name)s, %(id)s pid'inde izleniyor/monitoring yapılıyor." -#: django_q/cluster.py:395 +#: cluster.py:422 #, python-format msgid "Processed '%(info_name)s' (%(task_name)s)" msgstr "[%(task_name)s] - '%(info_name)s işlendi." -#: django_q/cluster.py:398 +#: cluster.py:428 #, python-format msgid "Failed '%(info_name)s' (%(task_name)s) - %(task_result)s" msgstr "[%(task_name)s] - '%(info_name)s' - %(task_result)s başarısız oldu" -#: django_q/cluster.py:399 +#: cluster.py:435 #, python-format msgid "%(name)s stopped monitoring results" msgstr "%(name)s sonuçları göstermeyi bıraktı" -#: django_q/cluster.py:413 +#: cluster.py:451 #, python-format msgid "%(proc_name)s ready for work at %(id)s" msgstr "%(proc_name)s, %(id)s pid'inde çalışmaya hazır" -#: django_q/cluster.py:425 +#: cluster.py:466 #, python-format msgid "%(proc_name)s processing '%(func_name)s' (%(task_name)s)" msgstr "%(proc_name)s, '%(func_name)s' [%(task_name)s] işlerini işiyor" -#: django_q/cluster.py:440 -#, python-format -msgid "" -"Could not process '%(func_name)s'. Check the location of the function and " -"the args/kwargs." -msgstr "" -"%(func_name)s' işlenemedi. İşlevin konumunu ve args/kwargs öğelerini kontrol " -"edin." - -#: django_q/cluster.py:456 +#: cluster.py:507 #, python-format msgid "%(proc_name)s stopped doing work" msgstr "%(proc_name)s çalışmayı bıraktı" -#: django_q/cluster.py:649 django_q/models.py:144 -msgid "Please install croniter to enable cron expressions" -msgstr "Cron expressions'ları açmak için croniter yükleyin" - -#: django_q/cluster.py:672 +#: cluster.py:712 #, python-format msgid "%(process_name)s failed to create a task from schedule [%(schedule)s]" msgstr "%(process_name)s programdan bir görev oluşturamadı [%(schedule)s]" -#: django_q/cluster.py:678 -#, python-format -msgid "%(process_name)s created a task from schedule [%(schedule)s]" +#: cluster.py:723 +#, fuzzy, python-format +#| msgid "%(process_name)s created a task from schedule [%(schedule)s]" +msgid "" +"%(process_name)s created task %(task_name)s from schedule [%(schedule)s]" msgstr "%(process_name)s programdan bir görev oluşturamadı [%(schedule)s]" -#: django_q/cluster.py:718 +#: cluster.py:769 msgid "Skipping cpu affinity because psutil was not found." msgstr "Psutil bulunamadığı için cpu benzeşimi atlanıyor." -#: django_q/cluster.py:723 +#: cluster.py:774 msgid "Faking cpu affinity because it is not supported on this platform" msgstr "Bu platformda desteklenmediği için sahte cpu benzeşimi" -#: django_q/cluster.py:744 +#: cluster.py:796 #, python-format msgid "%(pid)s will use cpu %(affinity)s" msgstr "%(pid)s cpu %(affinity)s kullanacaktır" -#: django_q/conf.py:85 +#: conf.py:85 #, python-format msgid "" "SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', " @@ -193,295 +182,311 @@ msgstr "" "'group', 'name', 'func' ve None. Varsayılan değer None'dır." #. Translators: Cluster status descriptions -#: django_q/conf.py:194 +#: conf.py:202 msgid "Starting" msgstr "Başlıyor" -#: django_q/conf.py:195 +#: conf.py:203 msgid "Working" msgstr "Çalışıyor" -#: django_q/conf.py:196 +#: conf.py:204 msgid "Idle" msgstr "Boşta" -#: django_q/conf.py:197 +#: conf.py:205 msgid "Stopped" msgstr "Durdu" -#: django_q/conf.py:198 +#: conf.py:206 msgid "Stopping" msgstr "Durduruluyor" #. Translators: help text for qcluster management command -#: django_q/management/commands/qcluster.py:9 +#: management/commands/qcluster.py:9 msgid "Starts a Django Q Cluster." msgstr "Bir Django Q Cluster çalıştırır." #. Translators: help text for qinfo management command -#: django_q/management/commands/qinfo.py:11 +#: management/commands/qinfo.py:11 msgid "General information over all clusters." msgstr "Tüm cluster'lar için genel bilgiler." #. Translators: help text for qmemory management command -#: django_q/management/commands/qmemory.py:9 +#: management/commands/qmemory.py:9 msgid "Monitors Q Cluster memory usage" msgstr "Q Cluster'ın bellek kullanımını izler" #. Translators: help text for qmonitor management command -#: django_q/management/commands/qmonitor.py:9 +#: management/commands/qmonitor.py:9 msgid "Monitors Q Cluster activity" msgstr "Q Cluster'ın aktivitelerini izler" -#: django_q/models.py:119 +#: models.py:125 msgid "Successful task" msgstr "Başarılı iş" -#: django_q/models.py:120 +#: models.py:126 msgid "Successful tasks" msgstr "Başarılı işler" -#: django_q/models.py:135 +#: models.py:141 msgid "Failed task" msgstr "Başarısız iş" -#: django_q/models.py:136 +#: models.py:142 msgid "Failed tasks" msgstr "Başarısız işler" -#: django_q/models.py:160 +#: models.py:150 models.py:234 +msgid "Please install croniter to enable cron expressions" +msgstr "Cron expressions'ları açmak için croniter yükleyin" + +#: models.py:170 msgid "e.g. 1, 2, 'John'" msgstr "Örneğin: 1, 2, 'Melih'" -#: django_q/models.py:162 +#: models.py:172 msgid "e.g. x=1, y=2, name='John'" msgstr "Örneğin: x=1, y=2, name='Melih'" -#: django_q/models.py:176 +#: models.py:186 msgid "Once" msgstr "Bir kere" -#: django_q/models.py:177 +#: models.py:187 msgid "Minutes" msgstr "Dakika" -#: django_q/models.py:178 +#: models.py:188 msgid "Hourly" msgstr "Saatlik" -#: django_q/models.py:179 +#: models.py:189 msgid "Daily" msgstr "Günlük" -#: django_q/models.py:180 +#: models.py:190 msgid "Weekly" msgstr "Haftalık" -#: django_q/models.py:181 +#: models.py:191 #, fuzzy #| msgid "Weekly" msgid "Biweekly" msgstr "İki haftada bir" -#: django_q/models.py:182 +#: models.py:192 msgid "Monthly" msgstr "Aylık" -#: django_q/models.py:183 +#: models.py:193 #, fuzzy #| msgid "Monthly" msgid "Bimonthly" msgstr "İki ayda bir" -#: django_q/models.py:184 +#: models.py:194 msgid "Quarterly" msgstr "Bir Çeyrek (3 Ay)" -#: django_q/models.py:185 +#: models.py:195 msgid "Yearly" msgstr "Yıllık" -#: django_q/models.py:186 +#: models.py:196 msgid "Cron" msgstr "" -#: django_q/models.py:189 +#: models.py:199 msgid "Schedule Type" msgstr "Zamanlama Tipi" -#: django_q/models.py:192 +#: models.py:202 msgid "Number of minutes for the Minutes type" msgstr "Dakika tipine göre dakika sayısı" -#: django_q/models.py:195 +#: models.py:205 msgid "Repeats" msgstr "Tekrar eder" -#: django_q/models.py:195 +#: models.py:205 msgid "n = n times, -1 = forever" msgstr "n = n kere, -1 = sonsuza kadar" -#: django_q/models.py:198 +#: models.py:208 msgid "Next Run" msgstr "Bir dahaki çalışma tarihi" -#: django_q/models.py:205 +#: models.py:215 msgid "Cron expression" msgstr "" -#: django_q/models.py:235 +#: models.py:224 +msgid "Name of kwarg to pass intended schedule date" +msgstr "" + +#: models.py:299 msgid "Scheduled task" msgstr "Zamanlanmış iş" -#: django_q/models.py:236 +#: models.py:300 msgid "Scheduled tasks" msgstr "Zamanlanmış işler" -#: django_q/models.py:262 +#: models.py:326 msgid "Queued task" msgstr "Sıraya alınmış iş" -#: django_q/models.py:263 +#: models.py:327 msgid "Queued tasks" msgstr "Sıraya alınmış işler" -#: django_q/monitor.py:62 django_q/monitor.py:339 +#: monitor.py:64 monitor.py:348 msgid "Host" msgstr "" -#: django_q/monitor.py:66 django_q/monitor.py:343 django_q/monitor.py:450 +#: monitor.py:68 monitor.py:352 monitor.py:459 msgid "Id" msgstr "" -#: django_q/monitor.py:70 +#: monitor.py:72 msgid "State" msgstr "Durum" -#: django_q/monitor.py:74 +#: monitor.py:76 msgid "Pool" msgstr "Havuz" -#: django_q/monitor.py:78 +#: monitor.py:80 msgid "TQ" msgstr "" -#: django_q/monitor.py:82 +#: monitor.py:84 msgid "RQ" msgstr "" -#: django_q/monitor.py:86 +#: monitor.py:88 msgid "RC" msgstr "" -#: django_q/monitor.py:90 +#: monitor.py:92 msgid "Up" msgstr "" -#: django_q/monitor.py:170 django_q/monitor.py:279 +#: monitor.py:172 monitor.py:286 msgid "Queued" msgstr "Sıraya alınmış" -#: django_q/monitor.py:178 +#: monitor.py:180 msgid "Success" msgstr "Başarılı olanlar" -#: django_q/monitor.py:188 django_q/monitor.py:287 +#: monitor.py:190 monitor.py:294 msgid "Failures" msgstr "Başarısız olanlar" -#: django_q/monitor.py:199 django_q/monitor.py:485 +#: monitor.py:201 monitor.py:498 msgid "[Press q to quit]" msgstr "[Çıkmak için q'ya basın]" -#: django_q/monitor.py:223 +#: monitor.py:227 msgid "day" msgstr "gün" -#: django_q/monitor.py:244 +#: monitor.py:248 msgid "second" msgstr "saniye" -#: django_q/monitor.py:247 +#: monitor.py:251 msgid "minute" msgstr "dakika" -#: django_q/monitor.py:250 +#: monitor.py:254 msgid "hour" msgstr "saat" -#: django_q/monitor.py:260 +#: monitor.py:263 #, python-format msgid "-- %(prefix)s %(version)s on %(info)s --" msgstr "-- %(prefix)s %(version)s üzerinde %(info)s --" -#: django_q/monitor.py:266 +#: monitor.py:273 msgid "Clusters" msgstr "" -#: django_q/monitor.py:270 +#: monitor.py:277 msgid "Workers" msgstr "" -#: django_q/monitor.py:274 +#: monitor.py:281 msgid "Restarts" msgstr "Yeniden çalıştırmalar" -#: django_q/monitor.py:283 +#: monitor.py:290 msgid "Successes" msgstr "Başarılı olanlar" -#: django_q/monitor.py:292 +#: monitor.py:299 msgid "Schedules" msgstr "Zamanlanmışlar" -#: django_q/monitor.py:296 +#: monitor.py:303 #, python-format msgid "Tasks/%(per)s" msgstr "İş/%(per)s" -#: django_q/monitor.py:300 +#: monitor.py:307 msgid "Avg time" msgstr "Ortalama süre" -#: django_q/monitor.py:348 +#: monitor.py:357 msgid "Available (%)" msgstr "Müsait (%) " -#: django_q/monitor.py:354 +#: monitor.py:363 msgid "Available (MB)" msgstr "Müsait (MB)" -#: django_q/monitor.py:359 +#: monitor.py:368 msgid "Total (MB)" msgstr "Toplam (MB)" -#: django_q/monitor.py:364 +#: monitor.py:373 msgid "Sentinel (MB)" msgstr "" -#: django_q/monitor.py:370 +#: monitor.py:379 msgid "Monitor (MB)" msgstr "İzleme (MB)" -#: django_q/monitor.py:376 +#: monitor.py:385 msgid "Workers (MB)" msgstr "" -#: django_q/monitor.py:478 +#: monitor.py:487 #, python-format msgid "Available lowest (): %(memory_percent)s ((at)s)" msgstr "Mevcut en düşük (): %(memory_percent)s ((at)s)" -#: django_q/monitor.py:496 +#: monitor.py:509 msgid "No clusters appear to be running." msgstr "Hiçbir küme çalışıyor görünmüyor." -#: django_q/signals.py:22 +#: signals.py:22 #, python-format msgid "malformed return hook '%(hook)s' for [%(name)s]" msgstr "" -#: django_q/signals.py:30 +#: signals.py:30 #, python-format msgid "return hook %(hook)s failed on [%(name)s] because %(error)s" msgstr "" + +#, python-format +#~ msgid "" +#~ "Could not process '%(func_name)s'. Check the location of the function and " +#~ "the args/kwargs." +#~ msgstr "" +#~ "%(func_name)s' işlenemedi. İşlevin konumunu ve args/kwargs öğelerini " +#~ "kontrol edin." diff --git a/django_q/migrations/0016_schedule_intended_date_kwarg.py b/django_q/migrations/0016_schedule_intended_date_kwarg.py new file mode 100644 index 0000000..234f1f9 --- /dev/null +++ b/django_q/migrations/0016_schedule_intended_date_kwarg.py @@ -0,0 +1,25 @@ +# Generated by Django 4.1.2 on 2023-01-15 22:34 + +from django.db import migrations, models +import django_q.models + + +class Migration(migrations.Migration): + + dependencies = [ + ("django_q", "0015_alter_schedule_schedule_type"), + ] + + operations = [ + migrations.AddField( + model_name="schedule", + name="intended_date_kwarg", + field=models.CharField( + blank=True, + help_text="Name of kwarg to pass intended schedule date", + max_length=100, + null=True, + validators=[django_q.models.validate_kwarg], + ), + ), + ] diff --git a/django_q/models.py b/django_q/models.py index 9a03019..8bf7f5c 100644 --- a/django_q/models.py +++ b/django_q/models.py @@ -1,4 +1,5 @@ from datetime import datetime, timedelta +from keyword import iskeyword # Django from django import get_version @@ -153,6 +154,10 @@ def validate_cron(value): raise ValidationError(e) +def validate_kwarg(value): + return value.isidentifier() and not iskeyword(value) + + class Schedule(models.Model): name = models.CharField(max_length=100, null=True, blank=True) func = models.CharField(max_length=256, help_text="e.g. module.tasks.function") @@ -211,6 +216,13 @@ class Schedule(models.Model): ) task = models.CharField(max_length=100, null=True, editable=False) cluster = models.CharField(max_length=100, default=None, null=True, blank=True) + intended_date_kwarg = models.CharField( + max_length=100, + null=True, + blank=True, + validators=[validate_kwarg], + help_text=_("Name of kwarg to pass intended schedule date"), + ) def calculate_next_run(self, next_run=None): # next run is always in UTC diff --git a/django_q/tasks.py b/django_q/tasks.py index b2aa7cf..5f91ba5 100644 --- a/django_q/tasks.py +++ b/django_q/tasks.py @@ -90,6 +90,7 @@ def schedule(func, *args, **kwargs): :type next_run: datetime.datetime :param cluster: optional cluster name. :param cron: optional cron expression + :param intended_date_kwarg: optional identifier to pass intended schedule date. :param kwargs: function keyword arguments. :return: the schedule object. :rtype: Schedule @@ -102,6 +103,7 @@ def schedule(func, *args, **kwargs): next_run = kwargs.pop("next_run", timezone.now()) cron = kwargs.pop("cron", None) cluster = kwargs.pop("cluster", None) + intended_date_kwarg = kwargs.pop("intended_date_kwarg", None) # check for name duplicates instead of am unique constraint if name and Schedule.objects.filter(name=name).exists(): @@ -120,6 +122,7 @@ def schedule(func, *args, **kwargs): next_run=next_run, cron=cron, cluster=cluster, + intended_date_kwarg=intended_date_kwarg, ) # make sure we trigger validation s.full_clean() diff --git a/django_q/tests/test_scheduler.py b/django_q/tests/test_scheduler.py index d1fbf77..db39895 100644 --- a/django_q/tests/test_scheduler.py +++ b/django_q/tests/test_scheduler.py @@ -417,6 +417,38 @@ def test_scheduler(broker, monkeypatch): assert task_queue.qsize() == 1 +@pytest.mark.django_db +def test_intended_schedule_kwarg(broker, monkeypatch): + broker.list_key = "scheduler_test:q" + broker.delete_queue() + run_date = timezone.now()-timedelta(hours=1) + schedule = create_schedule( + "math.copysign", + 1, + -1, + name="test math", + hook="django_q.tests.tasks.result", + schedule_type=Schedule.HOURLY, + repeats=1, + next_run=run_date, + intended_date_kwarg='intended_date', + ) + assert schedule.last_run() is None + assert schedule.intended_date_kwarg == 'intended_date' + # run scheduler + scheduler(broker=broker) + # set up the workflow + task_queue = Queue() + stop_event = Event() + stop_event.set() + # push it + pusher(task_queue, stop_event, broker=broker) + assert task_queue.qsize() == 1 + task = task_queue.get() + assert 'intended_date' in task['kwargs'] + assert task['kwargs']['intended_date'] == run_date.isoformat() + + @override_settings( DATABASE_ROUTERS=REPLICA_DATABASE_ROUTERS, DATABASES=REPLICA_DATABASES ) diff --git a/docs/schedules.rst b/docs/schedules.rst index b7b4f5b..8da5538 100644 --- a/docs/schedules.rst +++ b/docs/schedules.rst @@ -69,6 +69,10 @@ You can change this by setting the :ref:`catch_up` configuration setting to ``Fa The scheduler will then skip execution of scheduled events in the past. Instead those tasks will run once when the cluster starts again and the scheduler will find the next available slot in the future according to original schedule parameters. +When :ref:`catch_up` is to ``True`` it may be useful for the task to know what was the date and time it was originally intended to run at. +To achieve this, pass an identifier name to parameter `intended_date_kwarg` when creating the schedule. The intended datetime will then be passed - in isoformat string - as +a kwarg with that identifier name to the task that has been created. + Management Commands ------------------- @@ -123,9 +127,10 @@ Reference :param int repeats: Number of times to repeat schedule. -1=Always, 0=Never, n =n. :param datetime next_run: Next or first scheduled execution datetime. :param str cluster: optional cluster name. Task will be executed only on a cluster with a matching :ref:`name`. + :param str intended_date_kwarg: optional identifier to pass intended schedule date. :param dict q_options: options passed to async_task for this schedule :param kwargs: optional keyword arguments for the scheduled function. - + .. note:: q_options does not accept the 'broker' key with a broker instance but accepts a 'broker_name' key instead. This can be used to specify the broker connection name to assign the task. If a broker with the specified name does not exist or is not running at the moment of placing the task in queue it fallbacks to the random broker/queue that handled the schedule. @@ -183,9 +188,13 @@ Reference When set to -1, this will keep counting down. .. py:attribute:: cluster - + Task will be executed only on a cluster with a matching :ref:`name`. + .. py:attribute:: intended_date_kwarg + + Name of kwarg to pass intended schedule date. + .. py:attribute:: next_run Datetime of the next scheduled execution. From 650c3b15242ddf1e9188750e29c0c4e738f0704a Mon Sep 17 00:00:00 2001 From: msabatier <37879561+msabatier@users.noreply.github.com> Date: Wed, 18 Jan 2023 02:12:13 +0100 Subject: [PATCH 31/39] Fix use of database router for write queries and remove Conf.HAS_REPLICA (#61) Co-authored-by: Marc Sabatier --- django_q/cluster.py | 15 +---- django_q/conf.py | 3 - django_q/tests/test_scheduler.py | 64 ++++--------------- .../multiple_database_routers.py | 4 +- docs/configure.rst | 10 --- 5 files changed, 17 insertions(+), 79 deletions(-) diff --git a/django_q/cluster.py b/django_q/cluster.py index 7a52c34..04daf9f 100644 --- a/django_q/cluster.py +++ b/django_q/cluster.py @@ -20,7 +20,6 @@ except core.exceptions.AppRegistryNotReady: django.setup() -from django.conf import settings from django.utils import timezone from django.utils.translation import gettext_lazy as _ @@ -541,12 +540,7 @@ def save_task(task, broker: Broker): value = get_func_repr(value) filters[Conf.SAVE_LIMIT_PER] = value - database_to_use = ( - {"using": Conf.ORM if Conf.ORM else Schedule.objects.db} - if not Conf.HAS_REPLICA - else {} - ) - with db.transaction.atomic(**database_to_use): + with db.transaction.atomic(using=db.router.db_for_write(Success)): last = Success.objects.filter(**filters).select_for_update().last() if ( task["success"] @@ -652,12 +646,7 @@ def scheduler(broker: Broker = None): broker = get_broker() close_old_django_connections() try: - database_to_use = ( - {"using": Conf.ORM if Conf.ORM else Schedule.objects.db} - if not Conf.HAS_REPLICA - else {} - ) - with db.transaction.atomic(**database_to_use): + with db.transaction.atomic(using=db.router.db_for_write(Schedule)): for s in ( Schedule.objects.select_for_update() .exclude(repeats=0) diff --git a/django_q/conf.py b/django_q/conf.py index 3d32f0b..aabdb6a 100644 --- a/django_q/conf.py +++ b/django_q/conf.py @@ -54,9 +54,6 @@ class Conf: # ORM broker ORM = conf.get("orm", None) - # ORM support for read/write replicas - HAS_REPLICA = conf.get("has_replica", False) - # Custom broker class BROKER_CLASS = conf.get("broker_class", None) diff --git a/django_q/tests/test_scheduler.py b/django_q/tests/test_scheduler.py index db39895..bf226bb 100644 --- a/django_q/tests/test_scheduler.py +++ b/django_q/tests/test_scheduler.py @@ -50,25 +50,11 @@ def orm_broker(monkeypatch) -> None: monkeypatch.setattr(Conf, "ORM", "default") -@pytest.fixture -def orm_no_replica_broker(orm_broker, monkeypatch) -> Broker: - """Generates a Broker with a disabled read replica database configuration.""" - monkeypatch.setattr(Conf, "HAS_REPLICA", False) - return get_broker(list_key="scheduler_test:q") - - -@pytest.fixture -def orm_replica_broker(orm_broker, monkeypatch) -> Broker: - """Generates a Broker with read replica database configuration.""" - monkeypatch.setattr(Conf, "HAS_REPLICA", True) - return get_broker(list_key="scheduler_test:q") - - REPLICA_DATABASE_ROUTERS = [ f"{TestingReplicaDatabaseRouter.__module__}.{TestingReplicaDatabaseRouter.__name__}" ] REPLICA_DATABASES = { - "default": { + "writable": { "ENGINE": "django.db.backends.sqlite3", "NAME": os.path.join(BASE_DIR, "db.sqlite3"), }, @@ -453,39 +439,18 @@ def test_intended_schedule_kwarg(broker, monkeypatch): DATABASE_ROUTERS=REPLICA_DATABASE_ROUTERS, DATABASES=REPLICA_DATABASES ) @pytest.mark.django_db -def test_scheduler_atomic_transaction_must_specify_a_database_when_no_replicas_are_used( - orm_no_replica_broker: Broker, -): - """ - GIVEN a environment without a read replica database - WHEN the scheduler is called - THEN the transaction atomic must be called using the configured database in the - Conf.ORM settings. - """ - broker = orm_no_replica_broker - with mock.patch("django_q.cluster.db") as mocked_db: - scheduler(broker=broker) - # The router should correctly set the database to use! - mocked_db.transaction.atomic.assert_called_with(using=broker.connection.db) - - -@override_settings( - DATABASE_ROUTERS=REPLICA_DATABASE_ROUTERS, DATABASES=REPLICA_DATABASES -) -@pytest.mark.django_db -def test_scheduler_atomic_must_specify_no_db_when_read_write_replicas_are_used( - orm_replica_broker: Broker, +def test_scheduler_atomic_must_specify_the_write_db( + orm_broker: Broker, ): """ GIVEN a environment with a read/write configured replica database WHEN the scheduler is called - THEN the transaction must be called without a specific database, thus letting the - database router pick. + THEN the transaction must be called with the write database. """ - with mock.patch("django_q.cluster.db") as mocked_db: - scheduler(broker=orm_replica_broker) - # No specific databases should be set here, this is the job of the router! - mocked_db.transaction.atomic.assert_called_with() + broker = get_broker(list_key="scheduler_test:q") + with mock.patch("django_q.cluster.db.transaction") as mocked_db: + scheduler(broker=broker) + mocked_db.atomic.assert_called_with(using="writable") @override_settings( @@ -493,20 +458,17 @@ def test_scheduler_atomic_must_specify_no_db_when_read_write_replicas_are_used( ) @pytest.mark.django_db def test_scheduler_atomic_must_specify_the_database_based_on_router_redirection( - orm_no_replica_broker: Broker, + orm_broker: Broker, ): """ GIVEN a environment without a read replica database WHEN the scheduler is called - THEN the transaction atomic must be called using the configured database in the - Conf.ORM settings. + THEN the transaction atomic must be called using the default connection. """ - broker = orm_no_replica_broker - with mock.patch("django_q.cluster.db") as mocked_db: + broker = get_broker(list_key="scheduler_test:q") + with mock.patch("django_q.cluster.db.transaction") as mocked_db: scheduler(broker=broker) - # The router should correctly set the database to use! - assert broker.connection.db == "default" - mocked_db.transaction.atomic.assert_called_with(using=broker.connection.db) + mocked_db.atomic.assert_called_with(using="default") def test_localtime(): diff --git a/django_q/tests/testing_utilities/multiple_database_routers.py b/django_q/tests/testing_utilities/multiple_database_routers.py index 4958771..85b3e35 100644 --- a/django_q/tests/testing_utilities/multiple_database_routers.py +++ b/django_q/tests/testing_utilities/multiple_database_routers.py @@ -12,9 +12,9 @@ class TestingReplicaDatabaseRouter: def db_for_write(self, model, **hints): """ - Always write to DEFAULT database + Always write to WRITABLE database """ - return "default" + return "writable" class TestingMultipleAppsDatabaseRouter: diff --git a/docs/configure.rst b/docs/configure.rst index 1b83fe6..3b96df8 100644 --- a/docs/configure.rst +++ b/docs/configure.rst @@ -317,16 +317,6 @@ Using the Django ORM backend will also enable the Queued Tasks table in the Admi If you need better performance , you should consider using a different database backend than the main project. Set ``orm`` to the name of that database connection and make sure you run migrations on it using the ``--database`` option. -When using the Django database as a message broker, you can set the ``has_replica`` boolean keyword to ensure Django-Q2 works properly letting a `Database Router `__. :: - - # example ORM broker connection with replica database - - Q_CLUSTER = { - ... - 'orm': 'default', - 'has_replica': True - } - .. _mongo_configuration: mongo From 17c1609f10149fc2e80c17195d9d5197b947e927 Mon Sep 17 00:00:00 2001 From: msabatier <37879561+msabatier@users.noreply.github.com> Date: Thu, 26 Jan 2023 02:21:56 +0100 Subject: [PATCH 32/39] Add meaningfull process titles with currently running task name (#57) * Customize process names (in ps/top) and add task name in logs * Increase severity of reincarnate log messages and add task name * Document setproctitle optional dependency Co-authored-by: Marc Sabatier <37879561+msabatier@users.noreply.github.com> Co-authored-by: Stan Triepels <1939656+GDay@users.noreply.github.com> --- django_q/cluster.py | 75 +- django_q/conf.py | 5 + django_q/locale/de/LC_MESSAGES/django.po | 130 +- django_q/locale/fr/LC_MESSAGES/django.po | 195 +- django_q/locale/tr/LC_MESSAGES/django.po | 152 +- docs/install.rst | 4 + poetry.lock | 2077 +++++++++++----------- pyproject.toml | 3 +- 8 files changed, 1399 insertions(+), 1242 deletions(-) diff --git a/django_q/cluster.py b/django_q/cluster.py index 04daf9f..13d7a2f 100644 --- a/django_q/cluster.py +++ b/django_q/cluster.py @@ -33,6 +33,7 @@ from django_q.conf import ( get_ppid, logger, psutil, + setproctitle, resource, ) from django_q.humanhash import humanize @@ -59,6 +60,8 @@ class Cluster: signal.signal(signal.SIGINT, self.sig_handler) def start(self) -> int: + if setproctitle: + setproctitle.setproctitle(f"qcluster {current_process().name} {self.name}") # Start Sentinel self.stop_event = Event() self.start_event = Event() @@ -217,13 +220,13 @@ class Sentinel: db.connections.close_all() if process == self.monitor: self.monitor = self.spawn_monitor() - logger.error( + logger.critical( _("reincarnated monitor %(name)s after sudden death") % {"name": process.name} ) elif process == self.pusher: self.pusher = self.spawn_pusher() - logger.error( + logger.critical( _("reincarnated pusher %(name)s after sudden death") % {"name": process.name} ) @@ -233,15 +236,30 @@ class Sentinel: if process.timer.value == 0: # only need to terminate on timeout, otherwise we risk destabilizing # the queues + task_name = "" + if psutil: + try: + process_name = psutil.Process(process.pid).name() + name_splits = process_name.split(" ") + task_name = name_splits[3] if len(name_splits) >= 4 and name_splits[2] == "processing" else "" + except psutil.NoSuchProcess: + pass process.terminate() - logger.warning( - _("reincarnated worker %(name)s after timeout") - % {"name": process.name} - ) + if task_name: + msg = ( + _("reincarnated worker %(name)s after timeout while processing task %(task_name)s") + % {"name": process.name, "task_name": task_name} + ) + else: + msg = ( + _("reincarnated worker %(name)s after timeout") + % {"name": process.name} + ) + logger.critical(msg) elif int(process.timer.value) == -2: logger.info(_("recycled worker %(name)s") % {"name": process.name}) else: - logger.error( + logger.critical( _("reincarnated worker %(name)s after death") % {"name": process.name} ) @@ -358,9 +376,12 @@ def pusher(task_queue: Queue, event: Event, broker: Broker = None): """ if not broker: broker = get_broker() + proc_name = current_process().name + if setproctitle: + setproctitle.setproctitle(f"qcluster {proc_name} pusher") logger.info( - _("%(process_name)s pushing tasks at %(id)s") - % {"process_name": current_process().name, "id": current_process().pid} + _("%(name)s pushing tasks at %(id)s") + % {"name": proc_name, "id": current_process().pid} ) while True: try: @@ -398,9 +419,11 @@ def monitor(result_queue: Queue, broker: Broker = None): """ if not broker: broker = get_broker() - name = current_process().name + proc_name = current_process().name + if setproctitle: + setproctitle.setproctitle(f"qcluster {proc_name} monitor") logger.info( - _("%(name)s monitoring at %(id)s") % {"name": name, "id": current_process().pid} + _("%(name)s monitoring at %(id)s") % {"name": proc_name, "id": current_process().pid} ) for task in iter(result_queue.get, "STOP"): # save the result @@ -432,7 +455,7 @@ def monitor(result_queue: Queue, broker: Broker = None): "task_result": task["result"], } ) - logger.info(_("%(name)s stopped monitoring results") % {"name": name}) + logger.info(_("%(name)s stopped monitoring results") % {"name": proc_name}) def worker( @@ -451,6 +474,8 @@ def worker( _("%(proc_name)s ready for work at %(id)s") % {"proc_name": proc_name, "id": current_process().pid} ) + if setproctitle: + setproctitle.setproctitle(f"qcluster {proc_name} idle") task_count = 0 if timeout is None: timeout = -1 @@ -459,18 +484,30 @@ def worker( result = None timer.value = -1 # Idle task_count += 1 + f = task["func"] + + # Log task creation and set process name # Get the function from the task - func = task["func"] - func_name = get_func_repr(func) - logger.info( - _("%(proc_name)s processing '%(func_name)s' (%(task_name)s)") + func_name = get_func_repr(f) + task_name = task["name"] + task_desc = ( + _("%(proc_name)s processing %(task_name)s '%(func_name)s'") % { "proc_name": proc_name, "func_name": func_name, - "task_name": task["name"], + "task_name": task_name, } ) - f = task["func"] + if "group" in task: + task_desc += f" [{task['group']}]" + logger.info(task_desc) + + if setproctitle: + proc_title = f"qcluster {proc_name} processing {task_name} '{func_name}'" + if "group" in task: + proc_title += f" [{task['group']}]" + setproctitle.setproctitle(proc_title) + # if it's not an instance try to get it from the string if not callable(f): # locate() returns None if f cannot be loaded @@ -500,6 +537,8 @@ def worker( task["stopped"] = timezone.now() result_queue.put(task) timer.value = -1 # Idle + if setproctitle: + setproctitle.setproctitle(f"qcluster {proc_name} idle") # Recycle if task_count == Conf.RECYCLE or rss_check(): timer.value = -2 # Recycled diff --git a/django_q/conf.py b/django_q/conf.py index aabdb6a..fb556ba 100644 --- a/django_q/conf.py +++ b/django_q/conf.py @@ -27,6 +27,11 @@ try: except ModuleNotFoundError: resource = None +try: + import setproctitle +except ModuleNotFoundError: + setproctitle = None + class Conf: """ diff --git a/django_q/locale/de/LC_MESSAGES/django.po b/django_q/locale/de/LC_MESSAGES/django.po index 915b8df..151e0f6 100644 --- a/django_q/locale/de/LC_MESSAGES/django.po +++ b/django_q/locale/de/LC_MESSAGES/django.po @@ -42,17 +42,18 @@ msgstr "Q-Cluster %(name)s wird gestartet." msgid "Q Cluster %(name)s stopping." msgstr "Q-Cluster {name} wird gestoppt." -#: cluster.py:87 +#: cluster.py:91 #, python-format msgid "Q Cluster %(name)s has stopped." msgstr "Q-Cluster %(name)s wurde gestoppt." + #: cluster.py:94 #, python-format msgid "%(name)s got signal %(signal)s" msgstr "%(name)s erhielt das Signal %(signal)s" -#: cluster.py:221 +#: cluster.py:225 #, python-format msgid "reincarnated monitor %(name)s after sudden death" msgstr "Monitor %(name)s wurde nach unerwartetem Absturz neu gestartet" @@ -62,7 +63,15 @@ msgstr "Monitor %(name)s wurde nach unerwartetem Absturz neu gestartet" msgid "reincarnated pusher %(name)s after sudden death" msgstr "Pusher %(name)s wurde nach unerwartetem Absturz neu gestartet" -#: cluster.py:238 +#: cluster.py:251 +#, fuzzy, python-format +#| msgid "reincarnated worker %(name)s after timeout" +msgid "" +"reincarnated worker %(name)s after timeout while processing task " +"%(task_name)s" +msgstr "Worker %(name)s wurde nach Zeitüberschreitung neu gestartet" + +#: cluster.py:256 #, python-format msgid "reincarnated worker %(name)s after timeout" msgstr "Worker %(name)s wurde nach Zeitüberschreitung neu gestartet" @@ -87,6 +96,7 @@ msgstr "%(name)s beschützt das Cluster %(cluster_name)s" msgid "Q Cluster %(cluster_name)s running." msgstr "Q-Cluster %(cluster_name)s läuft." + #: cluster.py:314 #, python-format msgid "%(name)s stopping cluster processes" @@ -97,63 +107,66 @@ msgstr "%(name)s hält Cluster-Prozesse an" msgid "%(name)s waiting for the monitor." msgstr "%(name)s wartet auf den Monitor." -#: cluster.py:362 -#, python-format -msgid "%(process_name)s pushing tasks at %(id)s" + +#: cluster.py:384 +#, fuzzy, python-format +#| msgid "%(process_name)s pushing tasks at %(id)s" +msgid "%(name)s pushing tasks at %(id)s" msgstr "%(process_name)s veröffentlicht Aufagaben auf %(id)s" -#: cluster.py:386 +#: cluster.py:408 #, python-format msgid "queueing from %(list_key)s" msgstr "Einreihen von %(list_key)s" -#: cluster.py:390 +#: cluster.py:412 #, python-format msgid "%(name)s stopped pushing tasks" msgstr "%(name)s veröffentlicht keine Aufgaben mehr" -#: cluster.py:403 +#: cluster.py:427 #, python-format msgid "%(name)s monitoring at %(id)s" msgstr "%(name)s beobachtet auf %(id)s" -#: cluster.py:422 +#: cluster.py:446 #, python-format msgid "Processed '%(info_name)s' (%(task_name)s)" msgstr "[%(task_name)s] - '%(info_name)s' wurde verarbeitet" -#: cluster.py:428 +#: cluster.py:452 #, python-format msgid "Failed '%(info_name)s' (%(task_name)s) - %(task_result)s" msgstr "'%(info_name)s' (%(task_name)s) ist fehlgeschlagen - %(task_result)s" -#: cluster.py:435 +#: cluster.py:459 #, python-format msgid "%(name)s stopped monitoring results" msgstr "%(name)s überwacht keine Ergebnisse mehr" -#: cluster.py:451 +#: cluster.py:475 #, python-format msgid "%(proc_name)s ready for work at %(id)s" msgstr "%(proc_name)s ist bereit für Arbeit auf %(id)s" -#: cluster.py:466 -#, python-format -msgid "%(proc_name)s processing '%(func_name)s' (%(task_name)s)" +#: cluster.py:495 +#, fuzzy, python-format +#| msgid "%(proc_name)s processing '%(func_name)s' (%(task_name)s)" +msgid "%(proc_name)s processing %(task_name)s '%(func_name)s'" msgstr "%(proc_name)s verarbeitet '%(func_name)s' (%(task_name)s)" -#: cluster.py:507 +#: cluster.py:543 #, python-format msgid "%(proc_name)s stopped doing work" msgstr "%(proc_name)s hat die Arbeit beendet" -#: cluster.py:712 +#: cluster.py:756 #, python-format msgid "%(process_name)s failed to create a task from schedule [%(schedule)s]" msgstr "" "%(process_name)s konnte keine Aufgabe von Zeitplan [%(schedule)s] erstellen" -#: cluster.py:723 +#: cluster.py:767 #, fuzzy, python-format #| msgid "%(process_name)s created a task from schedule [%(schedule)s]" msgid "" @@ -161,22 +174,22 @@ msgid "" msgstr "" "%(process_name)s hat eine Aufgabe des Zeitplans [%(schedule)s] erstellt" -#: cluster.py:769 +#: cluster.py:813 msgid "Skipping cpu affinity because psutil was not found." msgstr "Cpu-Affinität wird übersprungen, da psutil nicht gefunden wurde." -#: cluster.py:774 +#: cluster.py:818 msgid "Faking cpu affinity because it is not supported on this platform" msgstr "" "Vortäuschen von CPU-Affinität, da diese auf dieser Plattform nicht " "unterstützt wird" -#: cluster.py:796 +#: cluster.py:840 #, python-format msgid "%(pid)s will use cpu %(affinity)s" msgstr "%(pid)s wird CPU %(affinity)s benutzen" -#: conf.py:85 +#: conf.py:93 #, python-format msgid "" "SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', " @@ -186,23 +199,23 @@ msgstr "" "'group', 'name', 'func' und None. Standard ist None." #. Translators: Cluster status descriptions -#: conf.py:202 +#: conf.py:210 msgid "Starting" msgstr "Wird gestartet" -#: conf.py:203 +#: conf.py:211 msgid "Working" msgstr "Arbeitet" -#: conf.py:204 +#: conf.py:212 msgid "Idle" msgstr "Leerlauf" -#: conf.py:205 +#: conf.py:213 msgid "Stopped" msgstr "Gestoppt" -#: conf.py:206 +#: conf.py:214 msgid "Stopping" msgstr "Wird gestoppt" @@ -226,119 +239,116 @@ msgstr "Überwacht die Speichernutzung von Q Cluster" msgid "Monitors Q Cluster activity" msgstr "Q-Cluster aktiv überwachen" -#: models.py:125 + +#: models.py:124 msgid "Successful task" msgstr "Erfolgreiche Aufgabe" -#: models.py:126 +#: models.py:125 msgid "Successful tasks" msgstr "Erfolgreiche Aufgaben" -#: models.py:141 +#: models.py:140 msgid "Failed task" msgstr "Fehlgeschlagene Aufgabe" -#: models.py:142 +#: models.py:141 msgid "Failed tasks" msgstr "Fehlgeschlagene Aufgaben" -#: models.py:150 models.py:234 +#: models.py:149 models.py:222 msgid "Please install croniter to enable cron expressions" msgstr "Bitte installieren Sie croniter, um Cron-Ausdrücke zu aktivieren" -#: models.py:170 +#: models.py:165 msgid "e.g. 1, 2, 'John'" msgstr "zum Beispiel 1, 2, 'John'" -#: models.py:172 +#: models.py:167 msgid "e.g. x=1, y=2, name='John'" msgstr "zum Beispiel x=1, y=2, name='John'" -#: models.py:186 +#: models.py:181 msgid "Once" msgstr "Einmal" -#: models.py:187 +#: models.py:182 msgid "Minutes" msgstr "Minuten" -#: models.py:188 +#: models.py:183 msgid "Hourly" msgstr "Stündlich" -#: models.py:189 +#: models.py:184 msgid "Daily" msgstr "Täglich" -#: models.py:190 +#: models.py:185 msgid "Weekly" msgstr "Wöchentlich" -#: models.py:191 +#: models.py:186 msgid "Biweekly" msgstr "Zweiwöchentlich" -#: models.py:192 +#: models.py:187 msgid "Monthly" msgstr "Monatlich" -#: models.py:193 +#: models.py:188 msgid "Bimonthly" msgstr "Zweimonatlich" -#: models.py:194 +#: models.py:189 msgid "Quarterly" msgstr "Vierteljährlich" -#: models.py:195 +#: models.py:190 msgid "Yearly" msgstr "Jährlich" -#: models.py:196 +#: models.py:191 msgid "Cron" msgstr "Cron" -#: models.py:199 +#: models.py:194 msgid "Schedule Type" msgstr "Zeitplan-Typ" -#: models.py:202 +#: models.py:197 msgid "Number of minutes for the Minutes type" msgstr "Anzahl Minuten für den Typ 'Minuten'" -#: models.py:205 +#: models.py:200 msgid "Repeats" msgstr "Wiederhohlungen" -#: models.py:205 +#: models.py:200 msgid "n = n times, -1 = forever" msgstr "n = n mal, -1 = für immer" -#: models.py:208 +#: models.py:203 msgid "Next Run" msgstr "Nächste Ausführung" -#: models.py:215 +#: models.py:210 msgid "Cron expression" msgstr "Cron-Ausdruck" -#: models.py:224 -msgid "Name of kwarg to pass intended schedule date" -msgstr "" - -#: models.py:299 +#: models.py:287 msgid "Scheduled task" msgstr "Geplante Aufgabe" -#: models.py:300 +#: models.py:288 msgid "Scheduled tasks" msgstr "Geplante Aufgaben" -#: models.py:326 +#: models.py:314 msgid "Queued task" msgstr "Eingereihte Aufgabe" -#: models.py:327 +#: models.py:315 msgid "Queued tasks" msgstr "Eingereihte Aufgaben" diff --git a/django_q/locale/fr/LC_MESSAGES/django.po b/django_q/locale/fr/LC_MESSAGES/django.po index 762fd2f..6f4eb0a 100644 --- a/django_q/locale/fr/LC_MESSAGES/django.po +++ b/django_q/locale/fr/LC_MESSAGES/django.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-01-15 23:35+0100\n" +"POT-Creation-Date: 2023-01-07 19:21+0100\n" "PO-Revision-Date: 2018-08-05 18:28+0200\n" "Last-Translator: Thierry BOULOGNE \n" "Language-Team: \n" @@ -21,160 +21,172 @@ msgstr "" msgid "Resubmit selected tasks to queue" msgstr "Resoumettre les tâches sélectionnées à la file d'attente" -#: admin.py:107 models.py:293 +#: admin.py:107 models.py:281 #, fuzzy #| msgid "Success" msgid "success" msgstr "succès" -#: admin.py:119 models.py:295 +#: admin.py:119 models.py:283 msgid "last_run" msgstr "" -#: cluster.py:76 +#: cluster.py:80 #, python-format msgid "Q Cluster %(name)s starting." msgstr "Démarrage de Q Cluster-%(name)s." -#: cluster.py:84 +#: cluster.py:88 #, python-format msgid "Q Cluster %(name)s stopping." msgstr "Arrêt de Q Cluster-%(name)s." -#: cluster.py:87 +#: cluster.py:91 #, python-format msgid "Q Cluster %(name)s has stopped." msgstr "Q Cluster-%(name)s a été arrêté." -#: cluster.py:94 +#: cluster.py:98 #, python-format msgid "%(name)s got signal %(signal)s" msgstr "%(name)s à reçu le signal %(signal)s" -#: cluster.py:221 +#: cluster.py:225 #, python-format msgid "reincarnated monitor %(name)s after sudden death" -msgstr "moniteur réintégré %(name)s après un arrêt intempestif" +msgstr "surveillant %(name)s réincarné après un arrêt intempestif" -#: cluster.py:227 + +#: cluster.py:231 #, python-format msgid "reincarnated pusher %(name)s after sudden death" -msgstr "pousseur réintégré %(name)s après un arrêt intempestif" +msgstr "répartiteur %(name)s réincarné après un arrêt intempestif" -#: cluster.py:238 +#: cluster.py:251 +#, python-format +msgid "" +"reincarnated worker %(name)s after timeout while processing task " +"%(task_name)s" +msgstr "" +"processus %(name)s réincarné, délai de traitement dépassé pour la tâche " +"%(task_name)s" + +#: cluster.py:256 #, python-format msgid "reincarnated worker %(name)s after timeout" -msgstr "processus réintégré %(name)s après un arrêt une attente trop longue" +msgstr "processus %(name)s réincarné, délai de traitement dépassé" -#: cluster.py:242 +#: cluster.py:261 #, python-format msgid "recycled worker %(name)s" msgstr "processus recyclé %(name)s" -#: cluster.py:245 +#: cluster.py:264 #, python-format msgid "reincarnated worker %(name)s after death" msgstr "processus réintégré %(name)s après arrêt" -#: cluster.py:269 +#: cluster.py:288 #, python-format msgid "%(name)s guarding cluster %(cluster_name)s" msgstr "%(name)s surveillance du cluster à %(cluster_name)s" -#: cluster.py:278 +#: cluster.py:297 #, python-format msgid "Q Cluster %(cluster_name)s running." msgstr "Démarrage de Q Cluster-%(cluster_name)s." -#: cluster.py:314 +#: cluster.py:333 #, python-format msgid "%(name)s stopping cluster processes" -msgstr "%(name)s arrêt des processus de cluster" +msgstr "%(name)s arrêt des processus du cluster" -#: cluster.py:339 +#: cluster.py:358 #, python-format msgid "%(name)s waiting for the monitor." -msgstr "%(name)s en attente du moniteur." +msgstr "%(name)s en attente du surveillant." -#: cluster.py:362 +#: cluster.py:384 #, python-format -msgid "%(process_name)s pushing tasks at %(id)s" -msgstr "%(process_name)s tâche envoyé à %(id)s" +msgid "%(name)s pushing tasks at %(id)s" +msgstr "%(name)s répartit les tâches %(id)s" -#: cluster.py:386 +#: cluster.py:408 #, python-format msgid "queueing from %(list_key)s" msgstr "mise en file d'attente de %(list_key)s" -#: cluster.py:390 +#: cluster.py:412 #, python-format msgid "%(name)s stopped pushing tasks" -msgstr "%(name)s a cessé de pousser les tâches" +msgstr "%(name)s a cessé de répartir les tâches" -#: cluster.py:403 +#: cluster.py:427 #, python-format msgid "%(name)s monitoring at %(id)s" -msgstr "%(name)s Surveillance de %(id)s" +msgstr "%(name)s surveille les résultats %(id)s" -#: cluster.py:422 +#: cluster.py:446 #, python-format msgid "Processed '%(info_name)s' (%(task_name)s)" msgstr "traité '%(info_name)s' (%(task_name)s)" -#: cluster.py:428 +#: cluster.py:452 #, python-format msgid "Failed '%(info_name)s' (%(task_name)s) - %(task_result)s" msgstr "Manqué '%(info_name)s' (%(task_name)s) - %(task_result)s" -#: cluster.py:435 +#: cluster.py:459 #, python-format msgid "%(name)s stopped monitoring results" -msgstr "%(name)s arrêt des résultats de surveillance" +msgstr "%(name)s a cessé de de surveiller les résultats" -#: cluster.py:451 +#: cluster.py:475 #, python-format msgid "%(proc_name)s ready for work at %(id)s" msgstr "%(proc_name)s prêt pour le travail à %(id)s" -#: cluster.py:466 -#, python-format -msgid "%(proc_name)s processing '%(func_name)s' (%(task_name)s)" -msgstr "%(proc_name)s en traitement '%(func_name)s' (%(task_name)s)" +#: cluster.py:495 +#, fuzzy, python-format +msgid "%(proc_name)s processing %(task_name)s '%(func_name)s'" +msgstr "%(proc_name)s exécute %(task_name)s '%(func_name)s'" -#: cluster.py:507 +#: cluster.py:543 #, python-format msgid "%(proc_name)s stopped doing work" -msgstr "%(proc_name)s arrêté de travailler" +msgstr "%(proc_name)s a cessé de travailler" -#: cluster.py:712 +#: cluster.py:756 #, python-format msgid "%(process_name)s failed to create a task from schedule [%(schedule)s]" msgstr "" "%(process_name)s Echec de la création d'une tâche à partir de Schedule " "[%(schedule)s]" -#: cluster.py:723 +#: cluster.py:767 #, python-format msgid "" "%(process_name)s created task %(task_name)s from schedule [%(schedule)s]" -msgstr "%(process_name)s a créé la tâche %(task_name)s à partir de Schedule [%(schedule)s]" +msgstr "" +"%(process_name)s a créé la tâche %(task_name)s à partir de Schedule " +"[%(schedule)s]" -#: cluster.py:769 +#: cluster.py:813 msgid "Skipping cpu affinity because psutil was not found." -msgstr "Sauter l'affinité du processeur parce que psutil n'a pas été trouvé." +msgstr "L'affinité cpu ne sera pas définie car psutil n'a pas été trouvé." -#: cluster.py:774 +#: cluster.py:818 msgid "Faking cpu affinity because it is not supported on this platform" msgstr "" -"Simulation de l'affinité du processeur parce qu'elle n'est pas supportée sur " -"cette plateforme." +"Simulation de l'affinité cpu parce qu'elle n'est pas supportée sur cette " +"plateforme." -#: cluster.py:796 +#: cluster.py:840 #, python-format msgid "%(pid)s will use cpu %(affinity)s" msgstr "%(pid)s utilisera le CPU %(affinity)s" -#: conf.py:85 +#: conf.py:93 #, python-format msgid "" "SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', " @@ -184,23 +196,23 @@ msgstr "" "'group', 'name', 'func' et None. La valeur par défaut est None." #. Translators: Cluster status descriptions -#: conf.py:202 +#: conf.py:210 msgid "Starting" msgstr "Démarrage" -#: conf.py:203 +#: conf.py:211 msgid "Working" msgstr "Actif" -#: conf.py:204 +#: conf.py:212 msgid "Idle" msgstr "En attente" -#: conf.py:205 +#: conf.py:213 msgid "Stopped" msgstr "Arrêté" -#: conf.py:206 +#: conf.py:214 msgid "Stopping" msgstr "En cours d’arrêt" @@ -219,130 +231,126 @@ msgstr "Informations générales sur tous les clusters." #, fuzzy #| msgid "Monitors Q Cluster activity" msgid "Monitors Q Cluster memory usage" -msgstr "Surveille l'utilisation de la mémoire du cluster Q" +msgstr "Surveille l'utilisation mémoire du Q cluster" #. Translators: help text for qmonitor management command #: management/commands/qmonitor.py:9 msgid "Monitors Q Cluster activity" -msgstr "Activité du cluster Moniteur Q" +msgstr "Surveille l'activité de Q cluster" -#: models.py:125 +#: models.py:124 msgid "Successful task" msgstr "Tâche réussie" -#: models.py:126 +#: models.py:125 msgid "Successful tasks" msgstr "Tâches réussies" -#: models.py:141 +#: models.py:140 msgid "Failed task" msgstr "Tâche échoué" -#: models.py:142 +#: models.py:141 msgid "Failed tasks" msgstr "Tâches échouées" -#: models.py:150 models.py:234 +#: models.py:149 models.py:222 msgid "Please install croniter to enable cron expressions" -msgstr "Veuillez installer croniter pour activer les expressions croniques." +msgstr "Veuillez installer croniter pour activer les expressions cron." -#: models.py:170 +#: models.py:165 msgid "e.g. 1, 2, 'John'" msgstr "ex. 1, 2, ‘Jean’" -#: models.py:172 +#: models.py:167 msgid "e.g. x=1, y=2, name='John'" msgstr "p. ex. x = 1, y = 2, Nom = ‘Jean’" -#: models.py:186 +#: models.py:181 msgid "Once" msgstr "Une fois" -#: models.py:187 +#: models.py:182 msgid "Minutes" msgstr "Minutes" -#: models.py:188 +#: models.py:183 msgid "Hourly" msgstr "Toutes les heures" -#: models.py:189 +#: models.py:184 msgid "Daily" msgstr "Quotidien" -#: models.py:190 +#: models.py:185 msgid "Weekly" msgstr "Hebdomadaire" -#: models.py:191 +#: models.py:186 #, fuzzy #| msgid "Weekly" msgid "Biweekly" msgstr "Bihebdomadaire" -#: models.py:192 +#: models.py:187 msgid "Monthly" msgstr "Mensuel" -#: models.py:193 +#: models.py:188 #, fuzzy #| msgid "Monthly" msgid "Bimonthly" msgstr "Bimestriel" -#: models.py:194 +#: models.py:189 msgid "Quarterly" msgstr "Tous les quart-d’heure" -#: models.py:195 +#: models.py:190 msgid "Yearly" msgstr "Annuel" -#: models.py:196 +#: models.py:191 msgid "Cron" msgstr "Cron" -#: models.py:199 +#: models.py:194 msgid "Schedule Type" msgstr "Type de plannification" -#: models.py:202 +#: models.py:197 msgid "Number of minutes for the Minutes type" msgstr "Nombre de minutes pour le type de minutes" -#: models.py:205 +#: models.py:200 msgid "Repeats" msgstr "Répéter" -#: models.py:205 +#: models.py:200 msgid "n = n times, -1 = forever" msgstr "n = n fois,-1 = Toujours" -#: models.py:208 +#: models.py:203 msgid "Next Run" msgstr "Prochaine exécution" -#: models.py:215 +#: models.py:210 msgid "Cron expression" -msgstr "Expression du Cron" +msgstr "Expression Cron" -#: models.py:224 -msgid "Name of kwarg to pass intended schedule date" -msgstr "Nom du kwarg pour passer la date d'éxecution prévue" - -#: models.py:299 +#: models.py:287 msgid "Scheduled task" msgstr "Tâche planifiée" -#: models.py:300 +#: models.py:288 msgid "Scheduled tasks" msgstr "Tâches planifiées" -#: models.py:326 +#: models.py:314 msgid "Queued task" msgstr "Tâche en file d'attente" -#: models.py:327 +#: models.py:315 msgid "Queued tasks" msgstr "Tâches en file d'attente" @@ -482,13 +490,12 @@ msgstr "Aucun cluster ne semble être en cours d'exécution." #: signals.py:22 #, python-format msgid "malformed return hook '%(hook)s' for [%(name)s]" -msgstr "hook de retour mal formé' %(hook)s 'pour [%(name)s]" +msgstr "hook de retour '%(hook)s' mal formé pour [%(name)s]" #: signals.py:30 #, python-format msgid "return hook %(hook)s failed on [%(name)s] because %(error)s" -msgstr "" -"le crochet de retour %(hook)s a échoué sur [%(name)s] parce que %(error)s" +msgstr "hook de retour %(hook)s a échoué sur [%(name)s] à cause de %(error)s" #, python-format #~ msgid "" diff --git a/django_q/locale/tr/LC_MESSAGES/django.po b/django_q/locale/tr/LC_MESSAGES/django.po index eff3bd9..24ea5fd 100644 --- a/django_q/locale/tr/LC_MESSAGES/django.po +++ b/django_q/locale/tr/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-01-15 23:35+0100\n" +"POT-Creation-Date: 2023-01-07 19:21+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Ethem Güner \n" "Language-Team: \n" @@ -22,157 +22,167 @@ msgstr "" msgid "Resubmit selected tasks to queue" msgstr "Seçili işleri kuyruğa tekrar gönder" -#: admin.py:107 models.py:293 +#: admin.py:107 models.py:281 #, fuzzy #| msgid "Success" msgid "success" msgstr "başarılı olanlar" -#: admin.py:119 models.py:295 +#: admin.py:119 models.py:283 msgid "last_run" msgstr "" -#: cluster.py:76 +#: cluster.py:80 #, python-format msgid "Q Cluster %(name)s starting." msgstr "Q Cluster %(name)s başlatılıyor." -#: cluster.py:84 +#: cluster.py:88 #, python-format msgid "Q Cluster %(name)s stopping." msgstr "Q Cluster %(name)s durduruluyor." -#: cluster.py:87 +#: cluster.py:91 #, python-format msgid "Q Cluster %(name)s has stopped." msgstr "Q Cluster %(name)s durduruldu." -#: cluster.py:94 +#: cluster.py:98 #, python-format msgid "%(name)s got signal %(signal)s" msgstr "%(name)s, %(signal)s pid'inde izleniyor/monitoring yapılıyor." -#: cluster.py:221 +#: cluster.py:225 #, python-format msgid "reincarnated monitor %(name)s after sudden death" msgstr "Monitor %(name)s ani ölüm sonrası tekrar dirildi" -#: cluster.py:227 +#: cluster.py:231 #, python-format msgid "reincarnated pusher %(name)s after sudden death" msgstr "Pusher %(name)s ani ölüm sonrası tekrar dirildi" -#: cluster.py:238 +#: cluster.py:251 +#, fuzzy, python-format +#| msgid "reincarnated worker %(name)s after timeout" +msgid "" +"reincarnated worker %(name)s after timeout while processing task " +"%(task_name)s" +msgstr "Worker %(name)s zaman aşımı sonrası tekrar dirildi" + +#: cluster.py:256 #, python-format msgid "reincarnated worker %(name)s after timeout" msgstr "Worker %(name)s zaman aşımı sonrası tekrar dirildi" -#: cluster.py:242 +#: cluster.py:261 #, python-format msgid "recycled worker %(name)s" msgstr "Worker %(name)s geri döndürüldü" -#: cluster.py:245 +#: cluster.py:264 #, python-format msgid "reincarnated worker %(name)s after death" msgstr "Worker %(name)s ani ölüm sonrası tekrar dirildi" -#: cluster.py:269 +#: cluster.py:288 #, python-format msgid "%(name)s guarding cluster %(cluster_name)s" msgstr "%(name)s, %(cluster_name)s cluster'ını koruyor" -#: cluster.py:278 +#: cluster.py:297 #, python-format msgid "Q Cluster %(cluster_name)s running." msgstr "Q Cluster %(cluster_name)s başlatılıyor." -#: cluster.py:314 +#: cluster.py:333 #, python-format msgid "%(name)s stopping cluster processes" msgstr "Cluster %(name)s işlemleri durduruluyor." -#: cluster.py:339 +#: cluster.py:358 #, python-format msgid "%(name)s waiting for the monitor." msgstr "%(name)s monitor için bekliyor." -#: cluster.py:362 -#, python-format -msgid "%(process_name)s pushing tasks at %(id)s" +#: cluster.py:384 +#, fuzzy, python-format +#| msgid "%(process_name)s pushing tasks at %(id)s" +msgid "%(name)s pushing tasks at %(id)s" msgstr "%(process_name)s, işleri %(id)s pid'ine gönderiyor." -#: cluster.py:386 +#: cluster.py:408 #, python-format msgid "queueing from %(list_key)s" msgstr "" -#: cluster.py:390 +#: cluster.py:412 #, python-format msgid "%(name)s stopped pushing tasks" msgstr "%(name)s işleri göndermeyi durdurdu" -#: cluster.py:403 +#: cluster.py:427 #, python-format msgid "%(name)s monitoring at %(id)s" msgstr "%(name)s, %(id)s pid'inde izleniyor/monitoring yapılıyor." -#: cluster.py:422 +#: cluster.py:446 #, python-format msgid "Processed '%(info_name)s' (%(task_name)s)" msgstr "[%(task_name)s] - '%(info_name)s işlendi." -#: cluster.py:428 +#: cluster.py:452 #, python-format msgid "Failed '%(info_name)s' (%(task_name)s) - %(task_result)s" msgstr "[%(task_name)s] - '%(info_name)s' - %(task_result)s başarısız oldu" -#: cluster.py:435 +#: cluster.py:459 #, python-format msgid "%(name)s stopped monitoring results" msgstr "%(name)s sonuçları göstermeyi bıraktı" -#: cluster.py:451 +#: cluster.py:475 #, python-format msgid "%(proc_name)s ready for work at %(id)s" msgstr "%(proc_name)s, %(id)s pid'inde çalışmaya hazır" -#: cluster.py:466 -#, python-format -msgid "%(proc_name)s processing '%(func_name)s' (%(task_name)s)" +#: cluster.py:495 +#, fuzzy, python-format +#| msgid "%(proc_name)s processing '%(func_name)s' (%(task_name)s)" +msgid "%(proc_name)s processing %(task_name)s '%(func_name)s'" msgstr "%(proc_name)s, '%(func_name)s' [%(task_name)s] işlerini işiyor" -#: cluster.py:507 +#: cluster.py:543 #, python-format msgid "%(proc_name)s stopped doing work" msgstr "%(proc_name)s çalışmayı bıraktı" -#: cluster.py:712 +#: cluster.py:756 #, python-format msgid "%(process_name)s failed to create a task from schedule [%(schedule)s]" msgstr "%(process_name)s programdan bir görev oluşturamadı [%(schedule)s]" -#: cluster.py:723 +#: cluster.py:767 #, fuzzy, python-format #| msgid "%(process_name)s created a task from schedule [%(schedule)s]" msgid "" "%(process_name)s created task %(task_name)s from schedule [%(schedule)s]" msgstr "%(process_name)s programdan bir görev oluşturamadı [%(schedule)s]" -#: cluster.py:769 +#: cluster.py:813 msgid "Skipping cpu affinity because psutil was not found." msgstr "Psutil bulunamadığı için cpu benzeşimi atlanıyor." -#: cluster.py:774 +#: cluster.py:818 msgid "Faking cpu affinity because it is not supported on this platform" msgstr "Bu platformda desteklenmediği için sahte cpu benzeşimi" -#: cluster.py:796 +#: cluster.py:840 #, python-format msgid "%(pid)s will use cpu %(affinity)s" msgstr "%(pid)s cpu %(affinity)s kullanacaktır" -#: conf.py:85 +#: conf.py:93 #, python-format msgid "" "SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', " @@ -182,23 +192,23 @@ msgstr "" "'group', 'name', 'func' ve None. Varsayılan değer None'dır." #. Translators: Cluster status descriptions -#: conf.py:202 +#: conf.py:210 msgid "Starting" msgstr "Başlıyor" -#: conf.py:203 +#: conf.py:211 msgid "Working" msgstr "Çalışıyor" -#: conf.py:204 +#: conf.py:212 msgid "Idle" msgstr "Boşta" -#: conf.py:205 +#: conf.py:213 msgid "Stopped" msgstr "Durdu" -#: conf.py:206 +#: conf.py:214 msgid "Stopping" msgstr "Durduruluyor" @@ -222,123 +232,119 @@ msgstr "Q Cluster'ın bellek kullanımını izler" msgid "Monitors Q Cluster activity" msgstr "Q Cluster'ın aktivitelerini izler" -#: models.py:125 +#: models.py:124 msgid "Successful task" msgstr "Başarılı iş" -#: models.py:126 +#: models.py:125 msgid "Successful tasks" msgstr "Başarılı işler" -#: models.py:141 +#: models.py:140 msgid "Failed task" msgstr "Başarısız iş" -#: models.py:142 +#: models.py:141 msgid "Failed tasks" msgstr "Başarısız işler" -#: models.py:150 models.py:234 +#: models.py:149 models.py:222 msgid "Please install croniter to enable cron expressions" msgstr "Cron expressions'ları açmak için croniter yükleyin" -#: models.py:170 +#: models.py:165 msgid "e.g. 1, 2, 'John'" msgstr "Örneğin: 1, 2, 'Melih'" -#: models.py:172 +#: models.py:167 msgid "e.g. x=1, y=2, name='John'" msgstr "Örneğin: x=1, y=2, name='Melih'" -#: models.py:186 +#: models.py:181 msgid "Once" msgstr "Bir kere" -#: models.py:187 +#: models.py:182 msgid "Minutes" msgstr "Dakika" -#: models.py:188 +#: models.py:183 msgid "Hourly" msgstr "Saatlik" -#: models.py:189 +#: models.py:184 msgid "Daily" msgstr "Günlük" -#: models.py:190 +#: models.py:185 msgid "Weekly" msgstr "Haftalık" -#: models.py:191 +#: models.py:186 #, fuzzy #| msgid "Weekly" msgid "Biweekly" msgstr "İki haftada bir" -#: models.py:192 +#: models.py:187 msgid "Monthly" msgstr "Aylık" -#: models.py:193 +#: models.py:188 #, fuzzy #| msgid "Monthly" msgid "Bimonthly" msgstr "İki ayda bir" -#: models.py:194 +#: models.py:189 msgid "Quarterly" msgstr "Bir Çeyrek (3 Ay)" -#: models.py:195 +#: models.py:190 msgid "Yearly" msgstr "Yıllık" -#: models.py:196 +#: models.py:191 msgid "Cron" msgstr "" -#: models.py:199 +#: models.py:194 msgid "Schedule Type" msgstr "Zamanlama Tipi" -#: models.py:202 +#: models.py:197 msgid "Number of minutes for the Minutes type" msgstr "Dakika tipine göre dakika sayısı" -#: models.py:205 +#: models.py:200 msgid "Repeats" msgstr "Tekrar eder" -#: models.py:205 +#: models.py:200 msgid "n = n times, -1 = forever" msgstr "n = n kere, -1 = sonsuza kadar" -#: models.py:208 +#: models.py:203 msgid "Next Run" msgstr "Bir dahaki çalışma tarihi" -#: models.py:215 +#: models.py:210 msgid "Cron expression" msgstr "" -#: models.py:224 -msgid "Name of kwarg to pass intended schedule date" -msgstr "" - -#: models.py:299 +#: models.py:287 msgid "Scheduled task" msgstr "Zamanlanmış iş" -#: models.py:300 +#: models.py:288 msgid "Scheduled tasks" msgstr "Zamanlanmış işler" -#: models.py:326 +#: models.py:314 msgid "Queued task" msgstr "Sıraya alınmış iş" -#: models.py:327 +#: models.py:315 msgid "Queued tasks" msgstr "Sıraya alınmış işler" diff --git a/docs/install.rst b/docs/install.rst index e862e68..b630b45 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -55,6 +55,10 @@ Optional $ pip install psutil +- `setproctitle `__ python module to customize the process title by Daniele Varrazzo', is an optional requirement used to set informative process titles:: + + $ pip install setproctitle + - `Hiredis `__ parser. This C library maintained by the core Redis team is faster than the standard PythonParser during high loads:: $ pip install hiredis diff --git a/poetry.lock b/poetry.lock index 8dade84..023ae7f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,3 +1,5 @@ +# This file is automatically @generated by Poetry and should not be changed by hand. + [[package]] name = "alabaster" version = "0.7.12" @@ -5,6 +7,10 @@ description = "A configurable sidebar-enabled Sphinx theme" category = "dev" optional = false python-versions = "*" +files = [ + {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"}, + {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"}, +] [[package]] name = "ansicon" @@ -13,6 +19,10 @@ description = "Python wrapper for loading Jason Hood's ANSICON" category = "main" optional = true python-versions = "*" +files = [ + {file = "ansicon-1.89.0-py2.py3-none-any.whl", hash = "sha256:f1def52d17f65c2c9682cf8370c03f541f410c1752d6a14029f97318e4b9dfec"}, + {file = "ansicon-1.89.0.tar.gz", hash = "sha256:e4d039def5768a47e4afec8e89e83ec3ae5a26bf00ad851f914d1240b444d2b1"}, +] [[package]] name = "asgiref" @@ -21,6 +31,10 @@ description = "ASGI specs, helper code, and adapters" category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "asgiref-3.5.2-py3-none-any.whl", hash = "sha256:1d2880b792ae8757289136f1db2b7b99100ce959b2aa57fd69dab783d05afac4"}, + {file = "asgiref-3.5.2.tar.gz", hash = "sha256:4a29362a6acebe09bf1d6640db38c1dc3d9217c68e6f9f6204d72667fc19a424"}, +] [package.extras] tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] @@ -32,6 +46,10 @@ description = "Timeout context manager for asyncio programs" category = "main" optional = true python-versions = ">=3.6" +files = [ + {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"}, + {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, +] [[package]] name = "attrs" @@ -40,6 +58,10 @@ description = "Classes Without Boilerplate" category = "dev" optional = false python-versions = ">=3.5" +files = [ + {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, + {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, +] [package.extras] dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"] @@ -54,6 +76,10 @@ description = "Internationalization utilities" category = "dev" optional = false python-versions = ">=3.6" +files = [ + {file = "Babel-2.10.3-py3-none-any.whl", hash = "sha256:ff56f4892c1c4bf0d814575ea23471c230d544203c7748e8c68f0089478d48eb"}, + {file = "Babel-2.10.3.tar.gz", hash = "sha256:7614553711ee97490f732126dc077f8d0ae084ebc6a96e23db1482afabdb2c51"}, +] [package.dependencies] pytz = ">=2015.7" @@ -65,930 +91,7 @@ description = "Backport of the standard library zoneinfo module" category = "main" optional = false python-versions = ">=3.6" - -[package.extras] -tzdata = ["tzdata"] - -[[package]] -name = "black" -version = "22.10.0" -description = "The uncompromising code formatter." -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -pathspec = ">=0.9.0" -platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} -typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - -[[package]] -name = "blessed" -version = "1.19.1" -description = "Easy, practical library for making terminal apps, by providing an elegant, well-documented interface to Colors, Keyboard input, and screen Positioning capabilities." -category = "main" -optional = true -python-versions = ">=2.7" - -[package.dependencies] -jinxed = {version = ">=1.1.0", markers = "platform_system == \"Windows\""} -six = ">=1.9.0" -wcwidth = ">=0.1.4" - -[[package]] -name = "boto3" -version = "1.24.95" -description = "The AWS SDK for Python" -category = "main" -optional = true -python-versions = ">= 3.7" - -[package.dependencies] -botocore = ">=1.27.95,<1.28.0" -jmespath = ">=0.7.1,<2.0.0" -s3transfer = ">=0.6.0,<0.7.0" - -[package.extras] -crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] - -[[package]] -name = "botocore" -version = "1.27.95" -description = "Low-level, data-driven core of boto 3." -category = "main" -optional = true -python-versions = ">= 3.7" - -[package.dependencies] -jmespath = ">=0.7.1,<2.0.0" -python-dateutil = ">=2.1,<3.0.0" -urllib3 = ">=1.25.4,<1.27" - -[package.extras] -crt = ["awscrt (==0.14.0)"] - -[[package]] -name = "certifi" -version = "2022.9.24" -description = "Python package for providing Mozilla's CA Bundle." -category = "main" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "charset-normalizer" -version = "2.1.1" -description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "main" -optional = false -python-versions = ">=3.6.0" - -[package.extras] -unicode-backport = ["unicodedata2"] - -[[package]] -name = "click" -version = "8.1.3" -description = "Composable command line interface toolkit" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[[package]] -name = "colorama" -version = "0.4.5" -description = "Cross-platform colored terminal text." -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - -[[package]] -name = "coverage" -version = "6.5.0" -description = "Code coverage measurement for Python" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} - -[package.extras] -toml = ["tomli"] - -[[package]] -name = "croniter" -version = "1.3.7" -description = "croniter provides iteration for datetime object with cron like format" -category = "main" -optional = true -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - -[package.dependencies] -python-dateutil = "*" - -[[package]] -name = "deprecated" -version = "1.2.13" -description = "Python @deprecated decorator to deprecate old python classes, functions or methods." -category = "main" -optional = true -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - -[package.dependencies] -wrapt = ">=1.10,<2" - -[package.extras] -dev = ["PyTest", "PyTest (<5)", "PyTest-Cov", "PyTest-Cov (<2.6)", "bump2version (<1)", "configparser (<5)", "importlib-metadata (<3)", "importlib-resources (<4)", "sphinx (<2)", "sphinxcontrib-websupport (<2)", "tox", "zipp (<2)"] - -[[package]] -name = "django" -version = "4.1.2" -description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." -category = "main" -optional = false -python-versions = ">=3.8" - -[package.dependencies] -asgiref = ">=3.5.2,<4" -"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} -sqlparse = ">=0.2.2" -tzdata = {version = "*", markers = "sys_platform == \"win32\""} - -[package.extras] -argon2 = ["argon2-cffi (>=19.1.0)"] -bcrypt = ["bcrypt"] - -[[package]] -name = "django-picklefield" -version = "3.1" -description = "Pickled object field for Django" -category = "main" -optional = false -python-versions = ">=3" - -[package.dependencies] -Django = ">=3.2" - -[package.extras] -tests = ["tox"] - -[[package]] -name = "django-q-rollbar" -version = "0.1.3" -description = "A Rollbar support plugin for Django Q" -category = "main" -optional = true -python-versions = "^3.6" - -[package.dependencies] -rollbar = ">=0.14.0,<0.15.0" - -[[package]] -name = "django-q-sentry" -version = "0.1.6" -description = "A Sentry support plugin for Django Q" -category = "main" -optional = true -python-versions = "*" - -[package.dependencies] -sentry-sdk = ">=1.5.5" - -[[package]] -name = "django-redis" -version = "5.2.0" -description = "Full featured redis cache backend for Django." -category = "main" -optional = true -python-versions = ">=3.6" - -[package.dependencies] -Django = ">=2.2" -redis = ">=3,<4.0.0 || >4.0.0,<4.0.1 || >4.0.1" - -[package.extras] -hiredis = ["redis[hiredis] (>=3,!=4.0.0,!=4.0.1)"] - -[[package]] -name = "dnspython" -version = "2.2.1" -description = "DNS toolkit" -category = "main" -optional = true -python-versions = ">=3.6,<4.0" - -[package.extras] -curio = ["curio (>=1.2,<2.0)", "sniffio (>=1.1,<2.0)"] -dnssec = ["cryptography (>=2.6,<37.0)"] -doh = ["h2 (>=4.1.0)", "httpx (>=0.21.1)", "requests (>=2.23.0,<3.0.0)", "requests-toolbelt (>=0.9.1,<0.10.0)"] -idna = ["idna (>=2.1,<4.0)"] -trio = ["trio (>=0.14,<0.20)"] -wmi = ["wmi (>=1.5.1,<2.0.0)"] - -[[package]] -name = "docopt" -version = "0.6.2" -description = "Pythonic argument parser, that will make you smile" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "docutils" -version = "0.17.1" -description = "Docutils -- Python Documentation Utilities" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - -[[package]] -name = "hiredis" -version = "2.0.0" -description = "Python wrapper for hiredis" -category = "main" -optional = true -python-versions = ">=3.6" - -[[package]] -name = "idna" -version = "3.4" -description = "Internationalized Domain Names in Applications (IDNA)" -category = "main" -optional = false -python-versions = ">=3.5" - -[[package]] -name = "imagesize" -version = "1.4.1" -description = "Getting image size from png/jpeg/jpeg2000/gif file" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - -[[package]] -name = "importlib-metadata" -version = "5.0.0" -description = "Read metadata from Python packages" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -zipp = ">=0.5" - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] -perf = ["ipython"] -testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] - -[[package]] -name = "iniconfig" -version = "1.1.1" -description = "iniconfig: brain-dead simple config-ini parsing" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "iron-core" -version = "1.2.1" -description = "Universal classes and methods for Iron.io API wrappers to build on." -category = "main" -optional = true -python-versions = "*" - -[package.dependencies] -python-dateutil = "*" -requests = ">=1.1.0" - -[[package]] -name = "iron-mq" -version = "0.9" -description = "Client library for IronMQ, a message queue in the cloud" -category = "main" -optional = true -python-versions = "*" - -[package.dependencies] -iron_core = "*" - -[[package]] -name = "isort" -version = "5.10.1" -description = "A Python utility / library to sort Python imports." -category = "dev" -optional = false -python-versions = ">=3.6.1,<4.0" - -[package.dependencies] -pip-api = {version = "*", optional = true, markers = "extra == \"requirements_deprecated_finder\""} -pipreqs = {version = "*", optional = true, markers = "extra == \"pipfile_deprecated_finder\" or extra == \"requirements_deprecated_finder\""} - -[package.extras] -colors = ["colorama (>=0.4.3,<0.5.0)"] -pipfile-deprecated-finder = ["pipreqs", "requirementslib"] -plugins = ["setuptools"] -requirements-deprecated-finder = ["pip-api", "pipreqs"] - -[[package]] -name = "jinja2" -version = "3.1.2" -description = "A very fast and expressive template engine." -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -MarkupSafe = ">=2.0" - -[package.extras] -i18n = ["Babel (>=2.7)"] - -[[package]] -name = "jinxed" -version = "1.2.0" -description = "Jinxed Terminal Library" -category = "main" -optional = true -python-versions = "*" - -[package.dependencies] -ansicon = {version = "*", markers = "platform_system == \"Windows\""} - -[[package]] -name = "jmespath" -version = "1.0.1" -description = "JSON Matching Expressions" -category = "main" -optional = true -python-versions = ">=3.7" - -[[package]] -name = "markupsafe" -version = "2.1.1" -description = "Safely add untrusted strings to HTML/XML markup." -category = "dev" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "mypy-extensions" -version = "0.4.3" -description = "Experimental type system extensions for programs checked with the mypy typechecker." -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "packaging" -version = "21.3" -description = "Core utilities for Python packages" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" - -[[package]] -name = "pathspec" -version = "0.10.1" -description = "Utility library for gitignore style pattern matching of file paths." -category = "dev" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "pip" -version = "22.3" -description = "The PyPA recommended tool for installing Python packages." -category = "dev" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "pip-api" -version = "0.0.30" -description = "An unofficial, importable pip API" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -pip = "*" - -[[package]] -name = "pipreqs" -version = "0.4.11" -description = "Pip requirements.txt generator based on imports in project" -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -docopt = "*" -yarg = "*" - -[[package]] -name = "platformdirs" -version = "2.5.2" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.extras] -docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx (>=4)", "sphinx-autodoc-typehints (>=1.12)"] -test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] - -[[package]] -name = "pluggy" -version = "1.0.0" -description = "plugin and hook calling mechanisms for python" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.extras] -dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] - -[[package]] -name = "psutil" -version = "5.9.3" -description = "Cross-platform lib for process and system monitoring in Python." -category = "main" -optional = true -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - -[package.extras] -test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] - -[[package]] -name = "py" -version = "1.11.0" -description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - -[[package]] -name = "pygments" -version = "2.13.0" -description = "Pygments is a syntax highlighting package written in Python." -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.extras] -plugins = ["importlib-metadata"] - -[[package]] -name = "pymongo" -version = "4.3.2" -description = "Python driver for MongoDB " -category = "main" -optional = true -python-versions = ">=3.7" - -[package.dependencies] -dnspython = ">=1.16.0,<3.0.0" - -[package.extras] -aws = ["pymongo-auth-aws (<2.0.0)"] -encryption = ["pymongocrypt (>=1.3.0,<2.0.0)"] -gssapi = ["pykerberos"] -ocsp = ["certifi", "pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)"] -snappy = ["python-snappy"] -zstd = ["zstandard"] - -[[package]] -name = "pyparsing" -version = "3.0.9" -description = "pyparsing module - Classes and methods to define and execute parsing grammars" -category = "main" -optional = false -python-versions = ">=3.6.8" - -[package.extras] -diagrams = ["jinja2", "railroad-diagrams"] - -[[package]] -name = "pytest" -version = "7.1.3" -description = "pytest: simple powerful testing with Python" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -attrs = ">=19.2.0" -colorama = {version = "*", markers = "sys_platform == \"win32\""} -iniconfig = "*" -packaging = "*" -pluggy = ">=0.12,<2.0" -py = ">=1.8.2" -tomli = ">=1.0.0" - -[package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] - -[[package]] -name = "pytest-cov" -version = "4.0.0" -description = "Pytest plugin for measuring coverage." -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -coverage = {version = ">=5.2.1", extras = ["toml"]} -pytest = ">=4.6" - -[package.extras] -testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] - -[[package]] -name = "pytest-django" -version = "4.5.2" -description = "A Django plugin for pytest." -category = "dev" -optional = false -python-versions = ">=3.5" - -[package.dependencies] -pytest = ">=5.4.0" - -[package.extras] -docs = ["sphinx", "sphinx-rtd-theme"] -testing = ["Django", "django-configurations (>=2.0)"] - -[[package]] -name = "python-dateutil" -version = "2.8.2" -description = "Extensions to the standard Python datetime module" -category = "main" -optional = true -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" - -[package.dependencies] -six = ">=1.5" - -[[package]] -name = "pytz" -version = "2022.5" -description = "World timezone definitions, modern and historical" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "redis" -version = "4.3.4" -description = "Python client for Redis database and key-value store" -category = "main" -optional = true -python-versions = ">=3.6" - -[package.dependencies] -async-timeout = ">=4.0.2" -deprecated = ">=1.2.3" -packaging = ">=20.4" - -[package.extras] -hiredis = ["hiredis (>=1.0.0)"] -ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"] - -[[package]] -name = "requests" -version = "2.28.1" -description = "Python HTTP for Humans." -category = "main" -optional = false -python-versions = ">=3.7, <4" - -[package.dependencies] -certifi = ">=2017.4.17" -charset-normalizer = ">=2,<3" -idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<1.27" - -[package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] - -[[package]] -name = "rollbar" -version = "0.14.7" -description = "Easy and powerful exception tracking with Rollbar. Send messages and exceptions with arbitrary context, get back aggregates, and debug production issues quickly." -category = "main" -optional = true -python-versions = "*" - -[package.dependencies] -requests = ">=0.12.1" -six = ">=1.9.0" - -[[package]] -name = "s3transfer" -version = "0.6.0" -description = "An Amazon S3 Transfer Manager" -category = "main" -optional = true -python-versions = ">= 3.7" - -[package.dependencies] -botocore = ">=1.12.36,<2.0a.0" - -[package.extras] -crt = ["botocore[crt] (>=1.20.29,<2.0a.0)"] - -[[package]] -name = "sentry-sdk" -version = "1.10.0" -description = "Python client for Sentry (https://sentry.io)" -category = "main" -optional = true -python-versions = "*" - -[package.dependencies] -certifi = "*" -urllib3 = {version = ">=1.26.11", markers = "python_version >= \"3.6\""} - -[package.extras] -aiohttp = ["aiohttp (>=3.5)"] -beam = ["apache-beam (>=2.12)"] -bottle = ["bottle (>=0.12.13)"] -celery = ["celery (>=3)"] -chalice = ["chalice (>=1.16.0)"] -django = ["django (>=1.8)"] -falcon = ["falcon (>=1.4)"] -fastapi = ["fastapi (>=0.79.0)"] -flask = ["blinker (>=1.1)", "flask (>=0.11)"] -httpx = ["httpx (>=0.16.0)"] -pure-eval = ["asttokens", "executing", "pure-eval"] -pyspark = ["pyspark (>=2.4.4)"] -quart = ["blinker (>=1.1)", "quart (>=0.16.1)"] -rq = ["rq (>=0.6)"] -sanic = ["sanic (>=0.8)"] -sqlalchemy = ["sqlalchemy (>=1.2)"] -starlette = ["starlette (>=0.19.1)"] -tornado = ["tornado (>=5)"] - -[[package]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -category = "main" -optional = true -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" - -[[package]] -name = "snowballstemmer" -version = "2.2.0" -description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "sphinx" -version = "4.5.0" -description = "Python documentation generator" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -alabaster = ">=0.7,<0.8" -babel = ">=1.3" -colorama = {version = ">=0.3.5", markers = "sys_platform == \"win32\""} -docutils = ">=0.14,<0.18" -imagesize = "*" -importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} -Jinja2 = ">=2.3" -packaging = "*" -Pygments = ">=2.0" -requests = ">=2.5.0" -snowballstemmer = ">=1.1" -sphinxcontrib-applehelp = "*" -sphinxcontrib-devhelp = "*" -sphinxcontrib-htmlhelp = ">=2.0.0" -sphinxcontrib-jsmath = "*" -sphinxcontrib-qthelp = "*" -sphinxcontrib-serializinghtml = ">=1.1.5" - -[package.extras] -docs = ["sphinxcontrib-websupport"] -lint = ["docutils-stubs", "flake8 (>=3.5.0)", "isort", "mypy (>=0.931)", "types-requests", "types-typed-ast"] -test = ["cython", "html5lib", "pytest", "pytest-cov", "typed-ast"] - -[[package]] -name = "sphinxcontrib-applehelp" -version = "1.0.2" -description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books" -category = "dev" -optional = false -python-versions = ">=3.5" - -[package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] -test = ["pytest"] - -[[package]] -name = "sphinxcontrib-devhelp" -version = "1.0.2" -description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." -category = "dev" -optional = false -python-versions = ">=3.5" - -[package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] -test = ["pytest"] - -[[package]] -name = "sphinxcontrib-htmlhelp" -version = "2.0.0" -description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] -test = ["html5lib", "pytest"] - -[[package]] -name = "sphinxcontrib-jsmath" -version = "1.0.1" -description = "A sphinx extension which renders display math in HTML via JavaScript" -category = "dev" -optional = false -python-versions = ">=3.5" - -[package.extras] -test = ["flake8", "mypy", "pytest"] - -[[package]] -name = "sphinxcontrib-qthelp" -version = "1.0.3" -description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." -category = "dev" -optional = false -python-versions = ">=3.5" - -[package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] -test = ["pytest"] - -[[package]] -name = "sphinxcontrib-serializinghtml" -version = "1.1.5" -description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." -category = "dev" -optional = false -python-versions = ">=3.5" - -[package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] -test = ["pytest"] - -[[package]] -name = "sqlparse" -version = "0.4.3" -description = "A non-validating SQL parser." -category = "main" -optional = false -python-versions = ">=3.5" - -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -category = "dev" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "typing-extensions" -version = "4.4.0" -description = "Backported and Experimental Type Hints for Python 3.7+" -category = "dev" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "tzdata" -version = "2022.5" -description = "Provider of IANA time zone data" -category = "main" -optional = false -python-versions = ">=2" - -[[package]] -name = "urllib3" -version = "1.26.12" -description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4" - -[package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] - -[[package]] -name = "wcwidth" -version = "0.2.5" -description = "Measures the displayed width of unicode strings in a terminal" -category = "main" -optional = true -python-versions = "*" - -[[package]] -name = "wrapt" -version = "1.14.1" -description = "Module for decorators, wrappers and monkey patching." -category = "main" -optional = true -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" - -[[package]] -name = "yarg" -version = "0.1.9" -description = "A semi hard Cornish cheese, also queries PyPI (PyPI client)" -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -requests = "*" - -[[package]] -name = "zipp" -version = "3.9.0" -description = "Backport of pathlib-compatible object wrapper for zip files" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] -testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] - -[extras] -build-backend = [] -requires = [] -rollbar = ["django-q-rollbar"] -sentry = ["django-q-sentry"] -testing = ["django-redis", "croniter", "hiredis", "psutil", "iron-mq", "boto3", "pymongo", "blessed", "redis"] - -[metadata] -lock-version = "1.1" -python-versions = ">=3.8.14, <4" -content-hash = "a5007f22e20151981df5e8e478ceea4b7c3d1932b0c1cef14b9cec39f04bcc84" - -[metadata.files] -alabaster = [ - {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"}, - {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"}, -] -ansicon = [ - {file = "ansicon-1.89.0-py2.py3-none-any.whl", hash = "sha256:f1def52d17f65c2c9682cf8370c03f541f410c1752d6a14029f97318e4b9dfec"}, - {file = "ansicon-1.89.0.tar.gz", hash = "sha256:e4d039def5768a47e4afec8e89e83ec3ae5a26bf00ad851f914d1240b444d2b1"}, -] -asgiref = [ - {file = "asgiref-3.5.2-py3-none-any.whl", hash = "sha256:1d2880b792ae8757289136f1db2b7b99100ce959b2aa57fd69dab783d05afac4"}, - {file = "asgiref-3.5.2.tar.gz", hash = "sha256:4a29362a6acebe09bf1d6640db38c1dc3d9217c68e6f9f6204d72667fc19a424"}, -] -async-timeout = [ - {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"}, - {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, -] -attrs = [ - {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, - {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, -] -babel = [ - {file = "Babel-2.10.3-py3-none-any.whl", hash = "sha256:ff56f4892c1c4bf0d814575ea23471c230d544203c7748e8c68f0089478d48eb"}, - {file = "Babel-2.10.3.tar.gz", hash = "sha256:7614553711ee97490f732126dc077f8d0ae084ebc6a96e23db1482afabdb2c51"}, -] -backports-zoneinfo = [ +files = [ {file = "backports.zoneinfo-0.2.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc"}, {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722"}, {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1c5742112073a563c81f786e77514969acb58649bcdf6cdf0b4ed31a348d4546"}, @@ -1006,7 +109,18 @@ backports-zoneinfo = [ {file = "backports.zoneinfo-0.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:4a0f800587060bf8880f954dbef70de6c11bbe59c673c3d818921f042f9954a6"}, {file = "backports.zoneinfo-0.2.1.tar.gz", hash = "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2"}, ] -black = [ + +[package.extras] +tzdata = ["tzdata"] + +[[package]] +name = "black" +version = "22.10.0" +description = "The uncompromising code formatter." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ {file = "black-22.10.0-1fixedarch-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:5cc42ca67989e9c3cf859e84c2bf014f6633db63d1cbdf8fdb666dcd9e77e3fa"}, {file = "black-22.10.0-1fixedarch-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:5d8f74030e67087b219b032aa33a919fae8806d49c867846bfacde57f43972ef"}, {file = "black-22.10.0-1fixedarch-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:197df8509263b0b8614e1df1756b1dd41be6738eed2ba9e9769f3880c2b9d7b6"}, @@ -1029,35 +143,140 @@ black = [ {file = "black-22.10.0-py3-none-any.whl", hash = "sha256:c957b2b4ea88587b46cf49d1dc17681c1e672864fd7af32fc1e9664d572b3458"}, {file = "black-22.10.0.tar.gz", hash = "sha256:f513588da599943e0cde4e32cc9879e825d58720d6557062d1098c5ad80080e1"}, ] -blessed = [ + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +pathspec = ">=0.9.0" +platformdirs = ">=2" +tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} +typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "blessed" +version = "1.19.1" +description = "Easy, practical library for making terminal apps, by providing an elegant, well-documented interface to Colors, Keyboard input, and screen Positioning capabilities." +category = "main" +optional = true +python-versions = ">=2.7" +files = [ {file = "blessed-1.19.1-py2.py3-none-any.whl", hash = "sha256:63b8554ae2e0e7f43749b6715c734cc8f3883010a809bf16790102563e6cf25b"}, {file = "blessed-1.19.1.tar.gz", hash = "sha256:9a0d099695bf621d4680dd6c73f6ad547f6a3442fbdbe80c4b1daa1edbc492fc"}, ] -boto3 = [ + +[package.dependencies] +jinxed = {version = ">=1.1.0", markers = "platform_system == \"Windows\""} +six = ">=1.9.0" +wcwidth = ">=0.1.4" + +[[package]] +name = "boto3" +version = "1.24.95" +description = "The AWS SDK for Python" +category = "main" +optional = true +python-versions = ">= 3.7" +files = [ {file = "boto3-1.24.95-py3-none-any.whl", hash = "sha256:05818ed61af104f28f039592c5c54d802a0398b1f158c2d485ec86352b48033f"}, {file = "boto3-1.24.95.tar.gz", hash = "sha256:285d29042c1684f8fc68492ddf20180d28b94aac1f19dd7161bcad3067c01314"}, ] -botocore = [ + +[package.dependencies] +botocore = ">=1.27.95,<1.28.0" +jmespath = ">=0.7.1,<2.0.0" +s3transfer = ">=0.6.0,<0.7.0" + +[package.extras] +crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] + +[[package]] +name = "botocore" +version = "1.27.95" +description = "Low-level, data-driven core of boto 3." +category = "main" +optional = true +python-versions = ">= 3.7" +files = [ {file = "botocore-1.27.95-py3-none-any.whl", hash = "sha256:04ff12a8d1d0687a1f1c2dfad5b6fc9f5a81de4b639cf9c9e41fee9449680fd4"}, {file = "botocore-1.27.95.tar.gz", hash = "sha256:0b90945aa7080179a0c4941a3809ce4df30792931e16b9b6ef3c739c4f2b7a59"}, ] -certifi = [ + +[package.dependencies] +jmespath = ">=0.7.1,<2.0.0" +python-dateutil = ">=2.1,<3.0.0" +urllib3 = ">=1.25.4,<1.27" + +[package.extras] +crt = ["awscrt (==0.14.0)"] + +[[package]] +name = "certifi" +version = "2022.9.24" +description = "Python package for providing Mozilla's CA Bundle." +category = "main" +optional = false +python-versions = ">=3.6" +files = [ {file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"}, {file = "certifi-2022.9.24.tar.gz", hash = "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14"}, ] -charset-normalizer = [ + +[[package]] +name = "charset-normalizer" +version = "2.1.1" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "main" +optional = false +python-versions = ">=3.6.0" +files = [ {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, ] -click = [ + +[package.extras] +unicode-backport = ["unicodedata2"] + +[[package]] +name = "click" +version = "8.1.3" +description = "Composable command line interface toolkit" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, ] -colorama = [ + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.5" +description = "Cross-platform colored terminal text." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, ] -coverage = [ + +[[package]] +name = "coverage" +version = "6.5.0" +description = "Code coverage measurement for Python" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ {file = "coverage-6.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef8674b0ee8cc11e2d574e3e2998aea5df5ab242e012286824ea3c6970580e53"}, {file = "coverage-6.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:784f53ebc9f3fd0e2a3f6a78b2be1bd1f5575d7863e10c6e12504f240fd06660"}, {file = "coverage-6.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4a5be1748d538a710f87542f22c2cad22f80545a847ad91ce45e77417293eb4"}, @@ -1109,45 +328,185 @@ coverage = [ {file = "coverage-6.5.0-pp36.pp37.pp38-none-any.whl", hash = "sha256:1431986dac3923c5945271f169f59c45b8802a114c8f548d611f2015133df77a"}, {file = "coverage-6.5.0.tar.gz", hash = "sha256:f642e90754ee3e06b0e7e51bce3379590e76b7f76b708e1a71ff043f87025c84"}, ] -croniter = [ + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli"] + +[[package]] +name = "croniter" +version = "1.3.7" +description = "croniter provides iteration for datetime object with cron like format" +category = "main" +optional = true +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ {file = "croniter-1.3.7-py2.py3-none-any.whl", hash = "sha256:12369c67e231c8ce5f98958d76ea6e8cb5b157fda4da7429d245a931e4ed411e"}, {file = "croniter-1.3.7.tar.gz", hash = "sha256:72ef78d0f8337eb35393b8893ebfbfbeb340f2d2ae47e0d2d78130e34b0dd8b9"}, ] -deprecated = [ + +[package.dependencies] +python-dateutil = "*" + +[[package]] +name = "deprecated" +version = "1.2.13" +description = "Python @deprecated decorator to deprecate old python classes, functions or methods." +category = "main" +optional = true +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ {file = "Deprecated-1.2.13-py2.py3-none-any.whl", hash = "sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d"}, {file = "Deprecated-1.2.13.tar.gz", hash = "sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d"}, ] -django = [ + +[package.dependencies] +wrapt = ">=1.10,<2" + +[package.extras] +dev = ["PyTest", "PyTest (<5)", "PyTest-Cov", "PyTest-Cov (<2.6)", "bump2version (<1)", "configparser (<5)", "importlib-metadata (<3)", "importlib-resources (<4)", "sphinx (<2)", "sphinxcontrib-websupport (<2)", "tox", "zipp (<2)"] + +[[package]] +name = "django" +version = "4.1.2" +description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." +category = "main" +optional = false +python-versions = ">=3.8" +files = [ {file = "Django-4.1.2-py3-none-any.whl", hash = "sha256:26dc24f99c8956374a054bcbf58aab8dc0cad2e6ac82b0fe036b752c00eee793"}, {file = "Django-4.1.2.tar.gz", hash = "sha256:b8d843714810ab88d59344507d4447be8b2cf12a49031363b6eed9f1b9b2280f"}, ] -django-picklefield = [ + +[package.dependencies] +asgiref = ">=3.5.2,<4" +"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} +sqlparse = ">=0.2.2" +tzdata = {version = "*", markers = "sys_platform == \"win32\""} + +[package.extras] +argon2 = ["argon2-cffi (>=19.1.0)"] +bcrypt = ["bcrypt"] + +[[package]] +name = "django-picklefield" +version = "3.1" +description = "Pickled object field for Django" +category = "main" +optional = false +python-versions = ">=3" +files = [ {file = "django-picklefield-3.1.tar.gz", hash = "sha256:c786cbeda78d6def2b43bff4840d19787809c8909f7ad683961703060398d356"}, {file = "django_picklefield-3.1-py3-none-any.whl", hash = "sha256:d77c504df7311e8ec14e8b779f10ca6fec74de6c7f8e2c136e1ef60cf955125d"}, ] -django-q-rollbar = [ + +[package.dependencies] +Django = ">=3.2" + +[package.extras] +tests = ["tox"] + +[[package]] +name = "django-q-rollbar" +version = "0.1.3" +description = "A Rollbar support plugin for Django Q" +category = "main" +optional = true +python-versions = "^3.6" +files = [ {file = "django-q-rollbar-0.1.3.tar.gz", hash = "sha256:a4de6da294507e6cbde77a015ece429f3602ea1d8df473ef2d63e44d2041ee4b"}, ] -django-q-sentry = [ + +[package.dependencies] +rollbar = ">=0.14.0,<0.15.0" + +[[package]] +name = "django-q-sentry" +version = "0.1.6" +description = "A Sentry support plugin for Django Q" +category = "main" +optional = true +python-versions = "*" +files = [ {file = "django-q-sentry-0.1.6.linux-x86_64.tar.gz", hash = "sha256:bdbd9c7a48d543c2d74ae9a4c9004dfc0965cb11bc145c6cf4de3429be1b58ae"}, {file = "django_q_sentry-0.1.6-py3-none-any.whl", hash = "sha256:9b8b4d7fad253a7d9a47f2c2ab0d9dea83078b7ef45c8849dbb1e4176ef8d050"}, ] -django-redis = [ + +[package.dependencies] +sentry-sdk = ">=1.5.5" + +[[package]] +name = "django-redis" +version = "5.2.0" +description = "Full featured redis cache backend for Django." +category = "main" +optional = true +python-versions = ">=3.6" +files = [ {file = "django-redis-5.2.0.tar.gz", hash = "sha256:8a99e5582c79f894168f5865c52bd921213253b7fd64d16733ae4591564465de"}, {file = "django_redis-5.2.0-py3-none-any.whl", hash = "sha256:1d037dc02b11ad7aa11f655d26dac3fb1af32630f61ef4428860a2e29ff92026"}, ] -dnspython = [ + +[package.dependencies] +Django = ">=2.2" +redis = ">=3,<4.0.0 || >4.0.0,<4.0.1 || >4.0.1" + +[package.extras] +hiredis = ["redis[hiredis] (>=3,!=4.0.0,!=4.0.1)"] + +[[package]] +name = "dnspython" +version = "2.2.1" +description = "DNS toolkit" +category = "main" +optional = true +python-versions = ">=3.6,<4.0" +files = [ {file = "dnspython-2.2.1-py3-none-any.whl", hash = "sha256:a851e51367fb93e9e1361732c1d60dab63eff98712e503ea7d92e6eccb109b4f"}, {file = "dnspython-2.2.1.tar.gz", hash = "sha256:0f7569a4a6ff151958b64304071d370daa3243d15941a7beedf0c9fe5105603e"}, ] -docopt = [ + +[package.extras] +curio = ["curio (>=1.2,<2.0)", "sniffio (>=1.1,<2.0)"] +dnssec = ["cryptography (>=2.6,<37.0)"] +doh = ["h2 (>=4.1.0)", "httpx (>=0.21.1)", "requests (>=2.23.0,<3.0.0)", "requests-toolbelt (>=0.9.1,<0.10.0)"] +idna = ["idna (>=2.1,<4.0)"] +trio = ["trio (>=0.14,<0.20)"] +wmi = ["wmi (>=1.5.1,<2.0.0)"] + +[[package]] +name = "docopt" +version = "0.6.2" +description = "Pythonic argument parser, that will make you smile" +category = "dev" +optional = false +python-versions = "*" +files = [ {file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"}, ] -docutils = [ + +[[package]] +name = "docutils" +version = "0.17.1" +description = "Docutils -- Python Documentation Utilities" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ {file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"}, {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"}, ] -hiredis = [ + +[[package]] +name = "hiredis" +version = "2.0.0" +description = "Python wrapper for hiredis" +category = "main" +optional = true +python-versions = ">=3.6" +files = [ {file = "hiredis-2.0.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b4c8b0bc5841e578d5fb32a16e0c305359b987b850a06964bd5a62739d688048"}, {file = "hiredis-2.0.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0adea425b764a08270820531ec2218d0508f8ae15a448568109ffcae050fee26"}, {file = "hiredis-2.0.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:3d55e36715ff06cdc0ab62f9591607c4324297b6b6ce5b58cb9928b3defe30ea"}, @@ -1190,46 +549,168 @@ hiredis = [ {file = "hiredis-2.0.0-pp37-pypy37_pp73-win32.whl", hash = "sha256:f52010e0a44e3d8530437e7da38d11fb822acfb0d5b12e9cd5ba655509937ca0"}, {file = "hiredis-2.0.0.tar.gz", hash = "sha256:81d6d8e39695f2c37954d1011c0480ef7cf444d4e3ae24bc5e89ee5de360139a"}, ] -idna = [ + +[[package]] +name = "idna" +version = "3.4" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" +optional = false +python-versions = ">=3.5" +files = [ {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, ] -imagesize = [ + +[[package]] +name = "imagesize" +version = "1.4.1" +description = "Getting image size from png/jpeg/jpeg2000/gif file" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, ] -importlib-metadata = [ + +[[package]] +name = "importlib-metadata" +version = "5.0.0" +description = "Read metadata from Python packages" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ {file = "importlib_metadata-5.0.0-py3-none-any.whl", hash = "sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43"}, {file = "importlib_metadata-5.0.0.tar.gz", hash = "sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab"}, ] -iniconfig = [ + +[package.dependencies] +zipp = ">=0.5" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] +perf = ["ipython"] +testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] + +[[package]] +name = "iniconfig" +version = "1.1.1" +description = "iniconfig: brain-dead simple config-ini parsing" +category = "dev" +optional = false +python-versions = "*" +files = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] -iron-core = [ + +[[package]] +name = "iron-core" +version = "1.2.1" +description = "Universal classes and methods for Iron.io API wrappers to build on." +category = "main" +optional = true +python-versions = "*" +files = [ {file = "iron-core-1.2.1.tar.gz", hash = "sha256:b7190b86afbe5470da8389fbb412c0fa0529c87f85261736a87e5983ab6f1b95"}, {file = "iron_core-1.2.1-py3-none-any.whl", hash = "sha256:fd5ed3f9b441b9256bae1f829ae6f1da73fae62872aef395336f7d0ac2f041f7"}, ] -iron-mq = [ + +[package.dependencies] +python-dateutil = "*" +requests = ">=1.1.0" + +[[package]] +name = "iron-mq" +version = "0.9" +description = "Client library for IronMQ, a message queue in the cloud" +category = "main" +optional = true +python-versions = "*" +files = [ {file = "iron-mq-0.9.tar.gz", hash = "sha256:c90441d872d9c08968343810a2ad1cca1664d80fd2ad3a3a2dbec57b7b38ecfa"}, ] -isort = [ + +[package.dependencies] +iron_core = "*" + +[[package]] +name = "isort" +version = "5.10.1" +description = "A Python utility / library to sort Python imports." +category = "dev" +optional = false +python-versions = ">=3.6.1,<4.0" +files = [ {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, ] -jinja2 = [ + +[package.dependencies] +pip-api = {version = "*", optional = true, markers = "extra == \"requirements_deprecated_finder\""} +pipreqs = {version = "*", optional = true, markers = "extra == \"pipfile_deprecated_finder\" or extra == \"requirements_deprecated_finder\""} + +[package.extras] +colors = ["colorama (>=0.4.3,<0.5.0)"] +pipfile-deprecated-finder = ["pipreqs", "requirementslib"] +plugins = ["setuptools"] +requirements-deprecated-finder = ["pip-api", "pipreqs"] + +[[package]] +name = "jinja2" +version = "3.1.2" +description = "A very fast and expressive template engine." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, ] -jinxed = [ + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "jinxed" +version = "1.2.0" +description = "Jinxed Terminal Library" +category = "main" +optional = true +python-versions = "*" +files = [ {file = "jinxed-1.2.0-py2.py3-none-any.whl", hash = "sha256:cfc2b2e4e3b4326954d546ba6d6b9a7a796ddcb0aef8d03161d005177eb0d48b"}, {file = "jinxed-1.2.0.tar.gz", hash = "sha256:032acda92d5c57cd216033cbbd53de731e6ed50deb63eb4781336ca55f72cda5"}, ] -jmespath = [ + +[package.dependencies] +ansicon = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "jmespath" +version = "1.0.1" +description = "JSON Matching Expressions" +category = "main" +optional = true +python-versions = ">=3.7" +files = [ {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"}, {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, ] -markupsafe = [ + +[[package]] +name = "markupsafe" +version = "2.1.1" +description = "Safely add untrusted strings to HTML/XML markup." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"}, {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"}, {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"}, @@ -1271,39 +752,129 @@ markupsafe = [ {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"}, {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, ] -mypy-extensions = [ + +[[package]] +name = "mypy-extensions" +version = "0.4.3" +description = "Experimental type system extensions for programs checked with the mypy typechecker." +category = "dev" +optional = false +python-versions = "*" +files = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] -packaging = [ + +[[package]] +name = "packaging" +version = "21.3" +description = "Core utilities for Python packages" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, ] -pathspec = [ + +[package.dependencies] +pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" + +[[package]] +name = "pathspec" +version = "0.10.1" +description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ {file = "pathspec-0.10.1-py3-none-any.whl", hash = "sha256:46846318467efc4556ccfd27816e004270a9eeeeb4d062ce5e6fc7a87c573f93"}, {file = "pathspec-0.10.1.tar.gz", hash = "sha256:7ace6161b621d31e7902eb6b5ae148d12cfd23f4a249b9ffb6b9fee12084323d"}, ] -pip = [ + +[[package]] +name = "pip" +version = "22.3" +description = "The PyPA recommended tool for installing Python packages." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ {file = "pip-22.3-py3-none-any.whl", hash = "sha256:1daab4b8d3b97d1d763caeb01a4640a2250a0ea899e257b1e44b9eded91e15ab"}, {file = "pip-22.3.tar.gz", hash = "sha256:8182aec21dad6c0a49a2a3d121a87cd524b950e0b6092b181625f07ebdde7530"}, ] -pip-api = [ + +[[package]] +name = "pip-api" +version = "0.0.30" +description = "An unofficial, importable pip API" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ {file = "pip-api-0.0.30.tar.gz", hash = "sha256:a05df2c7aa9b7157374bcf4273544201a0c7bae60a9c65bcf84f3959ef3896f3"}, {file = "pip_api-0.0.30-py3-none-any.whl", hash = "sha256:2a0314bd31522eb9ffe8a99668b0d07fee34ebc537931e7b6483001dbedcbdc9"}, ] -pipreqs = [ + +[package.dependencies] +pip = "*" + +[[package]] +name = "pipreqs" +version = "0.4.11" +description = "Pip requirements.txt generator based on imports in project" +category = "dev" +optional = false +python-versions = "*" +files = [ {file = "pipreqs-0.4.11-py2.py3-none-any.whl", hash = "sha256:1510a91ae73ef6a8e2f24ffc8751132251cd61a01296d61538f37d1491841640"}, {file = "pipreqs-0.4.11.tar.gz", hash = "sha256:c793b4e147ac437871b3a962c5ce467e129c859ece5ba79aca83c20f4d9c3aef"}, ] -platformdirs = [ + +[package.dependencies] +docopt = "*" +yarg = "*" + +[[package]] +name = "platformdirs" +version = "2.5.2" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, ] -pluggy = [ + +[package.extras] +docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx (>=4)", "sphinx-autodoc-typehints (>=1.12)"] +test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] + +[[package]] +name = "pluggy" +version = "1.0.0" +description = "plugin and hook calling mechanisms for python" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, ] -psutil = [ + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "psutil" +version = "5.9.3" +description = "Cross-platform lib for process and system monitoring in Python." +category = "main" +optional = true +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ {file = "psutil-5.9.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:b4a247cd3feaae39bb6085fcebf35b3b8ecd9b022db796d89c8f05067ca28e71"}, {file = "psutil-5.9.3-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:5fa88e3d5d0b480602553d362c4b33a63e0c40bfea7312a7bf78799e01e0810b"}, {file = "psutil-5.9.3-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:767ef4fa33acda16703725c0473a91e1832d296c37c63896c7153ba81698f1ab"}, @@ -1341,15 +912,45 @@ psutil = [ {file = "psutil-5.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:4bd4854f0c83aa84a5a40d3b5d0eb1f3c128f4146371e03baed4589fe4f3c931"}, {file = "psutil-5.9.3.tar.gz", hash = "sha256:7ccfcdfea4fc4b0a02ca2c31de7fcd186beb9cff8207800e14ab66f79c773af6"}, ] -py = [ + +[package.extras] +test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] + +[[package]] +name = "py" +version = "1.11.0" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, ] -pygments = [ + +[[package]] +name = "pygments" +version = "2.13.0" +description = "Pygments is a syntax highlighting package written in Python." +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ {file = "Pygments-2.13.0-py3-none-any.whl", hash = "sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42"}, {file = "Pygments-2.13.0.tar.gz", hash = "sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1"}, ] -pymongo = [ + +[package.extras] +plugins = ["importlib-metadata"] + +[[package]] +name = "pymongo" +version = "4.3.2" +description = "Python driver for MongoDB " +category = "main" +optional = true +python-versions = ">=3.7" +files = [ {file = "pymongo-4.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:68320e5326e2b1e49dcd901e6dcbe3009b8a0fd0da0c618579a2be7cf5f2d7be"}, {file = "pymongo-4.3.2-cp310-cp310-manylinux1_i686.whl", hash = "sha256:3f41781c8310fe1ae3ed0b809e2d7be6ebba9f0954c08e1d18ac443916b82b29"}, {file = "pymongo-4.3.2-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:372307185d8e17ea31d2f3ff6943e213a6c379ccf547f18b05a58a1620d6f92a"}, @@ -1425,110 +1026,559 @@ pymongo = [ {file = "pymongo-4.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:d7bdfac2f3c87d0971691f2a091427f55bb6b94b23d74213ed2de87d8facba85"}, {file = "pymongo-4.3.2.tar.gz", hash = "sha256:95913659d6c5fc714e662533d014836c988cc1561684f07b6a0a8343651afa66"}, ] -pyparsing = [ + +[package.dependencies] +dnspython = ">=1.16.0,<3.0.0" + +[package.extras] +aws = ["pymongo-auth-aws (<2.0.0)"] +encryption = ["pymongocrypt (>=1.3.0,<2.0.0)"] +gssapi = ["pykerberos"] +ocsp = ["certifi", "pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)"] +snappy = ["python-snappy"] +zstd = ["zstandard"] + +[[package]] +name = "pyparsing" +version = "3.0.9" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" +category = "main" +optional = false +python-versions = ">=3.6.8" +files = [ {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, ] -pytest = [ + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] + +[[package]] +name = "pytest" +version = "7.1.3" +description = "pytest: simple powerful testing with Python" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ {file = "pytest-7.1.3-py3-none-any.whl", hash = "sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7"}, {file = "pytest-7.1.3.tar.gz", hash = "sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39"}, ] -pytest-cov = [ + +[package.dependencies] +attrs = ">=19.2.0" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +py = ">=1.8.2" +tomli = ">=1.0.0" + +[package.extras] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] + +[[package]] +name = "pytest-cov" +version = "4.0.0" +description = "Pytest plugin for measuring coverage." +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"}, ] -pytest-django = [ + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] + +[[package]] +name = "pytest-django" +version = "4.5.2" +description = "A Django plugin for pytest." +category = "dev" +optional = false +python-versions = ">=3.5" +files = [ {file = "pytest-django-4.5.2.tar.gz", hash = "sha256:d9076f759bb7c36939dbdd5ae6633c18edfc2902d1a69fdbefd2426b970ce6c2"}, {file = "pytest_django-4.5.2-py3-none-any.whl", hash = "sha256:c60834861933773109334fe5a53e83d1ef4828f2203a1d6a0fa9972f4f75ab3e"}, ] -python-dateutil = [ + +[package.dependencies] +pytest = ">=5.4.0" + +[package.extras] +docs = ["sphinx", "sphinx-rtd-theme"] +testing = ["Django", "django-configurations (>=2.0)"] + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +category = "main" +optional = true +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, ] -pytz = [ + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pytz" +version = "2022.5" +description = "World timezone definitions, modern and historical" +category = "dev" +optional = false +python-versions = "*" +files = [ {file = "pytz-2022.5-py2.py3-none-any.whl", hash = "sha256:335ab46900b1465e714b4fda4963d87363264eb662aab5e65da039c25f1f5b22"}, {file = "pytz-2022.5.tar.gz", hash = "sha256:c4d88f472f54d615e9cd582a5004d1e5f624854a6a27a6211591c251f22a6914"}, ] -redis = [ + +[[package]] +name = "redis" +version = "4.3.4" +description = "Python client for Redis database and key-value store" +category = "main" +optional = true +python-versions = ">=3.6" +files = [ {file = "redis-4.3.4-py3-none-any.whl", hash = "sha256:a52d5694c9eb4292770084fa8c863f79367ca19884b329ab574d5cb2036b3e54"}, {file = "redis-4.3.4.tar.gz", hash = "sha256:ddf27071df4adf3821c4f2ca59d67525c3a82e5f268bed97b813cb4fabf87880"}, ] -requests = [ + +[package.dependencies] +async-timeout = ">=4.0.2" +deprecated = ">=1.2.3" +packaging = ">=20.4" + +[package.extras] +hiredis = ["hiredis (>=1.0.0)"] +ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"] + +[[package]] +name = "requests" +version = "2.28.1" +description = "Python HTTP for Humans." +category = "main" +optional = false +python-versions = ">=3.7, <4" +files = [ {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, ] -rollbar = [ + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<3" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<1.27" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "rollbar" +version = "0.14.7" +description = "Easy and powerful exception tracking with Rollbar. Send messages and exceptions with arbitrary context, get back aggregates, and debug production issues quickly." +category = "main" +optional = true +python-versions = "*" +files = [ {file = "rollbar-0.14.7.tar.gz", hash = "sha256:ee2dd1a2b512f93e9c0f26c8cf6bb28c4f06ae7e0c33a60e39b49337e0d92d57"}, ] -s3transfer = [ + +[package.dependencies] +requests = ">=0.12.1" +six = ">=1.9.0" + +[[package]] +name = "s3transfer" +version = "0.6.0" +description = "An Amazon S3 Transfer Manager" +category = "main" +optional = true +python-versions = ">= 3.7" +files = [ {file = "s3transfer-0.6.0-py3-none-any.whl", hash = "sha256:06176b74f3a15f61f1b4f25a1fc29a4429040b7647133a463da8fa5bd28d5ecd"}, {file = "s3transfer-0.6.0.tar.gz", hash = "sha256:2ed07d3866f523cc561bf4a00fc5535827981b117dd7876f036b0c1aca42c947"}, ] -sentry-sdk = [ + +[package.dependencies] +botocore = ">=1.12.36,<2.0a.0" + +[package.extras] +crt = ["botocore[crt] (>=1.20.29,<2.0a.0)"] + +[[package]] +name = "sentry-sdk" +version = "1.10.0" +description = "Python client for Sentry (https://sentry.io)" +category = "main" +optional = true +python-versions = "*" +files = [ {file = "sentry-sdk-1.10.0.tar.gz", hash = "sha256:1b965bcdbfe52321bb1307c7c93c74035afdbfceb5f585f01a963327c5befc4e"}, {file = "sentry_sdk-1.10.0-py2.py3-none-any.whl", hash = "sha256:8c648e96e0e2ec5e17ca75a28c442e2f523453fa7cf761ec093f4a656153490e"}, ] -six = [ + +[package.dependencies] +certifi = "*" +urllib3 = {version = ">=1.26.11", markers = "python_version >= \"3.6\""} + +[package.extras] +aiohttp = ["aiohttp (>=3.5)"] +beam = ["apache-beam (>=2.12)"] +bottle = ["bottle (>=0.12.13)"] +celery = ["celery (>=3)"] +chalice = ["chalice (>=1.16.0)"] +django = ["django (>=1.8)"] +falcon = ["falcon (>=1.4)"] +fastapi = ["fastapi (>=0.79.0)"] +flask = ["blinker (>=1.1)", "flask (>=0.11)"] +httpx = ["httpx (>=0.16.0)"] +pure-eval = ["asttokens", "executing", "pure-eval"] +pyspark = ["pyspark (>=2.4.4)"] +quart = ["blinker (>=1.1)", "quart (>=0.16.1)"] +rq = ["rq (>=0.6)"] +sanic = ["sanic (>=0.8)"] +sqlalchemy = ["sqlalchemy (>=1.2)"] +starlette = ["starlette (>=0.19.1)"] +tornado = ["tornado (>=5)"] + +[[package]] +name = "setproctitle" +version = "1.3.2" +description = "A Python module to customize the process title" +category = "main" +optional = true +python-versions = ">=3.7" +files = [ + {file = "setproctitle-1.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:288943dec88e178bb2fd868adf491197cc0fc8b6810416b1c6775e686bab87fe"}, + {file = "setproctitle-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:630f6fe5e24a619ccf970c78e084319ee8be5be253ecc9b5b216b0f474f5ef18"}, + {file = "setproctitle-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c877691b90026670e5a70adfbcc735460a9f4c274d35ec5e8a43ce3f8443005"}, + {file = "setproctitle-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7a55fe05f15c10e8c705038777656fe45e3bd676d49ad9ac8370b75c66dd7cd7"}, + {file = "setproctitle-1.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab45146c71ca6592c9cc8b354a2cc9cc4843c33efcbe1d245d7d37ce9696552d"}, + {file = "setproctitle-1.3.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e00c9d5c541a2713ba0e657e0303bf96ddddc412ef4761676adc35df35d7c246"}, + {file = "setproctitle-1.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:265ecbe2c6eafe82e104f994ddd7c811520acdd0647b73f65c24f51374cf9494"}, + {file = "setproctitle-1.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c2c46200656280a064073447ebd363937562debef329482fd7e570c8d498f806"}, + {file = "setproctitle-1.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:fa2f50678f04fda7a75d0fe5dd02bbdd3b13cbe6ed4cf626e4472a7ccf47ae94"}, + {file = "setproctitle-1.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7f2719a398e1a2c01c2a63bf30377a34d0b6ef61946ab9cf4d550733af8f1ef1"}, + {file = "setproctitle-1.3.2-cp310-cp310-win32.whl", hash = "sha256:e425be62524dc0c593985da794ee73eb8a17abb10fe692ee43bb39e201d7a099"}, + {file = "setproctitle-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:e85e50b9c67854f89635a86247412f3ad66b132a4d8534ac017547197c88f27d"}, + {file = "setproctitle-1.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2a97d51c17d438cf5be284775a322d57b7ca9505bb7e118c28b1824ecaf8aeaa"}, + {file = "setproctitle-1.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:587c7d6780109fbd8a627758063d08ab0421377c0853780e5c356873cdf0f077"}, + {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d17c8bd073cbf8d141993db45145a70b307385b69171d6b54bcf23e5d644de"}, + {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e932089c35a396dc31a5a1fc49889dd559548d14cb2237adae260382a090382e"}, + {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e4f8f12258a8739c565292a551c3db62cca4ed4f6b6126664e2381acb4931bf"}, + {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:570d255fd99c7f14d8f91363c3ea96bd54f8742275796bca67e1414aeca7d8c3"}, + {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a8e0881568c5e6beff91ef73c0ec8ac2a9d3ecc9edd6bd83c31ca34f770910c4"}, + {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4bba3be4c1fabf170595b71f3af46c6d482fbe7d9e0563999b49999a31876f77"}, + {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:37ece938110cab2bb3957e3910af8152ca15f2b6efdf4f2612e3f6b7e5459b80"}, + {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db684d6bbb735a80bcbc3737856385b55d53f8a44ce9b46e9a5682c5133a9bf7"}, + {file = "setproctitle-1.3.2-cp311-cp311-win32.whl", hash = "sha256:ca58cd260ea02759238d994cfae844fc8b1e206c684beb8f38877dcab8451dfc"}, + {file = "setproctitle-1.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:88486e6cce2a18a033013d17b30a594f1c5cb42520c49c19e6ade40b864bb7ff"}, + {file = "setproctitle-1.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:92c626edc66169a1b09e9541b9c0c9f10488447d8a2b1d87c8f0672e771bc927"}, + {file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:710e16fa3bade3b026907e4a5e841124983620046166f355bbb84be364bf2a02"}, + {file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f29b75e86260b0ab59adb12661ef9f113d2f93a59951373eb6d68a852b13e83"}, + {file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c8d9650154afaa86a44ff195b7b10d683c73509d085339d174e394a22cccbb9"}, + {file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0452282258dfcc01697026a8841258dd2057c4438b43914b611bccbcd048f10"}, + {file = "setproctitle-1.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:e49ae693306d7624015f31cb3e82708916759d592c2e5f72a35c8f4cc8aef258"}, + {file = "setproctitle-1.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1ff863a20d1ff6ba2c24e22436a3daa3cd80be1dfb26891aae73f61b54b04aca"}, + {file = "setproctitle-1.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:55ce1e9925ce1765865442ede9dca0ba9bde10593fcd570b1f0fa25d3ec6b31c"}, + {file = "setproctitle-1.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7fe9df7aeb8c64db6c34fc3b13271a363475d77bc157d3f00275a53910cb1989"}, + {file = "setproctitle-1.3.2-cp37-cp37m-win32.whl", hash = "sha256:e5c50e164cd2459bc5137c15288a9ef57160fd5cbf293265ea3c45efe7870865"}, + {file = "setproctitle-1.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:a499fff50387c1520c085a07578a000123f519e5f3eee61dd68e1d301659651f"}, + {file = "setproctitle-1.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5b932c3041aa924163f4aab970c2f0e6b4d9d773f4d50326e0ea1cd69240e5c5"}, + {file = "setproctitle-1.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f4bfc89bd33ebb8e4c0e9846a09b1f5a4a86f5cb7a317e75cc42fee1131b4f4f"}, + {file = "setproctitle-1.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcd3cf4286a60fdc95451d8d14e0389a6b4f5cebe02c7f2609325eb016535963"}, + {file = "setproctitle-1.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5fb4f769c02f63fac90989711a3fee83919f47ae9afd4758ced5d86596318c65"}, + {file = "setproctitle-1.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5194b4969f82ea842a4f6af2f82cd16ebdc3f1771fb2771796e6add9835c1973"}, + {file = "setproctitle-1.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f0cde41857a644b7353a0060b5f94f7ba7cf593ebde5a1094da1be581ac9a31"}, + {file = "setproctitle-1.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9124bedd8006b0e04d4e8a71a0945da9b67e7a4ab88fdad7b1440dc5b6122c42"}, + {file = "setproctitle-1.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c8a09d570b39517de10ee5b718730e171251ce63bbb890c430c725c8c53d4484"}, + {file = "setproctitle-1.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:8ff3c8cb26afaed25e8bca7b9dd0c1e36de71f35a3a0706b5c0d5172587a3827"}, + {file = "setproctitle-1.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:589be87172b238f839e19f146b9ea47c71e413e951ef0dc6db4218ddacf3c202"}, + {file = "setproctitle-1.3.2-cp38-cp38-win32.whl", hash = "sha256:4749a2b0c9ac52f864d13cee94546606f92b981b50e46226f7f830a56a9dc8e1"}, + {file = "setproctitle-1.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:e43f315c68aa61cbdef522a2272c5a5b9b8fd03c301d3167b5e1343ef50c676c"}, + {file = "setproctitle-1.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:de3a540cd1817ede31f530d20e6a4935bbc1b145fd8f8cf393903b1e02f1ae76"}, + {file = "setproctitle-1.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4058564195b975ddc3f0462375c533cce310ccdd41b80ac9aed641c296c3eff4"}, + {file = "setproctitle-1.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c5d5dad7c28bdd1ec4187d818e43796f58a845aa892bb4481587010dc4d362b"}, + {file = "setproctitle-1.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ffc61a388a5834a97953d6444a2888c24a05f2e333f9ed49f977a87bb1ad4761"}, + {file = "setproctitle-1.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fa1a0fbee72b47dc339c87c890d3c03a72ea65c061ade3204f285582f2da30f"}, + {file = "setproctitle-1.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe8a988c7220c002c45347430993830666e55bc350179d91fcee0feafe64e1d4"}, + {file = "setproctitle-1.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bae283e85fc084b18ffeb92e061ff7ac5af9e183c9d1345c93e178c3e5069cbe"}, + {file = "setproctitle-1.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:fed18e44711c5af4b681c2b3b18f85e6f0f1b2370a28854c645d636d5305ccd8"}, + {file = "setproctitle-1.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:b34baef93bfb20a8ecb930e395ccd2ae3268050d8cf4fe187de5e2bd806fd796"}, + {file = "setproctitle-1.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7f0bed90a216ef28b9d227d8d73e28a8c9b88c0f48a082d13ab3fa83c581488f"}, + {file = "setproctitle-1.3.2-cp39-cp39-win32.whl", hash = "sha256:4d8938249a7cea45ab7e1e48b77685d0f2bab1ebfa9dde23e94ab97968996a7c"}, + {file = "setproctitle-1.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:a47d97a75fd2d10c37410b180f67a5835cb1d8fdea2648fd7f359d4277f180b9"}, + {file = "setproctitle-1.3.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:dad42e676c5261eb50fdb16bdf3e2771cf8f99a79ef69ba88729aeb3472d8575"}, + {file = "setproctitle-1.3.2-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c91b9bc8985d00239f7dc08a49927a7ca1ca8a6af2c3890feec3ed9665b6f91e"}, + {file = "setproctitle-1.3.2-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8579a43eafd246e285eb3a5b939e7158073d5087aacdd2308f23200eac2458b"}, + {file = "setproctitle-1.3.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:2fbd8187948284293f43533c150cd69a0e4192c83c377da837dbcd29f6b83084"}, + {file = "setproctitle-1.3.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:faec934cfe5fd6ac1151c02e67156c3f526e82f96b24d550b5d51efa4a5527c6"}, + {file = "setproctitle-1.3.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1aafc91cbdacc9e5fe712c52077369168e6b6c346f3a9d51bf600b53eae56bb"}, + {file = "setproctitle-1.3.2-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b617f12c9be61e8f4b2857be4a4319754756845dbbbd9c3718f468bbb1e17bcb"}, + {file = "setproctitle-1.3.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:b2c9cb2705fc84cb8798f1ba74194f4c080aaef19d9dae843591c09b97678e98"}, + {file = "setproctitle-1.3.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a149a5f7f2c5a065d4e63cb0d7a4b6d3b66e6e80f12e3f8827c4f63974cbf122"}, + {file = "setproctitle-1.3.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e3ac25bfc4a0f29d2409650c7532d5ddfdbf29f16f8a256fc31c47d0dc05172"}, + {file = "setproctitle-1.3.2-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65d884e22037b23fa25b2baf1a3316602ed5c5971eb3e9d771a38c3a69ce6e13"}, + {file = "setproctitle-1.3.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7aa0aac1711fadffc1d51e9d00a3bea61f68443d6ac0241a224e4d622489d665"}, + {file = "setproctitle-1.3.2.tar.gz", hash = "sha256:b9fb97907c830d260fa0658ed58afd48a86b2b88aac521135c352ff7fd3477fd"}, +] + +[package.extras] +test = ["pytest"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" +optional = true +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] -snowballstemmer = [ + +[[package]] +name = "snowballstemmer" +version = "2.2.0" +description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." +category = "dev" +optional = false +python-versions = "*" +files = [ {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, ] -sphinx = [ + +[[package]] +name = "sphinx" +version = "4.5.0" +description = "Python documentation generator" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ {file = "Sphinx-4.5.0-py3-none-any.whl", hash = "sha256:ebf612653238bcc8f4359627a9b7ce44ede6fdd75d9d30f68255c7383d3a6226"}, {file = "Sphinx-4.5.0.tar.gz", hash = "sha256:7bf8ca9637a4ee15af412d1a1d9689fec70523a68ca9bb9127c2f3eeb344e2e6"}, ] -sphinxcontrib-applehelp = [ + +[package.dependencies] +alabaster = ">=0.7,<0.8" +babel = ">=1.3" +colorama = {version = ">=0.3.5", markers = "sys_platform == \"win32\""} +docutils = ">=0.14,<0.18" +imagesize = "*" +importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} +Jinja2 = ">=2.3" +packaging = "*" +Pygments = ">=2.0" +requests = ">=2.5.0" +snowballstemmer = ">=1.1" +sphinxcontrib-applehelp = "*" +sphinxcontrib-devhelp = "*" +sphinxcontrib-htmlhelp = ">=2.0.0" +sphinxcontrib-jsmath = "*" +sphinxcontrib-qthelp = "*" +sphinxcontrib-serializinghtml = ">=1.1.5" + +[package.extras] +docs = ["sphinxcontrib-websupport"] +lint = ["docutils-stubs", "flake8 (>=3.5.0)", "isort", "mypy (>=0.931)", "types-requests", "types-typed-ast"] +test = ["cython", "html5lib", "pytest", "pytest-cov", "typed-ast"] + +[[package]] +name = "sphinxcontrib-applehelp" +version = "1.0.2" +description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books" +category = "dev" +optional = false +python-versions = ">=3.5" +files = [ {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"}, {file = "sphinxcontrib_applehelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a"}, ] -sphinxcontrib-devhelp = [ + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-devhelp" +version = "1.0.2" +description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." +category = "dev" +optional = false +python-versions = ">=3.5" +files = [ {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"}, {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"}, ] -sphinxcontrib-htmlhelp = [ + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-htmlhelp" +version = "2.0.0" +description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ {file = "sphinxcontrib-htmlhelp-2.0.0.tar.gz", hash = "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2"}, {file = "sphinxcontrib_htmlhelp-2.0.0-py2.py3-none-any.whl", hash = "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07"}, ] -sphinxcontrib-jsmath = [ + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["html5lib", "pytest"] + +[[package]] +name = "sphinxcontrib-jsmath" +version = "1.0.1" +description = "A sphinx extension which renders display math in HTML via JavaScript" +category = "dev" +optional = false +python-versions = ">=3.5" +files = [ {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, ] -sphinxcontrib-qthelp = [ + +[package.extras] +test = ["flake8", "mypy", "pytest"] + +[[package]] +name = "sphinxcontrib-qthelp" +version = "1.0.3" +description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." +category = "dev" +optional = false +python-versions = ">=3.5" +files = [ {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"}, {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"}, ] -sphinxcontrib-serializinghtml = [ + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-serializinghtml" +version = "1.1.5" +description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." +category = "dev" +optional = false +python-versions = ">=3.5" +files = [ {file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"}, {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"}, ] -sqlparse = [ + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] + +[[package]] +name = "sqlparse" +version = "0.4.3" +description = "A non-validating SQL parser." +category = "main" +optional = false +python-versions = ">=3.5" +files = [ {file = "sqlparse-0.4.3-py3-none-any.whl", hash = "sha256:0323c0ec29cd52bceabc1b4d9d579e311f3e4961b98d174201d5622a23b85e34"}, {file = "sqlparse-0.4.3.tar.gz", hash = "sha256:69ca804846bb114d2ec380e4360a8a340db83f0ccf3afceeb1404df028f57268"}, ] -tomli = [ + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] -typing-extensions = [ + +[[package]] +name = "typing-extensions" +version = "4.4.0" +description = "Backported and Experimental Type Hints for Python 3.7+" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, ] -tzdata = [ + +[[package]] +name = "tzdata" +version = "2022.5" +description = "Provider of IANA time zone data" +category = "main" +optional = false +python-versions = ">=2" +files = [ {file = "tzdata-2022.5-py2.py3-none-any.whl", hash = "sha256:323161b22b7802fdc78f20ca5f6073639c64f1a7227c40cd3e19fd1d0ce6650a"}, {file = "tzdata-2022.5.tar.gz", hash = "sha256:e15b2b3005e2546108af42a0eb4ccab4d9e225e2dfbf4f77aad50c70a4b1f3ab"}, ] -urllib3 = [ + +[[package]] +name = "urllib3" +version = "1.26.12" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4" +files = [ {file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"}, {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"}, ] -wcwidth = [ + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[[package]] +name = "wcwidth" +version = "0.2.5" +description = "Measures the displayed width of unicode strings in a terminal" +category = "main" +optional = true +python-versions = "*" +files = [ {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, ] -wrapt = [ + +[[package]] +name = "wrapt" +version = "1.14.1" +description = "Module for decorators, wrappers and monkey patching." +category = "main" +optional = true +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +files = [ {file = "wrapt-1.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3"}, {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef"}, {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28"}, @@ -1594,11 +1644,46 @@ wrapt = [ {file = "wrapt-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb"}, {file = "wrapt-1.14.1.tar.gz", hash = "sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d"}, ] -yarg = [ + +[[package]] +name = "yarg" +version = "0.1.9" +description = "A semi hard Cornish cheese, also queries PyPI (PyPI client)" +category = "dev" +optional = false +python-versions = "*" +files = [ {file = "yarg-0.1.9-py2.py3-none-any.whl", hash = "sha256:4f9cebdc00fac946c9bf2783d634e538a71c7d280a4d806d45fd4dc0ef441492"}, {file = "yarg-0.1.9.tar.gz", hash = "sha256:55695bf4d1e3e7f756496c36a69ba32c40d18f821e38f61d028f6049e5e15911"}, ] -zipp = [ + +[package.dependencies] +requests = "*" + +[[package]] +name = "zipp" +version = "3.9.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ {file = "zipp-3.9.0-py3-none-any.whl", hash = "sha256:972cfa31bc2fedd3fa838a51e9bc7e64b7fb725a8c00e7431554311f180e9980"}, {file = "zipp-3.9.0.tar.gz", hash = "sha256:3a7af91c3db40ec72dd9d154ae18e008c69efe8ca88dde4f9a731bb82fe2f9eb"}, ] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] +testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] + +[extras] +build-backend = [] +requires = [] +rollbar = ["django-q-rollbar"] +sentry = ["django-q-sentry"] +testing = ["django-redis", "croniter", "hiredis", "psutil", "iron-mq", "boto3", "pymongo", "blessed", "redis"] + +[metadata] +lock-version = "2.0" +python-versions = ">=3.8.14, <4" +content-hash = "6fd49a20d7ac72c3fb3e5941bbe46d1088aa8ff1592db7b8c3ec72be622dc43f" diff --git a/pyproject.toml b/pyproject.toml index 9d7afc2..ba24385 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,6 +59,7 @@ croniter = { version = "^1.3.7", optional = true } django-q-rollbar = {version = ">=0.1", optional = true} django-q-sentry = {version = ">=0.1", optional = true} redis = {version = "^4.3.4", optional = true} +setproctitle = {version = "^1.3.2", optional = true} [tool.poetry.dev-dependencies] @@ -72,7 +73,7 @@ isort = {extras = ["requirements_deprecated_finder"], version = "^5.10.1"} [tool.poetry.extras] requires = ["poetry_core>=1.0.0"] build-backend = ["poetry.core.masonry.api"] -testing = ["django-redis", "croniter", "hiredis", "psutil", "iron-mq", "boto3", "pymongo", "blessed", "redis"] +testing = ["django-redis", "croniter", "hiredis", "psutil", "iron-mq", "boto3", "pymongo", "blessed", "redis", "setproctitle"] rollbar = ["django-q-rollbar"] sentry = ["django-q-sentry"] From 264607f59c4f4d725a34ff9d365bbd1c9d5e7b49 Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Thu, 26 Jan 2023 02:49:46 +0100 Subject: [PATCH 33/39] Bump translations to latest changes (#63) --- django_q/locale/de/LC_MESSAGES/django.po | 136 +++++++++++----------- django_q/locale/fr/LC_MESSAGES/django.po | 137 ++++++++++++----------- django_q/locale/tr/LC_MESSAGES/django.po | 136 +++++++++++----------- 3 files changed, 208 insertions(+), 201 deletions(-) diff --git a/django_q/locale/de/LC_MESSAGES/django.po b/django_q/locale/de/LC_MESSAGES/django.po index 151e0f6..64c7c93 100644 --- a/django_q/locale/de/LC_MESSAGES/django.po +++ b/django_q/locale/de/LC_MESSAGES/django.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-01-15 23:35+0100\n" +"POT-Creation-Date: 2023-01-26 01:38+0000\n" "PO-Revision-Date: 2018-08-05 18:28+0200\n" "Last-Translator: Jonas Winkler\n" "Language-Team: \n" @@ -31,39 +31,38 @@ msgstr "erfolg" msgid "last_run" msgstr "" -#: cluster.py:76 +#: cluster.py:79 #, python-format msgid "Q Cluster %(name)s starting." msgstr "Q-Cluster %(name)s wird gestartet." -#: cluster.py:84 +#: cluster.py:87 #, fuzzy, python-format #| msgid "Q Cluster-{} stopping." msgid "Q Cluster %(name)s stopping." msgstr "Q-Cluster {name} wird gestoppt." -#: cluster.py:91 +#: cluster.py:90 #, python-format msgid "Q Cluster %(name)s has stopped." msgstr "Q-Cluster %(name)s wurde gestoppt." - -#: cluster.py:94 +#: cluster.py:97 #, python-format msgid "%(name)s got signal %(signal)s" msgstr "%(name)s erhielt das Signal %(signal)s" -#: cluster.py:225 +#: cluster.py:224 #, python-format msgid "reincarnated monitor %(name)s after sudden death" msgstr "Monitor %(name)s wurde nach unerwartetem Absturz neu gestartet" -#: cluster.py:227 +#: cluster.py:230 #, python-format msgid "reincarnated pusher %(name)s after sudden death" msgstr "Pusher %(name)s wurde nach unerwartetem Absturz neu gestartet" -#: cluster.py:251 +#: cluster.py:250 #, fuzzy, python-format #| msgid "reincarnated worker %(name)s after timeout" msgid "" @@ -71,102 +70,100 @@ msgid "" "%(task_name)s" msgstr "Worker %(name)s wurde nach Zeitüberschreitung neu gestartet" -#: cluster.py:256 +#: cluster.py:255 #, python-format msgid "reincarnated worker %(name)s after timeout" msgstr "Worker %(name)s wurde nach Zeitüberschreitung neu gestartet" -#: cluster.py:242 +#: cluster.py:260 #, python-format msgid "recycled worker %(name)s" msgstr "Worker %(name)s wurde wiederverwendet" -#: cluster.py:245 +#: cluster.py:263 #, python-format msgid "reincarnated worker %(name)s after death" msgstr "Worker %(name)s wurde nach unerwartetem Absturz neu gestartet" -#: cluster.py:269 +#: cluster.py:287 #, python-format msgid "%(name)s guarding cluster %(cluster_name)s" msgstr "%(name)s beschützt das Cluster %(cluster_name)s" -#: cluster.py:278 +#: cluster.py:296 #, python-format msgid "Q Cluster %(cluster_name)s running." msgstr "Q-Cluster %(cluster_name)s läuft." - -#: cluster.py:314 +#: cluster.py:332 #, python-format msgid "%(name)s stopping cluster processes" msgstr "%(name)s hält Cluster-Prozesse an" -#: cluster.py:339 +#: cluster.py:357 #, python-format msgid "%(name)s waiting for the monitor." msgstr "%(name)s wartet auf den Monitor." - -#: cluster.py:384 +#: cluster.py:383 #, fuzzy, python-format #| msgid "%(process_name)s pushing tasks at %(id)s" msgid "%(name)s pushing tasks at %(id)s" msgstr "%(process_name)s veröffentlicht Aufagaben auf %(id)s" -#: cluster.py:408 +#: cluster.py:407 #, python-format msgid "queueing from %(list_key)s" msgstr "Einreihen von %(list_key)s" -#: cluster.py:412 +#: cluster.py:411 #, python-format msgid "%(name)s stopped pushing tasks" msgstr "%(name)s veröffentlicht keine Aufgaben mehr" -#: cluster.py:427 +#: cluster.py:426 #, python-format msgid "%(name)s monitoring at %(id)s" msgstr "%(name)s beobachtet auf %(id)s" -#: cluster.py:446 +#: cluster.py:445 #, python-format msgid "Processed '%(info_name)s' (%(task_name)s)" msgstr "[%(task_name)s] - '%(info_name)s' wurde verarbeitet" -#: cluster.py:452 +#: cluster.py:451 #, python-format msgid "Failed '%(info_name)s' (%(task_name)s) - %(task_result)s" msgstr "'%(info_name)s' (%(task_name)s) ist fehlgeschlagen - %(task_result)s" -#: cluster.py:459 +#: cluster.py:458 #, python-format msgid "%(name)s stopped monitoring results" msgstr "%(name)s überwacht keine Ergebnisse mehr" -#: cluster.py:475 +#: cluster.py:474 #, python-format msgid "%(proc_name)s ready for work at %(id)s" msgstr "%(proc_name)s ist bereit für Arbeit auf %(id)s" -#: cluster.py:495 +#: cluster.py:494 #, fuzzy, python-format #| msgid "%(proc_name)s processing '%(func_name)s' (%(task_name)s)" msgid "%(proc_name)s processing %(task_name)s '%(func_name)s'" msgstr "%(proc_name)s verarbeitet '%(func_name)s' (%(task_name)s)" -#: cluster.py:543 +#: cluster.py:546 #, python-format msgid "%(proc_name)s stopped doing work" msgstr "%(proc_name)s hat die Arbeit beendet" -#: cluster.py:756 +#: cluster.py:751 #, python-format msgid "%(process_name)s failed to create a task from schedule [%(schedule)s]" msgstr "" "%(process_name)s konnte keine Aufgabe von Zeitplan [%(schedule)s] erstellen" -#: cluster.py:767 +#: cluster.py:762 #, fuzzy, python-format #| msgid "%(process_name)s created a task from schedule [%(schedule)s]" msgid "" @@ -174,22 +171,22 @@ msgid "" msgstr "" "%(process_name)s hat eine Aufgabe des Zeitplans [%(schedule)s] erstellt" -#: cluster.py:813 +#: cluster.py:808 msgid "Skipping cpu affinity because psutil was not found." msgstr "Cpu-Affinität wird übersprungen, da psutil nicht gefunden wurde." -#: cluster.py:818 +#: cluster.py:813 msgid "Faking cpu affinity because it is not supported on this platform" msgstr "" "Vortäuschen von CPU-Affinität, da diese auf dieser Plattform nicht " "unterstützt wird" -#: cluster.py:840 +#: cluster.py:835 #, python-format msgid "%(pid)s will use cpu %(affinity)s" msgstr "%(pid)s wird CPU %(affinity)s benutzen" -#: conf.py:93 +#: conf.py:90 #, python-format msgid "" "SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', " @@ -199,23 +196,23 @@ msgstr "" "'group', 'name', 'func' und None. Standard ist None." #. Translators: Cluster status descriptions -#: conf.py:210 +#: conf.py:207 msgid "Starting" msgstr "Wird gestartet" -#: conf.py:211 +#: conf.py:208 msgid "Working" msgstr "Arbeitet" -#: conf.py:212 +#: conf.py:209 msgid "Idle" msgstr "Leerlauf" -#: conf.py:213 +#: conf.py:210 msgid "Stopped" msgstr "Gestoppt" -#: conf.py:214 +#: conf.py:211 msgid "Stopping" msgstr "Wird gestoppt" @@ -239,116 +236,119 @@ msgstr "Überwacht die Speichernutzung von Q Cluster" msgid "Monitors Q Cluster activity" msgstr "Q-Cluster aktiv überwachen" - -#: models.py:124 +#: models.py:125 msgid "Successful task" msgstr "Erfolgreiche Aufgabe" -#: models.py:125 +#: models.py:126 msgid "Successful tasks" msgstr "Erfolgreiche Aufgaben" -#: models.py:140 +#: models.py:141 msgid "Failed task" msgstr "Fehlgeschlagene Aufgabe" -#: models.py:141 +#: models.py:142 msgid "Failed tasks" msgstr "Fehlgeschlagene Aufgaben" -#: models.py:149 models.py:222 +#: models.py:150 models.py:234 msgid "Please install croniter to enable cron expressions" msgstr "Bitte installieren Sie croniter, um Cron-Ausdrücke zu aktivieren" -#: models.py:165 +#: models.py:170 msgid "e.g. 1, 2, 'John'" msgstr "zum Beispiel 1, 2, 'John'" -#: models.py:167 +#: models.py:172 msgid "e.g. x=1, y=2, name='John'" msgstr "zum Beispiel x=1, y=2, name='John'" -#: models.py:181 +#: models.py:186 msgid "Once" msgstr "Einmal" -#: models.py:182 +#: models.py:187 msgid "Minutes" msgstr "Minuten" -#: models.py:183 +#: models.py:188 msgid "Hourly" msgstr "Stündlich" -#: models.py:184 +#: models.py:189 msgid "Daily" msgstr "Täglich" -#: models.py:185 +#: models.py:190 msgid "Weekly" msgstr "Wöchentlich" -#: models.py:186 +#: models.py:191 msgid "Biweekly" msgstr "Zweiwöchentlich" -#: models.py:187 +#: models.py:192 msgid "Monthly" msgstr "Monatlich" -#: models.py:188 +#: models.py:193 msgid "Bimonthly" msgstr "Zweimonatlich" -#: models.py:189 +#: models.py:194 msgid "Quarterly" msgstr "Vierteljährlich" -#: models.py:190 +#: models.py:195 msgid "Yearly" msgstr "Jährlich" -#: models.py:191 +#: models.py:196 msgid "Cron" msgstr "Cron" -#: models.py:194 +#: models.py:199 msgid "Schedule Type" msgstr "Zeitplan-Typ" -#: models.py:197 +#: models.py:202 msgid "Number of minutes for the Minutes type" msgstr "Anzahl Minuten für den Typ 'Minuten'" -#: models.py:200 +#: models.py:205 msgid "Repeats" msgstr "Wiederhohlungen" -#: models.py:200 +#: models.py:205 msgid "n = n times, -1 = forever" msgstr "n = n mal, -1 = für immer" -#: models.py:203 +#: models.py:208 msgid "Next Run" msgstr "Nächste Ausführung" -#: models.py:210 +#: models.py:215 msgid "Cron expression" msgstr "Cron-Ausdruck" -#: models.py:287 +#: models.py:224 +msgid "Name of kwarg to pass intended schedule date" +msgstr "Name des zu passierenden Kwargs vorgesehenes Datum" + +#: models.py:299 msgid "Scheduled task" msgstr "Geplante Aufgabe" -#: models.py:288 +#: models.py:300 msgid "Scheduled tasks" msgstr "Geplante Aufgaben" -#: models.py:314 +#: models.py:326 msgid "Queued task" msgstr "Eingereihte Aufgabe" -#: models.py:315 +#: models.py:327 msgid "Queued tasks" msgstr "Eingereihte Aufgaben" diff --git a/django_q/locale/fr/LC_MESSAGES/django.po b/django_q/locale/fr/LC_MESSAGES/django.po index 6f4eb0a..7e43806 100644 --- a/django_q/locale/fr/LC_MESSAGES/django.po +++ b/django_q/locale/fr/LC_MESSAGES/django.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-01-07 19:21+0100\n" +"POT-Creation-Date: 2023-01-26 01:38+0000\n" "PO-Revision-Date: 2018-08-05 18:28+0200\n" "Last-Translator: Thierry BOULOGNE \n" "Language-Team: \n" @@ -21,48 +21,47 @@ msgstr "" msgid "Resubmit selected tasks to queue" msgstr "Resoumettre les tâches sélectionnées à la file d'attente" -#: admin.py:107 models.py:281 +#: admin.py:107 models.py:293 #, fuzzy #| msgid "Success" msgid "success" msgstr "succès" -#: admin.py:119 models.py:283 +#: admin.py:119 models.py:295 msgid "last_run" msgstr "" -#: cluster.py:80 +#: cluster.py:79 #, python-format msgid "Q Cluster %(name)s starting." msgstr "Démarrage de Q Cluster-%(name)s." -#: cluster.py:88 +#: cluster.py:87 #, python-format msgid "Q Cluster %(name)s stopping." msgstr "Arrêt de Q Cluster-%(name)s." -#: cluster.py:91 +#: cluster.py:90 #, python-format msgid "Q Cluster %(name)s has stopped." msgstr "Q Cluster-%(name)s a été arrêté." -#: cluster.py:98 +#: cluster.py:97 #, python-format msgid "%(name)s got signal %(signal)s" msgstr "%(name)s à reçu le signal %(signal)s" -#: cluster.py:225 +#: cluster.py:224 #, python-format msgid "reincarnated monitor %(name)s after sudden death" msgstr "surveillant %(name)s réincarné après un arrêt intempestif" - -#: cluster.py:231 +#: cluster.py:230 #, python-format msgid "reincarnated pusher %(name)s after sudden death" msgstr "répartiteur %(name)s réincarné après un arrêt intempestif" -#: cluster.py:251 +#: cluster.py:250 #, python-format msgid "" "reincarnated worker %(name)s after timeout while processing task " @@ -71,99 +70,99 @@ msgstr "" "processus %(name)s réincarné, délai de traitement dépassé pour la tâche " "%(task_name)s" -#: cluster.py:256 +#: cluster.py:255 #, python-format msgid "reincarnated worker %(name)s after timeout" msgstr "processus %(name)s réincarné, délai de traitement dépassé" -#: cluster.py:261 +#: cluster.py:260 #, python-format msgid "recycled worker %(name)s" msgstr "processus recyclé %(name)s" -#: cluster.py:264 +#: cluster.py:263 #, python-format msgid "reincarnated worker %(name)s after death" msgstr "processus réintégré %(name)s après arrêt" -#: cluster.py:288 +#: cluster.py:287 #, python-format msgid "%(name)s guarding cluster %(cluster_name)s" msgstr "%(name)s surveillance du cluster à %(cluster_name)s" -#: cluster.py:297 +#: cluster.py:296 #, python-format msgid "Q Cluster %(cluster_name)s running." msgstr "Démarrage de Q Cluster-%(cluster_name)s." -#: cluster.py:333 +#: cluster.py:332 #, python-format msgid "%(name)s stopping cluster processes" msgstr "%(name)s arrêt des processus du cluster" -#: cluster.py:358 +#: cluster.py:357 #, python-format msgid "%(name)s waiting for the monitor." msgstr "%(name)s en attente du surveillant." -#: cluster.py:384 +#: cluster.py:383 #, python-format msgid "%(name)s pushing tasks at %(id)s" msgstr "%(name)s répartit les tâches %(id)s" -#: cluster.py:408 +#: cluster.py:407 #, python-format msgid "queueing from %(list_key)s" msgstr "mise en file d'attente de %(list_key)s" -#: cluster.py:412 +#: cluster.py:411 #, python-format msgid "%(name)s stopped pushing tasks" msgstr "%(name)s a cessé de répartir les tâches" -#: cluster.py:427 +#: cluster.py:426 #, python-format msgid "%(name)s monitoring at %(id)s" msgstr "%(name)s surveille les résultats %(id)s" -#: cluster.py:446 +#: cluster.py:445 #, python-format msgid "Processed '%(info_name)s' (%(task_name)s)" msgstr "traité '%(info_name)s' (%(task_name)s)" -#: cluster.py:452 +#: cluster.py:451 #, python-format msgid "Failed '%(info_name)s' (%(task_name)s) - %(task_result)s" msgstr "Manqué '%(info_name)s' (%(task_name)s) - %(task_result)s" -#: cluster.py:459 +#: cluster.py:458 #, python-format msgid "%(name)s stopped monitoring results" msgstr "%(name)s a cessé de de surveiller les résultats" -#: cluster.py:475 +#: cluster.py:474 #, python-format msgid "%(proc_name)s ready for work at %(id)s" msgstr "%(proc_name)s prêt pour le travail à %(id)s" -#: cluster.py:495 +#: cluster.py:494 #, fuzzy, python-format msgid "%(proc_name)s processing %(task_name)s '%(func_name)s'" msgstr "%(proc_name)s exécute %(task_name)s '%(func_name)s'" -#: cluster.py:543 +#: cluster.py:546 #, python-format msgid "%(proc_name)s stopped doing work" msgstr "%(proc_name)s a cessé de travailler" -#: cluster.py:756 +#: cluster.py:751 #, python-format msgid "%(process_name)s failed to create a task from schedule [%(schedule)s]" msgstr "" "%(process_name)s Echec de la création d'une tâche à partir de Schedule " "[%(schedule)s]" -#: cluster.py:767 +#: cluster.py:762 #, python-format msgid "" "%(process_name)s created task %(task_name)s from schedule [%(schedule)s]" @@ -171,22 +170,22 @@ msgstr "" "%(process_name)s a créé la tâche %(task_name)s à partir de Schedule " "[%(schedule)s]" -#: cluster.py:813 +#: cluster.py:808 msgid "Skipping cpu affinity because psutil was not found." msgstr "L'affinité cpu ne sera pas définie car psutil n'a pas été trouvé." -#: cluster.py:818 +#: cluster.py:813 msgid "Faking cpu affinity because it is not supported on this platform" msgstr "" "Simulation de l'affinité cpu parce qu'elle n'est pas supportée sur cette " "plateforme." -#: cluster.py:840 +#: cluster.py:835 #, python-format msgid "%(pid)s will use cpu %(affinity)s" msgstr "%(pid)s utilisera le CPU %(affinity)s" -#: conf.py:93 +#: conf.py:90 #, python-format msgid "" "SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', " @@ -196,23 +195,23 @@ msgstr "" "'group', 'name', 'func' et None. La valeur par défaut est None." #. Translators: Cluster status descriptions -#: conf.py:210 +#: conf.py:207 msgid "Starting" msgstr "Démarrage" -#: conf.py:211 +#: conf.py:208 msgid "Working" msgstr "Actif" -#: conf.py:212 +#: conf.py:209 msgid "Idle" msgstr "En attente" -#: conf.py:213 +#: conf.py:210 msgid "Stopped" msgstr "Arrêté" -#: conf.py:214 +#: conf.py:211 msgid "Stopping" msgstr "En cours d’arrêt" @@ -238,119 +237,123 @@ msgstr "Surveille l'utilisation mémoire du Q cluster" msgid "Monitors Q Cluster activity" msgstr "Surveille l'activité de Q cluster" -#: models.py:124 +#: models.py:125 msgid "Successful task" msgstr "Tâche réussie" -#: models.py:125 +#: models.py:126 msgid "Successful tasks" msgstr "Tâches réussies" -#: models.py:140 +#: models.py:141 msgid "Failed task" msgstr "Tâche échoué" -#: models.py:141 +#: models.py:142 msgid "Failed tasks" msgstr "Tâches échouées" -#: models.py:149 models.py:222 +#: models.py:150 models.py:234 msgid "Please install croniter to enable cron expressions" msgstr "Veuillez installer croniter pour activer les expressions cron." -#: models.py:165 +#: models.py:170 msgid "e.g. 1, 2, 'John'" msgstr "ex. 1, 2, ‘Jean’" -#: models.py:167 +#: models.py:172 msgid "e.g. x=1, y=2, name='John'" msgstr "p. ex. x = 1, y = 2, Nom = ‘Jean’" -#: models.py:181 +#: models.py:186 msgid "Once" msgstr "Une fois" -#: models.py:182 +#: models.py:187 msgid "Minutes" msgstr "Minutes" -#: models.py:183 +#: models.py:188 msgid "Hourly" msgstr "Toutes les heures" -#: models.py:184 +#: models.py:189 msgid "Daily" msgstr "Quotidien" -#: models.py:185 +#: models.py:190 msgid "Weekly" msgstr "Hebdomadaire" -#: models.py:186 +#: models.py:191 #, fuzzy #| msgid "Weekly" msgid "Biweekly" msgstr "Bihebdomadaire" -#: models.py:187 +#: models.py:192 msgid "Monthly" msgstr "Mensuel" -#: models.py:188 +#: models.py:193 #, fuzzy #| msgid "Monthly" msgid "Bimonthly" msgstr "Bimestriel" -#: models.py:189 +#: models.py:194 msgid "Quarterly" msgstr "Tous les quart-d’heure" -#: models.py:190 +#: models.py:195 msgid "Yearly" msgstr "Annuel" -#: models.py:191 +#: models.py:196 msgid "Cron" msgstr "Cron" -#: models.py:194 +#: models.py:199 msgid "Schedule Type" msgstr "Type de plannification" -#: models.py:197 +#: models.py:202 msgid "Number of minutes for the Minutes type" msgstr "Nombre de minutes pour le type de minutes" -#: models.py:200 +#: models.py:205 msgid "Repeats" msgstr "Répéter" -#: models.py:200 +#: models.py:205 msgid "n = n times, -1 = forever" msgstr "n = n fois,-1 = Toujours" -#: models.py:203 +#: models.py:208 msgid "Next Run" msgstr "Prochaine exécution" -#: models.py:210 +#: models.py:215 msgid "Cron expression" msgstr "Expression Cron" -#: models.py:287 +#: models.py:224 +msgid "Name of kwarg to pass intended schedule date" +msgstr "Nom du kwarg à passer Date prévue de l'horaire" + +#: models.py:299 msgid "Scheduled task" msgstr "Tâche planifiée" -#: models.py:288 +#: models.py:300 msgid "Scheduled tasks" msgstr "Tâches planifiées" -#: models.py:314 +#: models.py:326 msgid "Queued task" msgstr "Tâche en file d'attente" -#: models.py:315 +#: models.py:327 msgid "Queued tasks" msgstr "Tâches en file d'attente" diff --git a/django_q/locale/tr/LC_MESSAGES/django.po b/django_q/locale/tr/LC_MESSAGES/django.po index 24ea5fd..1861a18 100644 --- a/django_q/locale/tr/LC_MESSAGES/django.po +++ b/django_q/locale/tr/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-01-07 19:21+0100\n" +"POT-Creation-Date: 2023-01-26 01:38+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Ethem Güner \n" "Language-Team: \n" @@ -22,47 +22,47 @@ msgstr "" msgid "Resubmit selected tasks to queue" msgstr "Seçili işleri kuyruğa tekrar gönder" -#: admin.py:107 models.py:281 +#: admin.py:107 models.py:293 #, fuzzy #| msgid "Success" msgid "success" msgstr "başarılı olanlar" -#: admin.py:119 models.py:283 +#: admin.py:119 models.py:295 msgid "last_run" msgstr "" -#: cluster.py:80 +#: cluster.py:79 #, python-format msgid "Q Cluster %(name)s starting." msgstr "Q Cluster %(name)s başlatılıyor." -#: cluster.py:88 +#: cluster.py:87 #, python-format msgid "Q Cluster %(name)s stopping." msgstr "Q Cluster %(name)s durduruluyor." -#: cluster.py:91 +#: cluster.py:90 #, python-format msgid "Q Cluster %(name)s has stopped." msgstr "Q Cluster %(name)s durduruldu." -#: cluster.py:98 +#: cluster.py:97 #, python-format msgid "%(name)s got signal %(signal)s" msgstr "%(name)s, %(signal)s pid'inde izleniyor/monitoring yapılıyor." -#: cluster.py:225 +#: cluster.py:224 #, python-format msgid "reincarnated monitor %(name)s after sudden death" msgstr "Monitor %(name)s ani ölüm sonrası tekrar dirildi" -#: cluster.py:231 +#: cluster.py:230 #, python-format msgid "reincarnated pusher %(name)s after sudden death" msgstr "Pusher %(name)s ani ölüm sonrası tekrar dirildi" -#: cluster.py:251 +#: cluster.py:250 #, fuzzy, python-format #| msgid "reincarnated worker %(name)s after timeout" msgid "" @@ -70,119 +70,119 @@ msgid "" "%(task_name)s" msgstr "Worker %(name)s zaman aşımı sonrası tekrar dirildi" -#: cluster.py:256 +#: cluster.py:255 #, python-format msgid "reincarnated worker %(name)s after timeout" msgstr "Worker %(name)s zaman aşımı sonrası tekrar dirildi" -#: cluster.py:261 +#: cluster.py:260 #, python-format msgid "recycled worker %(name)s" msgstr "Worker %(name)s geri döndürüldü" -#: cluster.py:264 +#: cluster.py:263 #, python-format msgid "reincarnated worker %(name)s after death" msgstr "Worker %(name)s ani ölüm sonrası tekrar dirildi" -#: cluster.py:288 +#: cluster.py:287 #, python-format msgid "%(name)s guarding cluster %(cluster_name)s" msgstr "%(name)s, %(cluster_name)s cluster'ını koruyor" -#: cluster.py:297 +#: cluster.py:296 #, python-format msgid "Q Cluster %(cluster_name)s running." msgstr "Q Cluster %(cluster_name)s başlatılıyor." -#: cluster.py:333 +#: cluster.py:332 #, python-format msgid "%(name)s stopping cluster processes" msgstr "Cluster %(name)s işlemleri durduruluyor." -#: cluster.py:358 +#: cluster.py:357 #, python-format msgid "%(name)s waiting for the monitor." msgstr "%(name)s monitor için bekliyor." -#: cluster.py:384 +#: cluster.py:383 #, fuzzy, python-format #| msgid "%(process_name)s pushing tasks at %(id)s" msgid "%(name)s pushing tasks at %(id)s" msgstr "%(process_name)s, işleri %(id)s pid'ine gönderiyor." -#: cluster.py:408 +#: cluster.py:407 #, python-format msgid "queueing from %(list_key)s" msgstr "" -#: cluster.py:412 +#: cluster.py:411 #, python-format msgid "%(name)s stopped pushing tasks" msgstr "%(name)s işleri göndermeyi durdurdu" -#: cluster.py:427 +#: cluster.py:426 #, python-format msgid "%(name)s monitoring at %(id)s" msgstr "%(name)s, %(id)s pid'inde izleniyor/monitoring yapılıyor." -#: cluster.py:446 +#: cluster.py:445 #, python-format msgid "Processed '%(info_name)s' (%(task_name)s)" msgstr "[%(task_name)s] - '%(info_name)s işlendi." -#: cluster.py:452 +#: cluster.py:451 #, python-format msgid "Failed '%(info_name)s' (%(task_name)s) - %(task_result)s" msgstr "[%(task_name)s] - '%(info_name)s' - %(task_result)s başarısız oldu" -#: cluster.py:459 +#: cluster.py:458 #, python-format msgid "%(name)s stopped monitoring results" msgstr "%(name)s sonuçları göstermeyi bıraktı" -#: cluster.py:475 +#: cluster.py:474 #, python-format msgid "%(proc_name)s ready for work at %(id)s" msgstr "%(proc_name)s, %(id)s pid'inde çalışmaya hazır" -#: cluster.py:495 +#: cluster.py:494 #, fuzzy, python-format #| msgid "%(proc_name)s processing '%(func_name)s' (%(task_name)s)" msgid "%(proc_name)s processing %(task_name)s '%(func_name)s'" msgstr "%(proc_name)s, '%(func_name)s' [%(task_name)s] işlerini işiyor" -#: cluster.py:543 +#: cluster.py:546 #, python-format msgid "%(proc_name)s stopped doing work" msgstr "%(proc_name)s çalışmayı bıraktı" -#: cluster.py:756 +#: cluster.py:751 #, python-format msgid "%(process_name)s failed to create a task from schedule [%(schedule)s]" msgstr "%(process_name)s programdan bir görev oluşturamadı [%(schedule)s]" -#: cluster.py:767 +#: cluster.py:762 #, fuzzy, python-format #| msgid "%(process_name)s created a task from schedule [%(schedule)s]" msgid "" "%(process_name)s created task %(task_name)s from schedule [%(schedule)s]" msgstr "%(process_name)s programdan bir görev oluşturamadı [%(schedule)s]" -#: cluster.py:813 +#: cluster.py:808 msgid "Skipping cpu affinity because psutil was not found." msgstr "Psutil bulunamadığı için cpu benzeşimi atlanıyor." -#: cluster.py:818 +#: cluster.py:813 msgid "Faking cpu affinity because it is not supported on this platform" msgstr "Bu platformda desteklenmediği için sahte cpu benzeşimi" -#: cluster.py:840 +#: cluster.py:835 #, python-format msgid "%(pid)s will use cpu %(affinity)s" msgstr "%(pid)s cpu %(affinity)s kullanacaktır" -#: conf.py:93 +#: conf.py:90 #, python-format msgid "" "SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', " @@ -192,23 +192,23 @@ msgstr "" "'group', 'name', 'func' ve None. Varsayılan değer None'dır." #. Translators: Cluster status descriptions -#: conf.py:210 +#: conf.py:207 msgid "Starting" msgstr "Başlıyor" -#: conf.py:211 +#: conf.py:208 msgid "Working" msgstr "Çalışıyor" -#: conf.py:212 +#: conf.py:209 msgid "Idle" msgstr "Boşta" -#: conf.py:213 +#: conf.py:210 msgid "Stopped" msgstr "Durdu" -#: conf.py:214 +#: conf.py:211 msgid "Stopping" msgstr "Durduruluyor" @@ -232,119 +232,123 @@ msgstr "Q Cluster'ın bellek kullanımını izler" msgid "Monitors Q Cluster activity" msgstr "Q Cluster'ın aktivitelerini izler" -#: models.py:124 +#: models.py:125 msgid "Successful task" msgstr "Başarılı iş" -#: models.py:125 +#: models.py:126 msgid "Successful tasks" msgstr "Başarılı işler" -#: models.py:140 +#: models.py:141 msgid "Failed task" msgstr "Başarısız iş" -#: models.py:141 +#: models.py:142 msgid "Failed tasks" msgstr "Başarısız işler" -#: models.py:149 models.py:222 +#: models.py:150 models.py:234 msgid "Please install croniter to enable cron expressions" msgstr "Cron expressions'ları açmak için croniter yükleyin" -#: models.py:165 +#: models.py:170 msgid "e.g. 1, 2, 'John'" msgstr "Örneğin: 1, 2, 'Melih'" -#: models.py:167 +#: models.py:172 msgid "e.g. x=1, y=2, name='John'" msgstr "Örneğin: x=1, y=2, name='Melih'" -#: models.py:181 +#: models.py:186 msgid "Once" msgstr "Bir kere" -#: models.py:182 +#: models.py:187 msgid "Minutes" msgstr "Dakika" -#: models.py:183 +#: models.py:188 msgid "Hourly" msgstr "Saatlik" -#: models.py:184 +#: models.py:189 msgid "Daily" msgstr "Günlük" -#: models.py:185 +#: models.py:190 msgid "Weekly" msgstr "Haftalık" -#: models.py:186 +#: models.py:191 #, fuzzy #| msgid "Weekly" msgid "Biweekly" msgstr "İki haftada bir" -#: models.py:187 +#: models.py:192 msgid "Monthly" msgstr "Aylık" -#: models.py:188 +#: models.py:193 #, fuzzy #| msgid "Monthly" msgid "Bimonthly" msgstr "İki ayda bir" -#: models.py:189 +#: models.py:194 msgid "Quarterly" msgstr "Bir Çeyrek (3 Ay)" -#: models.py:190 +#: models.py:195 msgid "Yearly" msgstr "Yıllık" -#: models.py:191 +#: models.py:196 msgid "Cron" msgstr "" -#: models.py:194 +#: models.py:199 msgid "Schedule Type" msgstr "Zamanlama Tipi" -#: models.py:197 +#: models.py:202 msgid "Number of minutes for the Minutes type" msgstr "Dakika tipine göre dakika sayısı" -#: models.py:200 +#: models.py:205 msgid "Repeats" msgstr "Tekrar eder" -#: models.py:200 +#: models.py:205 msgid "n = n times, -1 = forever" msgstr "n = n kere, -1 = sonsuza kadar" -#: models.py:203 +#: models.py:208 msgid "Next Run" msgstr "Bir dahaki çalışma tarihi" -#: models.py:210 +#: models.py:215 msgid "Cron expression" msgstr "" -#: models.py:287 +#: models.py:224 +msgid "Name of kwarg to pass intended schedule date" +msgstr "Geçilecek kwarg'ın adı öngörülen program tarihi" + +#: models.py:299 msgid "Scheduled task" msgstr "Zamanlanmış iş" -#: models.py:288 +#: models.py:300 msgid "Scheduled tasks" msgstr "Zamanlanmış işler" -#: models.py:314 +#: models.py:326 msgid "Queued task" msgstr "Sıraya alınmış iş" -#: models.py:315 +#: models.py:327 msgid "Queued tasks" msgstr "Sıraya alınmış işler" From 2f3b0d0a3181e7f558643aef6e9f2db7e69f13a5 Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Thu, 26 Jan 2023 02:56:20 +0100 Subject: [PATCH 34/39] Update all dependencies (#64) --- poetry.lock | 1049 ++++++++++++++++++++++++++------------------------- 1 file changed, 528 insertions(+), 521 deletions(-) diff --git a/poetry.lock b/poetry.lock index 023ae7f..11ce662 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2,14 +2,14 @@ [[package]] name = "alabaster" -version = "0.7.12" +version = "0.7.13" description = "A configurable sidebar-enabled Sphinx theme" category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.6" files = [ - {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"}, - {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"}, + {file = "alabaster-0.7.13-py3-none-any.whl", hash = "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3"}, + {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"}, ] [[package]] @@ -26,14 +26,14 @@ files = [ [[package]] name = "asgiref" -version = "3.5.2" +version = "3.6.0" description = "ASGI specs, helper code, and adapters" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "asgiref-3.5.2-py3-none-any.whl", hash = "sha256:1d2880b792ae8757289136f1db2b7b99100ce959b2aa57fd69dab783d05afac4"}, - {file = "asgiref-3.5.2.tar.gz", hash = "sha256:4a29362a6acebe09bf1d6640db38c1dc3d9217c68e6f9f6204d72667fc19a424"}, + {file = "asgiref-3.6.0-py3-none-any.whl", hash = "sha256:71e68008da809b957b7ee4b43dbccff33d1b23519fb8344e33f049897077afac"}, + {file = "asgiref-3.6.0.tar.gz", hash = "sha256:9567dfe7bd8d3c8c892227827c41cce860b368104c3431da67a0c5a65a949506"}, ] [package.extras] @@ -53,32 +53,33 @@ files = [ [[package]] name = "attrs" -version = "22.1.0" +version = "22.2.0" description = "Classes Without Boilerplate" category = "dev" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" files = [ - {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, - {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, + {file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"}, + {file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"}, ] [package.extras] -dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"] -docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] -tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"] -tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] +cov = ["attrs[tests]", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"] +dev = ["attrs[docs,tests]"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope.interface"] +tests = ["attrs[tests-no-zope]", "zope.interface"] +tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"] [[package]] name = "babel" -version = "2.10.3" +version = "2.11.0" description = "Internationalization utilities" category = "dev" optional = false python-versions = ">=3.6" files = [ - {file = "Babel-2.10.3-py3-none-any.whl", hash = "sha256:ff56f4892c1c4bf0d814575ea23471c230d544203c7748e8c68f0089478d48eb"}, - {file = "Babel-2.10.3.tar.gz", hash = "sha256:7614553711ee97490f732126dc077f8d0ae084ebc6a96e23db1482afabdb2c51"}, + {file = "Babel-2.11.0-py3-none-any.whl", hash = "sha256:1ad3eca1c885218f6dce2ab67291178944f810a10a9b5f3cb8382a5a232b64fe"}, + {file = "Babel-2.11.0.tar.gz", hash = "sha256:5ef4b3226b0180dedded4229651c8b0e1a3a6a2837d45a073272f313e4cf97f6"}, ] [package.dependencies] @@ -115,33 +116,24 @@ tzdata = ["tzdata"] [[package]] name = "black" -version = "22.10.0" +version = "22.12.0" description = "The uncompromising code formatter." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "black-22.10.0-1fixedarch-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:5cc42ca67989e9c3cf859e84c2bf014f6633db63d1cbdf8fdb666dcd9e77e3fa"}, - {file = "black-22.10.0-1fixedarch-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:5d8f74030e67087b219b032aa33a919fae8806d49c867846bfacde57f43972ef"}, - {file = "black-22.10.0-1fixedarch-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:197df8509263b0b8614e1df1756b1dd41be6738eed2ba9e9769f3880c2b9d7b6"}, - {file = "black-22.10.0-1fixedarch-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:2644b5d63633702bc2c5f3754b1b475378fbbfb481f62319388235d0cd104c2d"}, - {file = "black-22.10.0-1fixedarch-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:e41a86c6c650bcecc6633ee3180d80a025db041a8e2398dcc059b3afa8382cd4"}, - {file = "black-22.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2039230db3c6c639bd84efe3292ec7b06e9214a2992cd9beb293d639c6402edb"}, - {file = "black-22.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14ff67aec0a47c424bc99b71005202045dc09270da44a27848d534600ac64fc7"}, - {file = "black-22.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:819dc789f4498ecc91438a7de64427c73b45035e2e3680c92e18795a839ebb66"}, - {file = "black-22.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5b9b29da4f564ba8787c119f37d174f2b69cdfdf9015b7d8c5c16121ddc054ae"}, - {file = "black-22.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8b49776299fece66bffaafe357d929ca9451450f5466e997a7285ab0fe28e3b"}, - {file = "black-22.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:21199526696b8f09c3997e2b4db8d0b108d801a348414264d2eb8eb2532e540d"}, - {file = "black-22.10.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e464456d24e23d11fced2bc8c47ef66d471f845c7b7a42f3bd77bf3d1789650"}, - {file = "black-22.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9311e99228ae10023300ecac05be5a296f60d2fd10fff31cf5c1fa4ca4b1988d"}, - {file = "black-22.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fba8a281e570adafb79f7755ac8721b6cf1bbf691186a287e990c7929c7692ff"}, - {file = "black-22.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:915ace4ff03fdfff953962fa672d44be269deb2eaf88499a0f8805221bc68c87"}, - {file = "black-22.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:444ebfb4e441254e87bad00c661fe32df9969b2bf224373a448d8aca2132b395"}, - {file = "black-22.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:974308c58d057a651d182208a484ce80a26dac0caef2895836a92dd6ebd725e0"}, - {file = "black-22.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72ef3925f30e12a184889aac03d77d031056860ccae8a1e519f6cbb742736383"}, - {file = "black-22.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:432247333090c8c5366e69627ccb363bc58514ae3e63f7fc75c54b1ea80fa7de"}, - {file = "black-22.10.0-py3-none-any.whl", hash = "sha256:c957b2b4ea88587b46cf49d1dc17681c1e672864fd7af32fc1e9664d572b3458"}, - {file = "black-22.10.0.tar.gz", hash = "sha256:f513588da599943e0cde4e32cc9879e825d58720d6557062d1098c5ad80080e1"}, + {file = "black-22.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d"}, + {file = "black-22.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351"}, + {file = "black-22.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f"}, + {file = "black-22.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:7412e75863aa5c5411886804678b7d083c7c28421210180d67dfd8cf1221e1f4"}, + {file = "black-22.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c116eed0efb9ff870ded8b62fe9f28dd61ef6e9ddd28d83d7d264a38417dcee2"}, + {file = "black-22.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1f58cbe16dfe8c12b7434e50ff889fa479072096d79f0a7f25e4ab8e94cd8350"}, + {file = "black-22.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d86c9f3db9b1bf6761244bc0b3572a546f5fe37917a044e02f3166d5aafa7d"}, + {file = "black-22.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:82d9fe8fee3401e02e79767016b4907820a7dc28d70d137eb397b92ef3cc5bfc"}, + {file = "black-22.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:101c69b23df9b44247bd88e1d7e90154336ac4992502d4197bdac35dd7ee3320"}, + {file = "black-22.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:559c7a1ba9a006226f09e4916060982fd27334ae1998e7a38b3f33a37f7a2148"}, + {file = "black-22.12.0-py3-none-any.whl", hash = "sha256:436cc9167dd28040ad90d3b404aec22cedf24a6e4d7de221bec2730ec0c97bcf"}, + {file = "black-22.12.0.tar.gz", hash = "sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f"}, ] [package.dependencies] @@ -177,18 +169,18 @@ wcwidth = ">=0.1.4" [[package]] name = "boto3" -version = "1.24.95" +version = "1.26.57" description = "The AWS SDK for Python" category = "main" optional = true python-versions = ">= 3.7" files = [ - {file = "boto3-1.24.95-py3-none-any.whl", hash = "sha256:05818ed61af104f28f039592c5c54d802a0398b1f158c2d485ec86352b48033f"}, - {file = "boto3-1.24.95.tar.gz", hash = "sha256:285d29042c1684f8fc68492ddf20180d28b94aac1f19dd7161bcad3067c01314"}, + {file = "boto3-1.26.57-py3-none-any.whl", hash = "sha256:f1f13bfcb34d2175cf6f515a632bc432e0b357e4ebee7d4efda7ab5ec2914ef2"}, + {file = "boto3-1.26.57.tar.gz", hash = "sha256:9c34ceac30a0672d2b6b030d459eb87f1a02d48f86f347fb4b054de85fb8a4b1"}, ] [package.dependencies] -botocore = ">=1.27.95,<1.28.0" +botocore = ">=1.29.57,<1.30.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.6.0,<0.7.0" @@ -197,14 +189,14 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.27.95" +version = "1.29.57" description = "Low-level, data-driven core of boto 3." category = "main" optional = true python-versions = ">= 3.7" files = [ - {file = "botocore-1.27.95-py3-none-any.whl", hash = "sha256:04ff12a8d1d0687a1f1c2dfad5b6fc9f5a81de4b639cf9c9e41fee9449680fd4"}, - {file = "botocore-1.27.95.tar.gz", hash = "sha256:0b90945aa7080179a0c4941a3809ce4df30792931e16b9b6ef3c739c4f2b7a59"}, + {file = "botocore-1.29.57-py3-none-any.whl", hash = "sha256:f43382babffc07645a084484b1f08fb9d3fa4744bb08b74065ae0b4b1f4103b6"}, + {file = "botocore-1.29.57.tar.gz", hash = "sha256:02078e37d6b3626794f821385f3357195d87610fa1b25355577ed5393f16f7b8"}, ] [package.dependencies] @@ -213,35 +205,118 @@ python-dateutil = ">=2.1,<3.0.0" urllib3 = ">=1.25.4,<1.27" [package.extras] -crt = ["awscrt (==0.14.0)"] +crt = ["awscrt (==0.15.3)"] [[package]] name = "certifi" -version = "2022.9.24" +version = "2022.12.7" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"}, - {file = "certifi-2022.9.24.tar.gz", hash = "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14"}, + {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"}, + {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, ] [[package]] name = "charset-normalizer" -version = "2.1.1" +version = "3.0.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." category = "main" optional = false -python-versions = ">=3.6.0" +python-versions = "*" files = [ - {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, - {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, + {file = "charset-normalizer-3.0.1.tar.gz", hash = "sha256:ebea339af930f8ca5d7a699b921106c6e29c617fe9606fa7baa043c1cdae326f"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88600c72ef7587fe1708fd242b385b6ed4b8904976d5da0893e31df8b3480cb6"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c75ffc45f25324e68ab238cb4b5c0a38cd1c3d7f1fb1f72b5541de469e2247db"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:db72b07027db150f468fbada4d85b3b2729a3db39178abf5c543b784c1254539"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62595ab75873d50d57323a91dd03e6966eb79c41fa834b7a1661ed043b2d404d"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ff6f3db31555657f3163b15a6b7c6938d08df7adbfc9dd13d9d19edad678f1e8"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:772b87914ff1152b92a197ef4ea40efe27a378606c39446ded52c8f80f79702e"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70990b9c51340e4044cfc394a81f614f3f90d41397104d226f21e66de668730d"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:292d5e8ba896bbfd6334b096e34bffb56161c81408d6d036a7dfa6929cff8783"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2edb64ee7bf1ed524a1da60cdcd2e1f6e2b4f66ef7c077680739f1641f62f555"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:31a9ddf4718d10ae04d9b18801bd776693487cbb57d74cc3458a7673f6f34639"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:44ba614de5361b3e5278e1241fda3dc1838deed864b50a10d7ce92983797fa76"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:12db3b2c533c23ab812c2b25934f60383361f8a376ae272665f8e48b88e8e1c6"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c512accbd6ff0270939b9ac214b84fb5ada5f0409c44298361b2f5e13f9aed9e"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-win32.whl", hash = "sha256:502218f52498a36d6bf5ea77081844017bf7982cdbe521ad85e64cabee1b608b"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:601f36512f9e28f029d9481bdaf8e89e5148ac5d89cffd3b05cd533eeb423b59"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0298eafff88c99982a4cf66ba2efa1128e4ddaca0b05eec4c456bbc7db691d8d"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a8d0fc946c784ff7f7c3742310cc8a57c5c6dc31631269876a88b809dbeff3d3"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:87701167f2a5c930b403e9756fab1d31d4d4da52856143b609e30a1ce7160f3c"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14e76c0f23218b8f46c4d87018ca2e441535aed3632ca134b10239dfb6dadd6b"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c0a590235ccd933d9892c627dec5bc7511ce6ad6c1011fdf5b11363022746c1"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c7fe7afa480e3e82eed58e0ca89f751cd14d767638e2550c77a92a9e749c317"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79909e27e8e4fcc9db4addea88aa63f6423ebb171db091fb4373e3312cb6d603"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ac7b6a045b814cf0c47f3623d21ebd88b3e8cf216a14790b455ea7ff0135d18"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:72966d1b297c741541ca8cf1223ff262a6febe52481af742036a0b296e35fa5a"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f9d0c5c045a3ca9bedfc35dca8526798eb91a07aa7a2c0fee134c6c6f321cbd7"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5995f0164fa7df59db4746112fec3f49c461dd6b31b841873443bdb077c13cfc"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4a8fcf28c05c1f6d7e177a9a46a1c52798bfe2ad80681d275b10dcf317deaf0b"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:761e8904c07ad053d285670f36dd94e1b6ab7f16ce62b9805c475b7aa1cffde6"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-win32.whl", hash = "sha256:71140351489970dfe5e60fc621ada3e0f41104a5eddaca47a7acb3c1b851d6d3"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:9ab77acb98eba3fd2a85cd160851816bfce6871d944d885febf012713f06659c"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:84c3990934bae40ea69a82034912ffe5a62c60bbf6ec5bc9691419641d7d5c9a"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74292fc76c905c0ef095fe11e188a32ebd03bc38f3f3e9bcb85e4e6db177b7ea"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c95a03c79bbe30eec3ec2b7f076074f4281526724c8685a42872974ef4d36b72"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c39b0e3eac288fedc2b43055cfc2ca7a60362d0e5e87a637beac5d801ef478"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df2c707231459e8a4028eabcd3cfc827befd635b3ef72eada84ab13b52e1574d"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93ad6d87ac18e2a90b0fe89df7c65263b9a99a0eb98f0a3d2e079f12a0735837"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:59e5686dd847347e55dffcc191a96622f016bc0ad89105e24c14e0d6305acbc6"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:cd6056167405314a4dc3c173943f11249fa0f1b204f8b51ed4bde1a9cd1834dc"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:083c8d17153ecb403e5e1eb76a7ef4babfc2c48d58899c98fcaa04833e7a2f9a"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:f5057856d21e7586765171eac8b9fc3f7d44ef39425f85dbcccb13b3ebea806c"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:7eb33a30d75562222b64f569c642ff3dc6689e09adda43a082208397f016c39a"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-win32.whl", hash = "sha256:95dea361dd73757c6f1c0a1480ac499952c16ac83f7f5f4f84f0658a01b8ef41"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:eaa379fcd227ca235d04152ca6704c7cb55564116f8bc52545ff357628e10602"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3e45867f1f2ab0711d60c6c71746ac53537f1684baa699f4f668d4c6f6ce8e14"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cadaeaba78750d58d3cc6ac4d1fd867da6fc73c88156b7a3212a3cd4819d679d"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:911d8a40b2bef5b8bbae2e36a0b103f142ac53557ab421dc16ac4aafee6f53dc"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:503e65837c71b875ecdd733877d852adbc465bd82c768a067badd953bf1bc5a3"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a60332922359f920193b1d4826953c507a877b523b2395ad7bc716ddd386d866"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16a8663d6e281208d78806dbe14ee9903715361cf81f6d4309944e4d1e59ac5b"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a16418ecf1329f71df119e8a65f3aa68004a3f9383821edcb20f0702934d8087"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9d9153257a3f70d5f69edf2325357251ed20f772b12e593f3b3377b5f78e7ef8"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:02a51034802cbf38db3f89c66fb5d2ec57e6fe7ef2f4a44d070a593c3688667b"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:2e396d70bc4ef5325b72b593a72c8979999aa52fb8bcf03f701c1b03e1166918"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:11b53acf2411c3b09e6af37e4b9005cba376c872503c8f28218c7243582df45d"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-win32.whl", hash = "sha256:0bf2dae5291758b6f84cf923bfaa285632816007db0330002fa1de38bfcb7154"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:2c03cc56021a4bd59be889c2b9257dae13bf55041a3372d3295416f86b295fb5"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:024e606be3ed92216e2b6952ed859d86b4cfa52cd5bc5f050e7dc28f9b43ec42"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4b0d02d7102dd0f997580b51edc4cebcf2ab6397a7edf89f1c73b586c614272c"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:358a7c4cb8ba9b46c453b1dd8d9e431452d5249072e4f56cfda3149f6ab1405e"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81d6741ab457d14fdedc215516665050f3822d3e56508921cc7239f8c8e66a58"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8b8af03d2e37866d023ad0ddea594edefc31e827fee64f8de5611a1dbc373174"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9cf4e8ad252f7c38dd1f676b46514f92dc0ebeb0db5552f5f403509705e24753"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e696f0dd336161fca9adbb846875d40752e6eba585843c768935ba5c9960722b"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c22d3fe05ce11d3671297dc8973267daa0f938b93ec716e12e0f6dee81591dc1"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:109487860ef6a328f3eec66f2bf78b0b72400280d8f8ea05f69c51644ba6521a"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:37f8febc8ec50c14f3ec9637505f28e58d4f66752207ea177c1d67df25da5aed"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:f97e83fa6c25693c7a35de154681fcc257c1c41b38beb0304b9c4d2d9e164479"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a152f5f33d64a6be73f1d30c9cc82dfc73cec6477ec268e7c6e4c7d23c2d2291"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:39049da0ffb96c8cbb65cbf5c5f3ca3168990adf3551bd1dee10c48fce8ae820"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-win32.whl", hash = "sha256:4457ea6774b5611f4bed5eaa5df55f70abde42364d498c5134b7ef4c6958e20e"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:e62164b50f84e20601c1ff8eb55620d2ad25fb81b59e3cd776a1902527a788af"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8eade758719add78ec36dc13201483f8e9b5d940329285edcd5f70c0a9edbd7f"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8499ca8f4502af841f68135133d8258f7b32a53a1d594aa98cc52013fff55678"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3fc1c4a2ffd64890aebdb3f97e1278b0cc72579a08ca4de8cd2c04799a3a22be"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00d3ffdaafe92a5dc603cb9bd5111aaa36dfa187c8285c543be562e61b755f6b"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2ac1b08635a8cd4e0cbeaf6f5e922085908d48eb05d44c5ae9eabab148512ca"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6f45710b4459401609ebebdbcfb34515da4fc2aa886f95107f556ac69a9147e"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ae1de54a77dc0d6d5fcf623290af4266412a7c4be0b1ff7444394f03f5c54e3"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b590df687e3c5ee0deef9fc8c547d81986d9a1b56073d82de008744452d6541"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab5de034a886f616a5668aa5d098af2b5385ed70142090e2a31bcbd0af0fdb3d"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9cb3032517f1627cc012dbc80a8ec976ae76d93ea2b5feaa9d2a5b8882597579"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:608862a7bf6957f2333fc54ab4399e405baad0163dc9f8d99cb236816db169d4"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0f438ae3532723fb6ead77e7c604be7c8374094ef4ee2c5e03a3a17f1fca256c"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:356541bf4381fa35856dafa6a965916e54bed415ad8a24ee6de6e37deccf2786"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-win32.whl", hash = "sha256:39cf9ed17fe3b1bc81f33c9ceb6ce67683ee7526e65fde1447c772afc54a1bb8"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:0a11e971ed097d24c534c037d298ad32c6ce81a45736d31e0ff0ad37ab437d59"}, + {file = "charset_normalizer-3.0.1-py3-none-any.whl", hash = "sha256:7e189e2e1d3ed2f4aebabd2d5b0f931e883676e51c7624826e0a4e5fe8a0bf24"}, ] -[package.extras] -unicode-backport = ["unicodedata2"] - [[package]] name = "click" version = "8.1.3" @@ -259,74 +334,75 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} [[package]] name = "colorama" -version = "0.4.5" +version = "0.4.6" description = "Cross-platform colored terminal text." category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ - {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, - {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] [[package]] name = "coverage" -version = "6.5.0" +version = "7.1.0" description = "Code coverage measurement for Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "coverage-6.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef8674b0ee8cc11e2d574e3e2998aea5df5ab242e012286824ea3c6970580e53"}, - {file = "coverage-6.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:784f53ebc9f3fd0e2a3f6a78b2be1bd1f5575d7863e10c6e12504f240fd06660"}, - {file = "coverage-6.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4a5be1748d538a710f87542f22c2cad22f80545a847ad91ce45e77417293eb4"}, - {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83516205e254a0cb77d2d7bb3632ee019d93d9f4005de31dca0a8c3667d5bc04"}, - {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af4fffaffc4067232253715065e30c5a7ec6faac36f8fc8d6f64263b15f74db0"}, - {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:97117225cdd992a9c2a5515db1f66b59db634f59d0679ca1fa3fe8da32749cae"}, - {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a1170fa54185845505fbfa672f1c1ab175446c887cce8212c44149581cf2d466"}, - {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:11b990d520ea75e7ee8dcab5bc908072aaada194a794db9f6d7d5cfd19661e5a"}, - {file = "coverage-6.5.0-cp310-cp310-win32.whl", hash = "sha256:5dbec3b9095749390c09ab7c89d314727f18800060d8d24e87f01fb9cfb40b32"}, - {file = "coverage-6.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:59f53f1dc5b656cafb1badd0feb428c1e7bc19b867479ff72f7a9dd9b479f10e"}, - {file = "coverage-6.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4a5375e28c5191ac38cca59b38edd33ef4cc914732c916f2929029b4bfb50795"}, - {file = "coverage-6.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ed2820d919351f4167e52425e096af41bfabacb1857186c1ea32ff9983ed75"}, - {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33a7da4376d5977fbf0a8ed91c4dffaaa8dbf0ddbf4c8eea500a2486d8bc4d7b"}, - {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8fb6cf131ac4070c9c5a3e21de0f7dc5a0fbe8bc77c9456ced896c12fcdad91"}, - {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a6b7d95969b8845250586f269e81e5dfdd8ff828ddeb8567a4a2eaa7313460c4"}, - {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1ef221513e6f68b69ee9e159506d583d31aa3567e0ae84eaad9d6ec1107dddaa"}, - {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cca4435eebea7962a52bdb216dec27215d0df64cf27fc1dd538415f5d2b9da6b"}, - {file = "coverage-6.5.0-cp311-cp311-win32.whl", hash = "sha256:98e8a10b7a314f454d9eff4216a9a94d143a7ee65018dd12442e898ee2310578"}, - {file = "coverage-6.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:bc8ef5e043a2af066fa8cbfc6e708d58017024dc4345a1f9757b329a249f041b"}, - {file = "coverage-6.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4433b90fae13f86fafff0b326453dd42fc9a639a0d9e4eec4d366436d1a41b6d"}, - {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4f05d88d9a80ad3cac6244d36dd89a3c00abc16371769f1340101d3cb899fc3"}, - {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94e2565443291bd778421856bc975d351738963071e9b8839ca1fc08b42d4bef"}, - {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:027018943386e7b942fa832372ebc120155fd970837489896099f5cfa2890f79"}, - {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:255758a1e3b61db372ec2736c8e2a1fdfaf563977eedbdf131de003ca5779b7d"}, - {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:851cf4ff24062c6aec510a454b2584f6e998cada52d4cb58c5e233d07172e50c"}, - {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:12adf310e4aafddc58afdb04d686795f33f4d7a6fa67a7a9d4ce7d6ae24d949f"}, - {file = "coverage-6.5.0-cp37-cp37m-win32.whl", hash = "sha256:b5604380f3415ba69de87a289a2b56687faa4fe04dbee0754bfcae433489316b"}, - {file = "coverage-6.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4a8dbc1f0fbb2ae3de73eb0bdbb914180c7abfbf258e90b311dcd4f585d44bd2"}, - {file = "coverage-6.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d900bb429fdfd7f511f868cedd03a6bbb142f3f9118c09b99ef8dc9bf9643c3c"}, - {file = "coverage-6.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2198ea6fc548de52adc826f62cb18554caedfb1d26548c1b7c88d8f7faa8f6ba"}, - {file = "coverage-6.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c4459b3de97b75e3bd6b7d4b7f0db13f17f504f3d13e2a7c623786289dd670e"}, - {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:20c8ac5386253717e5ccc827caad43ed66fea0efe255727b1053a8154d952398"}, - {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b07130585d54fe8dff3d97b93b0e20290de974dc8177c320aeaf23459219c0b"}, - {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dbdb91cd8c048c2b09eb17713b0c12a54fbd587d79adcebad543bc0cd9a3410b"}, - {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:de3001a203182842a4630e7b8d1a2c7c07ec1b45d3084a83d5d227a3806f530f"}, - {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e07f4a4a9b41583d6eabec04f8b68076ab3cd44c20bd29332c6572dda36f372e"}, - {file = "coverage-6.5.0-cp38-cp38-win32.whl", hash = "sha256:6d4817234349a80dbf03640cec6109cd90cba068330703fa65ddf56b60223a6d"}, - {file = "coverage-6.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:7ccf362abd726b0410bf8911c31fbf97f09f8f1061f8c1cf03dfc4b6372848f6"}, - {file = "coverage-6.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:633713d70ad6bfc49b34ead4060531658dc6dfc9b3eb7d8a716d5873377ab745"}, - {file = "coverage-6.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:95203854f974e07af96358c0b261f1048d8e1083f2de9b1c565e1be4a3a48cfc"}, - {file = "coverage-6.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9023e237f4c02ff739581ef35969c3739445fb059b060ca51771e69101efffe"}, - {file = "coverage-6.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:265de0fa6778d07de30bcf4d9dc471c3dc4314a23a3c6603d356a3c9abc2dfcf"}, - {file = "coverage-6.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f830ed581b45b82451a40faabb89c84e1a998124ee4212d440e9c6cf70083e5"}, - {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7b6be138d61e458e18d8e6ddcddd36dd96215edfe5f1168de0b1b32635839b62"}, - {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:42eafe6778551cf006a7c43153af1211c3aaab658d4d66fa5fcc021613d02518"}, - {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:723e8130d4ecc8f56e9a611e73b31219595baa3bb252d539206f7bbbab6ffc1f"}, - {file = "coverage-6.5.0-cp39-cp39-win32.whl", hash = "sha256:d9ecf0829c6a62b9b573c7bb6d4dcd6ba8b6f80be9ba4fc7ed50bf4ac9aecd72"}, - {file = "coverage-6.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:fc2af30ed0d5ae0b1abdb4ebdce598eafd5b35397d4d75deb341a614d333d987"}, - {file = "coverage-6.5.0-pp36.pp37.pp38-none-any.whl", hash = "sha256:1431986dac3923c5945271f169f59c45b8802a114c8f548d611f2015133df77a"}, - {file = "coverage-6.5.0.tar.gz", hash = "sha256:f642e90754ee3e06b0e7e51bce3379590e76b7f76b708e1a71ff043f87025c84"}, + {file = "coverage-7.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3b946bbcd5a8231383450b195cfb58cb01cbe7f8949f5758566b881df4b33baf"}, + {file = "coverage-7.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ec8e767f13be637d056f7e07e61d089e555f719b387a7070154ad80a0ff31801"}, + {file = "coverage-7.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4a5a5879a939cb84959d86869132b00176197ca561c664fc21478c1eee60d75"}, + {file = "coverage-7.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b643cb30821e7570c0aaf54feaf0bfb630b79059f85741843e9dc23f33aaca2c"}, + {file = "coverage-7.1.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32df215215f3af2c1617a55dbdfb403b772d463d54d219985ac7cd3bf124cada"}, + {file = "coverage-7.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:33d1ae9d4079e05ac4cc1ef9e20c648f5afabf1a92adfaf2ccf509c50b85717f"}, + {file = "coverage-7.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:29571503c37f2ef2138a306d23e7270687c0efb9cab4bd8038d609b5c2393a3a"}, + {file = "coverage-7.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:63ffd21aa133ff48c4dff7adcc46b7ec8b565491bfc371212122dd999812ea1c"}, + {file = "coverage-7.1.0-cp310-cp310-win32.whl", hash = "sha256:4b14d5e09c656de5038a3f9bfe5228f53439282abcab87317c9f7f1acb280352"}, + {file = "coverage-7.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:8361be1c2c073919500b6601220a6f2f98ea0b6d2fec5014c1d9cfa23dd07038"}, + {file = "coverage-7.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:da9b41d4539eefd408c46725fb76ecba3a50a3367cafb7dea5f250d0653c1040"}, + {file = "coverage-7.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5b15ed7644ae4bee0ecf74fee95808dcc34ba6ace87e8dfbf5cb0dc20eab45a"}, + {file = "coverage-7.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d12d076582507ea460ea2a89a8c85cb558f83406c8a41dd641d7be9a32e1274f"}, + {file = "coverage-7.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2617759031dae1bf183c16cef8fcfb3de7617f394c813fa5e8e46e9b82d4222"}, + {file = "coverage-7.1.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4e4881fa9e9667afcc742f0c244d9364d197490fbc91d12ac3b5de0bf2df146"}, + {file = "coverage-7.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9d58885215094ab4a86a6aef044e42994a2bd76a446dc59b352622655ba6621b"}, + {file = "coverage-7.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ffeeb38ee4a80a30a6877c5c4c359e5498eec095878f1581453202bfacc8fbc2"}, + {file = "coverage-7.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3baf5f126f30781b5e93dbefcc8271cb2491647f8283f20ac54d12161dff080e"}, + {file = "coverage-7.1.0-cp311-cp311-win32.whl", hash = "sha256:ded59300d6330be27bc6cf0b74b89ada58069ced87c48eaf9344e5e84b0072f7"}, + {file = "coverage-7.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:6a43c7823cd7427b4ed763aa7fb63901ca8288591323b58c9cd6ec31ad910f3c"}, + {file = "coverage-7.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7a726d742816cb3a8973c8c9a97539c734b3a309345236cd533c4883dda05b8d"}, + {file = "coverage-7.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc7c85a150501286f8b56bd8ed3aa4093f4b88fb68c0843d21ff9656f0009d6a"}, + {file = "coverage-7.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5b4198d85a3755d27e64c52f8c95d6333119e49fd001ae5798dac872c95e0f8"}, + {file = "coverage-7.1.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddb726cb861c3117a553f940372a495fe1078249ff5f8a5478c0576c7be12050"}, + {file = "coverage-7.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:51b236e764840a6df0661b67e50697aaa0e7d4124ca95e5058fa3d7cbc240b7c"}, + {file = "coverage-7.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7ee5c9bb51695f80878faaa5598040dd6c9e172ddcf490382e8aedb8ec3fec8d"}, + {file = "coverage-7.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c31b75ae466c053a98bf26843563b3b3517b8f37da4d47b1c582fdc703112bc3"}, + {file = "coverage-7.1.0-cp37-cp37m-win32.whl", hash = "sha256:3b155caf3760408d1cb903b21e6a97ad4e2bdad43cbc265e3ce0afb8e0057e73"}, + {file = "coverage-7.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2a60d6513781e87047c3e630b33b4d1e89f39836dac6e069ffee28c4786715f5"}, + {file = "coverage-7.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f2cba5c6db29ce991029b5e4ac51eb36774458f0a3b8d3137241b32d1bb91f06"}, + {file = "coverage-7.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:beeb129cacea34490ffd4d6153af70509aa3cda20fdda2ea1a2be870dfec8d52"}, + {file = "coverage-7.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c45948f613d5d18c9ec5eaa203ce06a653334cf1bd47c783a12d0dd4fd9c851"}, + {file = "coverage-7.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef382417db92ba23dfb5864a3fc9be27ea4894e86620d342a116b243ade5d35d"}, + {file = "coverage-7.1.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c7c0d0827e853315c9bbd43c1162c006dd808dbbe297db7ae66cd17b07830f0"}, + {file = "coverage-7.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e5cdbb5cafcedea04924568d990e20ce7f1945a1dd54b560f879ee2d57226912"}, + {file = "coverage-7.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9817733f0d3ea91bea80de0f79ef971ae94f81ca52f9b66500c6a2fea8e4b4f8"}, + {file = "coverage-7.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:218fe982371ac7387304153ecd51205f14e9d731b34fb0568181abaf7b443ba0"}, + {file = "coverage-7.1.0-cp38-cp38-win32.whl", hash = "sha256:04481245ef966fbd24ae9b9e537ce899ae584d521dfbe78f89cad003c38ca2ab"}, + {file = "coverage-7.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:8ae125d1134bf236acba8b83e74c603d1b30e207266121e76484562bc816344c"}, + {file = "coverage-7.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2bf1d5f2084c3932b56b962a683074a3692bce7cabd3aa023c987a2a8e7612f6"}, + {file = "coverage-7.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:98b85dd86514d889a2e3dd22ab3c18c9d0019e696478391d86708b805f4ea0fa"}, + {file = "coverage-7.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38da2db80cc505a611938d8624801158e409928b136c8916cd2e203970dde4dc"}, + {file = "coverage-7.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3164d31078fa9efe406e198aecd2a02d32a62fecbdef74f76dad6a46c7e48311"}, + {file = "coverage-7.1.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db61a79c07331e88b9a9974815c075fbd812bc9dbc4dc44b366b5368a2936063"}, + {file = "coverage-7.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ccb092c9ede70b2517a57382a601619d20981f56f440eae7e4d7eaafd1d1d09"}, + {file = "coverage-7.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:33ff26d0f6cc3ca8de13d14fde1ff8efe1456b53e3f0273e63cc8b3c84a063d8"}, + {file = "coverage-7.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d47dd659a4ee952e90dc56c97d78132573dc5c7b09d61b416a9deef4ebe01a0c"}, + {file = "coverage-7.1.0-cp39-cp39-win32.whl", hash = "sha256:d248cd4a92065a4d4543b8331660121b31c4148dd00a691bfb7a5cdc7483cfa4"}, + {file = "coverage-7.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:7ed681b0f8e8bcbbffa58ba26fcf5dbc8f79e7997595bf071ed5430d8c08d6f3"}, + {file = "coverage-7.1.0-pp37.pp38.pp39-none-any.whl", hash = "sha256:755e89e32376c850f826c425ece2c35a4fc266c081490eb0a841e7c1cb0d3bda"}, + {file = "coverage-7.1.0.tar.gz", hash = "sha256:10188fe543560ec4874f974b5305cd1a8bdcfa885ee00ea3a03733464c4ca265"}, ] [package.dependencies] @@ -337,47 +413,29 @@ toml = ["tomli"] [[package]] name = "croniter" -version = "1.3.7" +version = "1.3.8" description = "croniter provides iteration for datetime object with cron like format" category = "main" optional = true python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ - {file = "croniter-1.3.7-py2.py3-none-any.whl", hash = "sha256:12369c67e231c8ce5f98958d76ea6e8cb5b157fda4da7429d245a931e4ed411e"}, - {file = "croniter-1.3.7.tar.gz", hash = "sha256:72ef78d0f8337eb35393b8893ebfbfbeb340f2d2ae47e0d2d78130e34b0dd8b9"}, + {file = "croniter-1.3.8-py2.py3-none-any.whl", hash = "sha256:d6ed8386d5f4bbb29419dc1b65c4909c04a2322bd15ec0dc5b2877bfa1b75c7a"}, + {file = "croniter-1.3.8.tar.gz", hash = "sha256:32a5ec04e97ec0837bcdf013767abd2e71cceeefd3c2e14c804098ce51ad6cd9"}, ] [package.dependencies] python-dateutil = "*" -[[package]] -name = "deprecated" -version = "1.2.13" -description = "Python @deprecated decorator to deprecate old python classes, functions or methods." -category = "main" -optional = true -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "Deprecated-1.2.13-py2.py3-none-any.whl", hash = "sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d"}, - {file = "Deprecated-1.2.13.tar.gz", hash = "sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d"}, -] - -[package.dependencies] -wrapt = ">=1.10,<2" - -[package.extras] -dev = ["PyTest", "PyTest (<5)", "PyTest-Cov", "PyTest-Cov (<2.6)", "bump2version (<1)", "configparser (<5)", "importlib-metadata (<3)", "importlib-resources (<4)", "sphinx (<2)", "sphinxcontrib-websupport (<2)", "tox", "zipp (<2)"] - [[package]] name = "django" -version = "4.1.2" +version = "4.1.5" description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "Django-4.1.2-py3-none-any.whl", hash = "sha256:26dc24f99c8956374a054bcbf58aab8dc0cad2e6ac82b0fe036b752c00eee793"}, - {file = "Django-4.1.2.tar.gz", hash = "sha256:b8d843714810ab88d59344507d4447be8b2cf12a49031363b6eed9f1b9b2280f"}, + {file = "Django-4.1.5-py3-none-any.whl", hash = "sha256:4b214a05fe4c99476e99e2445c8b978c8369c18d4dea8e22ec412862715ad763"}, + {file = "Django-4.1.5.tar.gz", hash = "sha256:ff56ebd7ead0fd5dbe06fe157b0024a7aaea2e0593bb3785fb594cf94dad58ef"}, ] [package.dependencies] @@ -458,22 +516,23 @@ hiredis = ["redis[hiredis] (>=3,!=4.0.0,!=4.0.1)"] [[package]] name = "dnspython" -version = "2.2.1" +version = "2.3.0" description = "DNS toolkit" category = "main" optional = true -python-versions = ">=3.6,<4.0" +python-versions = ">=3.7,<4.0" files = [ - {file = "dnspython-2.2.1-py3-none-any.whl", hash = "sha256:a851e51367fb93e9e1361732c1d60dab63eff98712e503ea7d92e6eccb109b4f"}, - {file = "dnspython-2.2.1.tar.gz", hash = "sha256:0f7569a4a6ff151958b64304071d370daa3243d15941a7beedf0c9fe5105603e"}, + {file = "dnspython-2.3.0-py3-none-any.whl", hash = "sha256:89141536394f909066cabd112e3e1a37e4e654db00a25308b0f130bc3152eb46"}, + {file = "dnspython-2.3.0.tar.gz", hash = "sha256:224e32b03eb46be70e12ef6d64e0be123a64e621ab4c0822ff6d450d52a540b9"}, ] [package.extras] curio = ["curio (>=1.2,<2.0)", "sniffio (>=1.1,<2.0)"] -dnssec = ["cryptography (>=2.6,<37.0)"] -doh = ["h2 (>=4.1.0)", "httpx (>=0.21.1)", "requests (>=2.23.0,<3.0.0)", "requests-toolbelt (>=0.9.1,<0.10.0)"] +dnssec = ["cryptography (>=2.6,<40.0)"] +doh = ["h2 (>=4.1.0)", "httpx (>=0.21.1)", "requests (>=2.23.0,<3.0.0)", "requests-toolbelt (>=0.9.1,<0.11.0)"] +doq = ["aioquic (>=0.9.20)"] idna = ["idna (>=2.1,<4.0)"] -trio = ["trio (>=0.14,<0.20)"] +trio = ["trio (>=0.14,<0.23)"] wmi = ["wmi (>=1.5.1,<2.0.0)"] [[package]] @@ -499,55 +558,118 @@ files = [ {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"}, ] +[[package]] +name = "exceptiongroup" +version = "1.1.0" +description = "Backport of PEP 654 (exception groups)" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.1.0-py3-none-any.whl", hash = "sha256:327cbda3da756e2de031a3107b81ab7b3770a602c4d16ca618298c526f4bec1e"}, + {file = "exceptiongroup-1.1.0.tar.gz", hash = "sha256:bcb67d800a4497e1b404c2dd44fca47d3b7a5e5433dbab67f96c1a685cdfdf23"}, +] + +[package.extras] +test = ["pytest (>=6)"] + [[package]] name = "hiredis" -version = "2.0.0" +version = "2.1.1" description = "Python wrapper for hiredis" category = "main" optional = true -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "hiredis-2.0.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b4c8b0bc5841e578d5fb32a16e0c305359b987b850a06964bd5a62739d688048"}, - {file = "hiredis-2.0.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0adea425b764a08270820531ec2218d0508f8ae15a448568109ffcae050fee26"}, - {file = "hiredis-2.0.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:3d55e36715ff06cdc0ab62f9591607c4324297b6b6ce5b58cb9928b3defe30ea"}, - {file = "hiredis-2.0.0-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:5d2a48c80cf5a338d58aae3c16872f4d452345e18350143b3bf7216d33ba7b99"}, - {file = "hiredis-2.0.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:240ce6dc19835971f38caf94b5738092cb1e641f8150a9ef9251b7825506cb05"}, - {file = "hiredis-2.0.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:5dc7a94bb11096bc4bffd41a3c4f2b958257085c01522aa81140c68b8bf1630a"}, - {file = "hiredis-2.0.0-cp36-cp36m-win32.whl", hash = "sha256:139705ce59d94eef2ceae9fd2ad58710b02aee91e7fa0ccb485665ca0ecbec63"}, - {file = "hiredis-2.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:c39c46d9e44447181cd502a35aad2bb178dbf1b1f86cf4db639d7b9614f837c6"}, - {file = "hiredis-2.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:adf4dd19d8875ac147bf926c727215a0faf21490b22c053db464e0bf0deb0485"}, - {file = "hiredis-2.0.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:0f41827028901814c709e744060843c77e78a3aca1e0d6875d2562372fcb405a"}, - {file = "hiredis-2.0.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:508999bec4422e646b05c95c598b64bdbef1edf0d2b715450a078ba21b385bcc"}, - {file = "hiredis-2.0.0-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:0d5109337e1db373a892fdcf78eb145ffb6bbd66bb51989ec36117b9f7f9b579"}, - {file = "hiredis-2.0.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:04026461eae67fdefa1949b7332e488224eac9e8f2b5c58c98b54d29af22093e"}, - {file = "hiredis-2.0.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:a00514362df15af041cc06e97aebabf2895e0a7c42c83c21894be12b84402d79"}, - {file = "hiredis-2.0.0-cp37-cp37m-win32.whl", hash = "sha256:09004096e953d7ebd508cded79f6b21e05dff5d7361771f59269425108e703bc"}, - {file = "hiredis-2.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:f8196f739092a78e4f6b1b2172679ed3343c39c61a3e9d722ce6fcf1dac2824a"}, - {file = "hiredis-2.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:294a6697dfa41a8cba4c365dd3715abc54d29a86a40ec6405d677ca853307cfb"}, - {file = "hiredis-2.0.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:3dddf681284fe16d047d3ad37415b2e9ccdc6c8986c8062dbe51ab9a358b50a5"}, - {file = "hiredis-2.0.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:dcef843f8de4e2ff5e35e96ec2a4abbdf403bd0f732ead127bd27e51f38ac298"}, - {file = "hiredis-2.0.0-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:87c7c10d186f1743a8fd6a971ab6525d60abd5d5d200f31e073cd5e94d7e7a9d"}, - {file = "hiredis-2.0.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:7f0055f1809b911ab347a25d786deff5e10e9cf083c3c3fd2dd04e8612e8d9db"}, - {file = "hiredis-2.0.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:11d119507bb54e81f375e638225a2c057dda748f2b1deef05c2b1a5d42686048"}, - {file = "hiredis-2.0.0-cp38-cp38-win32.whl", hash = "sha256:7492af15f71f75ee93d2a618ca53fea8be85e7b625e323315169977fae752426"}, - {file = "hiredis-2.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:65d653df249a2f95673976e4e9dd7ce10de61cfc6e64fa7eeaa6891a9559c581"}, - {file = "hiredis-2.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ae8427a5e9062ba66fc2c62fb19a72276cf12c780e8db2b0956ea909c48acff5"}, - {file = "hiredis-2.0.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:3f5f7e3a4ab824e3de1e1700f05ad76ee465f5f11f5db61c4b297ec29e692b2e"}, - {file = "hiredis-2.0.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:e3447d9e074abf0e3cd85aef8131e01ab93f9f0e86654db7ac8a3f73c63706ce"}, - {file = "hiredis-2.0.0-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:8b42c0dc927b8d7c0eb59f97e6e34408e53bc489f9f90e66e568f329bff3e443"}, - {file = "hiredis-2.0.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:b84f29971f0ad4adaee391c6364e6f780d5aae7e9226d41964b26b49376071d0"}, - {file = "hiredis-2.0.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:0b39ec237459922c6544d071cdcf92cbb5bc6685a30e7c6d985d8a3e3a75326e"}, - {file = "hiredis-2.0.0-cp39-cp39-win32.whl", hash = "sha256:a7928283143a401e72a4fad43ecc85b35c27ae699cf5d54d39e1e72d97460e1d"}, - {file = "hiredis-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:a4ee8000454ad4486fb9f28b0cab7fa1cd796fc36d639882d0b34109b5b3aec9"}, - {file = "hiredis-2.0.0-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1f03d4dadd595f7a69a75709bc81902673fa31964c75f93af74feac2f134cc54"}, - {file = "hiredis-2.0.0-pp36-pypy36_pp73-manylinux1_x86_64.whl", hash = "sha256:04927a4c651a0e9ec11c68e4427d917e44ff101f761cd3b5bc76f86aaa431d27"}, - {file = "hiredis-2.0.0-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:a39efc3ade8c1fb27c097fd112baf09d7fd70b8cb10ef1de4da6efbe066d381d"}, - {file = "hiredis-2.0.0-pp36-pypy36_pp73-win32.whl", hash = "sha256:07bbf9bdcb82239f319b1f09e8ef4bdfaec50ed7d7ea51a56438f39193271163"}, - {file = "hiredis-2.0.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:807b3096205c7cec861c8803a6738e33ed86c9aae76cac0e19454245a6bbbc0a"}, - {file = "hiredis-2.0.0-pp37-pypy37_pp73-manylinux1_x86_64.whl", hash = "sha256:1233e303645f468e399ec906b6b48ab7cd8391aae2d08daadbb5cad6ace4bd87"}, - {file = "hiredis-2.0.0-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:cb2126603091902767d96bcb74093bd8b14982f41809f85c9b96e519c7e1dc41"}, - {file = "hiredis-2.0.0-pp37-pypy37_pp73-win32.whl", hash = "sha256:f52010e0a44e3d8530437e7da38d11fb822acfb0d5b12e9cd5ba655509937ca0"}, - {file = "hiredis-2.0.0.tar.gz", hash = "sha256:81d6d8e39695f2c37954d1011c0480ef7cf444d4e3ae24bc5e89ee5de360139a"}, + {file = "hiredis-2.1.1-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:f15e48545dadf3760220821d2f3c850e0c67bbc66aad2776c9d716e6216b5103"}, + {file = "hiredis-2.1.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b3a437e3af246dd06d116f1615cdf4e620e639dfcc923fe3045e00f6a967fc27"}, + {file = "hiredis-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b61732d75e2222a3b0060b97395df78693d5c3487fe4a5d0b75f6ac1affc68b9"}, + {file = "hiredis-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:170c2080966721b42c5a8726e91c5fc271300a4ac9ddf8a5b79856cfd47553e1"}, + {file = "hiredis-2.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d2d6e4caaffaf42faf14cfdf20b1d6fff6b557137b44e9569ea6f1877e6f375d"}, + {file = "hiredis-2.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d64b2d90302f0dd9e9ba43e89f8640f35b6d5968668da82ba2d2652b2cc3c3d2"}, + {file = "hiredis-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61fd1c55efb48ba734628f096e7a50baf0df3f18e91183face5c07fba3b4beb7"}, + {file = "hiredis-2.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfc5e923828714f314737e7f856b3dccf8805e5679fe23f07241b397cd785f6c"}, + {file = "hiredis-2.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ef2aa0485735c8608a92964e52ab9025ceb6003776184a1eb5d1701742cc910b"}, + {file = "hiredis-2.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2d39193900a03b900a25d474b9f787434f05a282b402f063d4ca02c62d61bdb9"}, + {file = "hiredis-2.1.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:4b51f5eb47e61c6b82cb044a1815903a77a4f840fa050fd2ff40d617c102d16c"}, + {file = "hiredis-2.1.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:d9145d011b74bef972b485a09f391babaa101626dbb54afc2313d5682a746593"}, + {file = "hiredis-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6f45509b43d720d64837c1211fcdea42acd48e71539b7152d74c16413ceea080"}, + {file = "hiredis-2.1.1-cp310-cp310-win32.whl", hash = "sha256:3a284bbf6503cd6ac1183b3542fe853a8be47fb52a631224f6dda46ba229d572"}, + {file = "hiredis-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:f60fad285db733b2badba43f7036a1241cb3e19c17260348f3ff702e6eaa4980"}, + {file = "hiredis-2.1.1-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:69c20816ac2af11701caf10e5b027fd33c6e8dfe7806ab71bc5191aa2a6d50f9"}, + {file = "hiredis-2.1.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:cd43dbaa73322a0c125122114cbc2c37141353b971751d05798f3b9780091e90"}, + {file = "hiredis-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c9632cd480fbc09c14622038a9a5f2f21ef6ce35892e9fa4df8d3308d3f2cedf"}, + {file = "hiredis-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:252d4a254f1566012b94e35cba577a001d3a732fa91e824d2076233222232cf9"}, + {file = "hiredis-2.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b901e68f3a6da279388e5dbe8d3bc562dd6dd3ff8a4b90e4f62e94de36461777"}, + {file = "hiredis-2.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f45f296998043345ecfc4f69a51fa4f3e80ca3659864df80b459095580968a6"}, + {file = "hiredis-2.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79f2acf237428dd61faa5b49247999ff68f45b3552c57303fcfabd2002eab249"}, + {file = "hiredis-2.1.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82bc6f5b92c9fcd5b5d6506000dd433006b126b193932c52a9bcc10dcc10e4fc"}, + {file = "hiredis-2.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:19843e4505069085301c3126c91b4e48970070fb242d7c617fb6777e83b55541"}, + {file = "hiredis-2.1.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c7336fddae533cbe786360d7a0316c71fe96313872c06cde20a969765202ab04"}, + {file = "hiredis-2.1.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:90b4355779970e121c219def3e35533ec2b24773a26fc4aa0f8271dd262fa2f2"}, + {file = "hiredis-2.1.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4beaac5047317a73b27cf15b4f4e0d2abaafa8378e1a6ed4cf9ff420d8f88aba"}, + {file = "hiredis-2.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7e25dc06e02689a45a49fa5e2f48bdfdbc11c5b52bef792a8cb37e0b82a7b0ae"}, + {file = "hiredis-2.1.1-cp311-cp311-win32.whl", hash = "sha256:f8b3233c1de155743ef34b0cae494e33befed5e0adba77762f5d8a8e417c5015"}, + {file = "hiredis-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:4ced076af04e28761d486501c58259247c1882fd19c7f94c18a257d143248eee"}, + {file = "hiredis-2.1.1-cp37-cp37m-macosx_10_12_x86_64.whl", hash = "sha256:f4300e063045e11ee79b79a7c9426813ab8d97e340b15843374093225dde407d"}, + {file = "hiredis-2.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b04b6c04fe13e1e30ba6f9340d3d0fb776a7e52611d11809fb59341871e050e5"}, + {file = "hiredis-2.1.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:436dcbbe3104737e8b4e2d63a019a764d107d72d6b6ee3cd107097c1c263fd1e"}, + {file = "hiredis-2.1.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:11801d9e96f39286ab558c6db940c39fc00150450ae1007d18b35437d2f79ad7"}, + {file = "hiredis-2.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7d8d0ca7b4f6136f8a29845d31cfbc3f562cbe71f26da6fca55aa4977e45a18"}, + {file = "hiredis-2.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c040af9eb9b12602b4b714b90a1c2ac1109e939498d47b0748ec33e7a948747"}, + {file = "hiredis-2.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f448146b86a8693dda5f02bb4cb2ef65c894db2cf743e7bf351978354ce685e3"}, + {file = "hiredis-2.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:649c5a1f0952af50f008f0bbec5f0b1e519150220c0a71ef80541a0c128d0c13"}, + {file = "hiredis-2.1.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b8e7415b0952b0dd6df3aa2d37b5191c85e54d6a0ac1449ddb1e9039bbb39fa5"}, + {file = "hiredis-2.1.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:38c1a56a30b953e3543662f950f498cfb17afed214b27f4fc497728fb623e0c9"}, + {file = "hiredis-2.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6050b519fb3b62d68a28a1941ae9dc5122e8820fef2b8e20a65cb3c1577332a0"}, + {file = "hiredis-2.1.1-cp37-cp37m-win32.whl", hash = "sha256:96add2a205efffe5e19a256a50be0ed78fcb5e9503242c65f57928e95cf4c901"}, + {file = "hiredis-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:8ceb101095f8cce9ac672ed7244b002d83ea97af7f27bb73f2fbe7fe8e8f03c7"}, + {file = "hiredis-2.1.1-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:9f068136e5119f2ba939ecd45c47b4e3cf6dd7ca9a65b6078c838029c5c1f564"}, + {file = "hiredis-2.1.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:8a42e246a03086ae1430f789e37d7192113db347417932745c4700d8999f853a"}, + {file = "hiredis-2.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5359811bfdb10fca234cba4629e555a1cde6c8136025395421f486ce43129ae3"}, + {file = "hiredis-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d304746e2163d3d2cbc4c08925539e00d2bb3edc9e79fce531b5468d4e264d15"}, + {file = "hiredis-2.1.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4fe297a52a8fc1204eef646bebf616263509d089d472e25742913924b1449099"}, + {file = "hiredis-2.1.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:637e563d5cbf79d8b04224f99cfce8001146647e7ce198f0b032e32e62079e3c"}, + {file = "hiredis-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39b61340ff2dcd99d5ded0ca5fc33c878d89a1426e2f7b6dbc7c7381e330bc8a"}, + {file = "hiredis-2.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66eaf6d5ea5207177ba8ffb9ee479eea743292267caf1d6b89b51cf9d5885d23"}, + {file = "hiredis-2.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4d2d0e458c32cdafd9a0f0b0aaeb61b169583d074287721eee740b730b7654bd"}, + {file = "hiredis-2.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8a92781e466f2f1f9d38720d8920cb094bc0d59f88219591bc12b1c12c9d471c"}, + {file = "hiredis-2.1.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:5560b09304ebaac5323a7402f5090f2a8559843200014f5adf1ff7517dd3805b"}, + {file = "hiredis-2.1.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4732a0bf877bbd69d4d1b38a3db2160252acb31894a48f324fd54f742f6b2123"}, + {file = "hiredis-2.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b5bd33ac8a572e2aa94b489dec35b0c00ca554b27e56ad19953e0bf2cbcf3ad8"}, + {file = "hiredis-2.1.1-cp38-cp38-win32.whl", hash = "sha256:07e86649773e486a21e170d1396217e15833776d9e8f4a7121c28a1d37e032c9"}, + {file = "hiredis-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:b964d81db8f11a99552621acd24c97381a0fd401a57187ce9f8cb9a53f4b6f4e"}, + {file = "hiredis-2.1.1-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:27e89e7befc785a273cccb105840db54b7f93005adf4e68c516d57b19ea2aac2"}, + {file = "hiredis-2.1.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:ea6f0f98e1721741b5bc3167a495a9f16459fe67648054be05365a67e67c29ba"}, + {file = "hiredis-2.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:40c34aeecccb9474999839299c9d2d5ff46a62ed47c58645b7965f48944abd74"}, + {file = "hiredis-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65927e75da4265ec88d06cbdab20113a9e69bbac3aea1ec053d4d940f1c88fc8"}, + {file = "hiredis-2.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:72cab67bcceb2e998da2f28aad9ec7b1a5ece5888f7ac3d3723cccba62338703"}, + {file = "hiredis-2.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d67429ff99231137491d8c3daa097c767a9c273bb03ac412ed8f6acb89e2e52f"}, + {file = "hiredis-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c596bce5e9dd379c68c17208716da2767bb6f6f2a71d748f9e4c247ced31e6"}, + {file = "hiredis-2.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e0aab2d6e60aa9f9e14c83396b4a58fb4aded712806486c79189bcae4a175ac"}, + {file = "hiredis-2.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:17deb7d218a5ae9f05d2b19d51936231546973303747924fc17a2869aef0029a"}, + {file = "hiredis-2.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d3d60e2af4ce93d6e45a50a9b5795156a8725495e411c7987a2f81ab14e99665"}, + {file = "hiredis-2.1.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:fbc960cd91e55e2281e1a330e7d1c4970b6a05567dd973c96e412b4d012e17c6"}, + {file = "hiredis-2.1.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0ae718e9db4b622072ff73d38bc9cd7711edfedc8a1e08efe25a6c8170446da4"}, + {file = "hiredis-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e51e3fa176fecd19660f898c4238232e8ca0f5709e6451a664c996f9aec1b8e1"}, + {file = "hiredis-2.1.1-cp39-cp39-win32.whl", hash = "sha256:0258bb84b4a1e015f14f891d91957042fa88f6f4e86cc0808d735ebbc1e3fc88"}, + {file = "hiredis-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:c5a47c964c58c044a323336a798d8729722e09865d7e087eb3512df6146b39a8"}, + {file = "hiredis-2.1.1-pp37-pypy37_pp73-macosx_10_12_x86_64.whl", hash = "sha256:8de0334c212e069d49952e476e16c6b42ba9677cc1e2d2f4588bd9a39489a3ab"}, + {file = "hiredis-2.1.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:653e33f69202c00eca35416ee23091447ad1e9f9a556cc2b715b2befcfc31b3c"}, + {file = "hiredis-2.1.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f14cccf931c859ba3169d766e892a3673a79649ec2ceca7ba95ea376b23fd222"}, + {file = "hiredis-2.1.1-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:86c56359fd7aca6a9ca41af91636aef15d5ad6d19e631ebd662f233c79f7e100"}, + {file = "hiredis-2.1.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:c2b197e3613c3aef3933b2c6eb095bd4be9c84022aea52057697b709b400c4bc"}, + {file = "hiredis-2.1.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ec060d6db9576f6723b5290448aea67160608556b5506eb947997d9d1ca6f7b7"}, + {file = "hiredis-2.1.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8781f5b91d75abef529a33cf3509ba5fe540d2814de0c4602f0f5ba6f1669739"}, + {file = "hiredis-2.1.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9bd6b934794bea92a15b10ac35889df63b28d2abf9d020a7c87c05dd9c6e1edd"}, + {file = "hiredis-2.1.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf6d85c1ffb4ec4a859b2f31cd8845e633f91ed971a3cce6f59a722dcc361b8c"}, + {file = "hiredis-2.1.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:bbf80c686e3f63d40b0ab42d3605d3b6d415c368a5d8a9764a314ebda6138650"}, + {file = "hiredis-2.1.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c1d85dfdf37a8df0e0174fc0c762b485b80a2fc7ce9592ae109aaf4a5d45ba9a"}, + {file = "hiredis-2.1.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:816b9ea96e7cc2496a1ac9c4a76db670827c1e31045cc377c66e64a20bb4b3ff"}, + {file = "hiredis-2.1.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db59afa0edf194bea782e4686bfc496fc1cea2e24f310d769641e343d14cc929"}, + {file = "hiredis-2.1.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c7a7e4ccec7164cdf2a9bbedc0e7430492eb56d9355a41377f40058c481bccc"}, + {file = "hiredis-2.1.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:646f150fa73f9cbc69419e34a1aae318c9f39bd9640760aa46624b2815da0c2d"}, + {file = "hiredis-2.1.1.tar.gz", hash = "sha256:21751e4b7737aaf7261a068758b22f7670155099592b28d8dde340bf6874313d"}, ] [[package]] @@ -576,34 +698,34 @@ files = [ [[package]] name = "importlib-metadata" -version = "5.0.0" +version = "6.0.0" description = "Read metadata from Python packages" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "importlib_metadata-5.0.0-py3-none-any.whl", hash = "sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43"}, - {file = "importlib_metadata-5.0.0.tar.gz", hash = "sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab"}, + {file = "importlib_metadata-6.0.0-py3-none-any.whl", hash = "sha256:7efb448ec9a5e313a57655d35aa54cd3e01b7e1fbcf72dce1bf06119420f5bad"}, + {file = "importlib_metadata-6.0.0.tar.gz", hash = "sha256:e354bedeb60efa6affdcc8ae121b73544a7aa74156d047311948f6d711cd378d"}, ] [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] [[package]] name = "iniconfig" -version = "1.1.1" -description = "iniconfig: brain-dead simple config-ini parsing" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.7" files = [ - {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, - {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] [[package]] @@ -638,19 +760,19 @@ iron_core = "*" [[package]] name = "isort" -version = "5.10.1" +version = "5.11.4" description = "A Python utility / library to sort Python imports." category = "dev" optional = false -python-versions = ">=3.6.1,<4.0" +python-versions = ">=3.7.0" files = [ - {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, - {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, + {file = "isort-5.11.4-py3-none-any.whl", hash = "sha256:c033fd0edb91000a7f09527fe5c75321878f98322a77ddcc81adbd83724afb7b"}, + {file = "isort-5.11.4.tar.gz", hash = "sha256:6db30c5ded9815d813932c04c2f85a360bcdd35fed496f4d8f35495ef0a261b6"}, ] [package.dependencies] -pip-api = {version = "*", optional = true, markers = "extra == \"requirements_deprecated_finder\""} -pipreqs = {version = "*", optional = true, markers = "extra == \"pipfile_deprecated_finder\" or extra == \"requirements_deprecated_finder\""} +pip-api = {version = "*", optional = true, markers = "extra == \"requirements-deprecated-finder\""} +pipreqs = {version = "*", optional = true, markers = "extra == \"pipfile-deprecated-finder\" or extra == \"requirements-deprecated-finder\""} [package.extras] colors = ["colorama (>=0.4.3,<0.5.0)"] @@ -705,52 +827,62 @@ files = [ [[package]] name = "markupsafe" -version = "2.1.1" +version = "2.1.2" description = "Safely add untrusted strings to HTML/XML markup." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-win32.whl", hash = "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-win32.whl", hash = "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-win32.whl", hash = "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-win32.whl", hash = "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"}, - {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:665a36ae6f8f20a4676b53224e33d456a6f5a72657d9c83c2aa00765072f31f7"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:340bea174e9761308703ae988e982005aedf427de816d1afe98147668cc03036"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22152d00bf4a9c7c83960521fc558f55a1adbc0631fbb00a9471e097b19d72e1"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28057e985dace2f478e042eaa15606c7efccb700797660629da387eb289b9323"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca244fa73f50a800cf8c3ebf7fd93149ec37f5cb9596aa8873ae2c1d23498601"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d9d971ec1e79906046aa3ca266de79eac42f1dbf3612a05dc9368125952bd1a1"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7e007132af78ea9df29495dbf7b5824cb71648d7133cf7848a2a5dd00d36f9ff"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7313ce6a199651c4ed9d7e4cfb4aa56fe923b1adf9af3b420ee14e6d9a73df65"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-win32.whl", hash = "sha256:c4a549890a45f57f1ebf99c067a4ad0cb423a05544accaf2b065246827ed9603"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:835fb5e38fd89328e9c81067fd642b3593c33e1e17e2fdbf77f5676abb14a156"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2ec4f2d48ae59bbb9d1f9d7efb9236ab81429a764dedca114f5fdabbc3788013"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608e7073dfa9e38a85d38474c082d4281f4ce276ac0010224eaba11e929dd53a"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65608c35bfb8a76763f37036547f7adfd09270fbdbf96608be2bead319728fcd"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2bfb563d0211ce16b63c7cb9395d2c682a23187f54c3d79bfec33e6705473c6"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da25303d91526aac3672ee6d49a2f3db2d9502a4a60b55519feb1a4c7714e07d"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9cad97ab29dfc3f0249b483412c85c8ef4766d96cdf9dcf5a1e3caa3f3661cf1"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:085fd3201e7b12809f9e6e9bc1e5c96a368c8523fad5afb02afe3c051ae4afcc"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1bea30e9bf331f3fef67e0a3877b2288593c98a21ccb2cf29b74c581a4eb3af0"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-win32.whl", hash = "sha256:7df70907e00c970c60b9ef2938d894a9381f38e6b9db73c5be35e59d92e06625"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:e55e40ff0cc8cc5c07996915ad367fa47da6b3fc091fdadca7f5403239c5fec3"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a6e40afa7f45939ca356f348c8e23048e02cb109ced1eb8420961b2f40fb373a"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf877ab4ed6e302ec1d04952ca358b381a882fbd9d1b07cccbfd61783561f98a"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63ba06c9941e46fa389d389644e2d8225e0e3e5ebcc4ff1ea8506dce646f8c8a"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1cd098434e83e656abf198f103a8207a8187c0fc110306691a2e94a78d0abb2"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:55f44b440d491028addb3b88f72207d71eeebfb7b5dbf0643f7c023ae1fba619"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a6f2fcca746e8d5910e18782f976489939d54a91f9411c32051b4aab2bd7c513"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0b462104ba25f1ac006fdab8b6a01ebbfbce9ed37fd37fd4acd70c67c973e460"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-win32.whl", hash = "sha256:7668b52e102d0ed87cb082380a7e2e1e78737ddecdde129acadb0eccc5423859"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6d6607f98fcf17e534162f0709aaad3ab7a96032723d8ac8750ffe17ae5a0666"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a806db027852538d2ad7555b203300173dd1b77ba116de92da9afbc3a3be3eed"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a4abaec6ca3ad8660690236d11bfe28dfd707778e2442b45addd2f086d6ef094"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f03a532d7dee1bed20bc4884194a16160a2de9ffc6354b3878ec9682bb623c54"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cf06cdc1dda95223e9d2d3c58d3b178aa5dacb35ee7e3bbac10e4e1faacb419"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22731d79ed2eb25059ae3df1dfc9cb1546691cc41f4e3130fe6bfbc3ecbbecfa"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f8ffb705ffcf5ddd0e80b65ddf7bed7ee4f5a441ea7d3419e861a12eaf41af58"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8db032bf0ce9022a8e41a22598eefc802314e81b879ae093f36ce9ddf39ab1ba"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2298c859cfc5463f1b64bd55cb3e602528db6fa0f3cfd568d3605c50678f8f03"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-win32.whl", hash = "sha256:50c42830a633fa0cf9e7d27664637532791bfc31c731a87b202d2d8ac40c3ea2"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:bb06feb762bade6bf3c8b844462274db0c76acc95c52abe8dbed28ae3d44a147"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:99625a92da8229df6d44335e6fcc558a5037dd0a760e11d84be2260e6f37002f"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8bca7e26c1dd751236cfb0c6c72d4ad61d986e9a41bbf76cb445f69488b2a2bd"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40627dcf047dadb22cd25ea7ecfe9cbf3bbbad0482ee5920b582f3809c97654f"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40dfd3fefbef579ee058f139733ac336312663c6706d1163b82b3003fb1925c4"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:090376d812fb6ac5f171e5938e82e7f2d7adc2b629101cec0db8b267815c85e2"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2e7821bffe00aa6bd07a23913b7f4e01328c3d5cc0b40b36c0bd81d362faeb65"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c0a33bc9f02c2b17c3ea382f91b4db0e6cde90b63b296422a939886a7a80de1c"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b8526c6d437855442cdd3d87eede9c425c4445ea011ca38d937db299382e6fa3"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-win32.whl", hash = "sha256:137678c63c977754abe9086a3ec011e8fd985ab90631145dfb9294ad09c102a7"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:0576fe974b40a400449768941d5d0858cc624e3249dfd1e0c33674e5c7ca7aed"}, + {file = "MarkupSafe-2.1.2.tar.gz", hash = "sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d"}, ] [[package]] @@ -767,41 +899,38 @@ files = [ [[package]] name = "packaging" -version = "21.3" +version = "23.0" description = "Core utilities for Python packages" -category = "main" +category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, - {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, + {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"}, + {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, ] -[package.dependencies] -pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" - [[package]] name = "pathspec" -version = "0.10.1" +version = "0.11.0" description = "Utility library for gitignore style pattern matching of file paths." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pathspec-0.10.1-py3-none-any.whl", hash = "sha256:46846318467efc4556ccfd27816e004270a9eeeeb4d062ce5e6fc7a87c573f93"}, - {file = "pathspec-0.10.1.tar.gz", hash = "sha256:7ace6161b621d31e7902eb6b5ae148d12cfd23f4a249b9ffb6b9fee12084323d"}, + {file = "pathspec-0.11.0-py3-none-any.whl", hash = "sha256:3a66eb970cbac598f9e5ccb5b2cf58930cd8e3ed86d393d541eaf2d8b1705229"}, + {file = "pathspec-0.11.0.tar.gz", hash = "sha256:64d338d4e0914e91c1792321e6907b5a593f1ab1851de7fc269557a21b30ebbc"}, ] [[package]] name = "pip" -version = "22.3" +version = "22.3.1" description = "The PyPA recommended tool for installing Python packages." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pip-22.3-py3-none-any.whl", hash = "sha256:1daab4b8d3b97d1d763caeb01a4640a2250a0ea899e257b1e44b9eded91e15ab"}, - {file = "pip-22.3.tar.gz", hash = "sha256:8182aec21dad6c0a49a2a3d121a87cd524b950e0b6092b181625f07ebdde7530"}, + {file = "pip-22.3.1-py3-none-any.whl", hash = "sha256:908c78e6bc29b676ede1c4d57981d490cb892eb45cd8c214ab6298125119e077"}, + {file = "pip-22.3.1.tar.gz", hash = "sha256:65fd48317359f3af8e593943e6ae1506b66325085ea64b706a998c6e83eeaf38"}, ] [[package]] @@ -837,19 +966,19 @@ yarg = "*" [[package]] name = "platformdirs" -version = "2.5.2" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +version = "2.6.2" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, - {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, + {file = "platformdirs-2.6.2-py3-none-any.whl", hash = "sha256:83c8f6d04389165de7c9b6f0c682439697887bca0aa2f1c87ef1826be3584490"}, + {file = "platformdirs-2.6.2.tar.gz", hash = "sha256:e1fea1fe471b9ff8332e229df3cb7de4f53eeea4998d3b6bfff542115e998bd2"}, ] [package.extras] -docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx (>=4)", "sphinx-autodoc-typehints (>=1.12)"] -test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] +docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] [[package]] name = "pluggy" @@ -869,75 +998,41 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "psutil" -version = "5.9.3" +version = "5.9.4" description = "Cross-platform lib for process and system monitoring in Python." category = "main" optional = true python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ - {file = "psutil-5.9.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:b4a247cd3feaae39bb6085fcebf35b3b8ecd9b022db796d89c8f05067ca28e71"}, - {file = "psutil-5.9.3-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:5fa88e3d5d0b480602553d362c4b33a63e0c40bfea7312a7bf78799e01e0810b"}, - {file = "psutil-5.9.3-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:767ef4fa33acda16703725c0473a91e1832d296c37c63896c7153ba81698f1ab"}, - {file = "psutil-5.9.3-cp27-cp27m-win32.whl", hash = "sha256:9a4af6ed1094f867834f5f07acd1250605a0874169a5fcadbcec864aec2496a6"}, - {file = "psutil-5.9.3-cp27-cp27m-win_amd64.whl", hash = "sha256:fa5e32c7d9b60b2528108ade2929b115167fe98d59f89555574715054f50fa31"}, - {file = "psutil-5.9.3-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:fe79b4ad4836e3da6c4650cb85a663b3a51aef22e1a829c384e18fae87e5e727"}, - {file = "psutil-5.9.3-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:db8e62016add2235cc87fb7ea000ede9e4ca0aa1f221b40cef049d02d5d2593d"}, - {file = "psutil-5.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:941a6c2c591da455d760121b44097781bc970be40e0e43081b9139da485ad5b7"}, - {file = "psutil-5.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:71b1206e7909792d16933a0d2c1c7f04ae196186c51ba8567abae1d041f06dcb"}, - {file = "psutil-5.9.3-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f57d63a2b5beaf797b87024d018772439f9d3103a395627b77d17a8d72009543"}, - {file = "psutil-5.9.3-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7507f6c7b0262d3e7b0eeda15045bf5881f4ada70473b87bc7b7c93b992a7d7"}, - {file = "psutil-5.9.3-cp310-cp310-win32.whl", hash = "sha256:1b540599481c73408f6b392cdffef5b01e8ff7a2ac8caae0a91b8222e88e8f1e"}, - {file = "psutil-5.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:547ebb02031fdada635452250ff39942db8310b5c4a8102dfe9384ee5791e650"}, - {file = "psutil-5.9.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d8c3cc6bb76492133474e130a12351a325336c01c96a24aae731abf5a47fe088"}, - {file = "psutil-5.9.3-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07d880053c6461c9b89cd5d4808f3b8336665fa3acdefd6777662c5ed73a851a"}, - {file = "psutil-5.9.3-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e8b50241dd3c2ed498507f87a6602825073c07f3b7e9560c58411c14fe1e1c9"}, - {file = "psutil-5.9.3-cp36-cp36m-win32.whl", hash = "sha256:828c9dc9478b34ab96be75c81942d8df0c2bb49edbb481f597314d92b6441d89"}, - {file = "psutil-5.9.3-cp36-cp36m-win_amd64.whl", hash = "sha256:ed15edb14f52925869250b1375f0ff58ca5c4fa8adefe4883cfb0737d32f5c02"}, - {file = "psutil-5.9.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d266cd05bd4a95ca1c2b9b5aac50d249cf7c94a542f47e0b22928ddf8b80d1ef"}, - {file = "psutil-5.9.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e4939ff75149b67aef77980409f156f0082fa36accc475d45c705bb00c6c16a"}, - {file = "psutil-5.9.3-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68fa227c32240c52982cb931801c5707a7f96dd8927f9102d6c7771ea1ff5698"}, - {file = "psutil-5.9.3-cp37-cp37m-win32.whl", hash = "sha256:beb57d8a1ca0ae0eb3d08ccaceb77e1a6d93606f0e1754f0d60a6ebd5c288837"}, - {file = "psutil-5.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:12500d761ac091f2426567f19f95fd3f15a197d96befb44a5c1e3cbe6db5752c"}, - {file = "psutil-5.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ba38cf9984d5462b506e239cf4bc24e84ead4b1d71a3be35e66dad0d13ded7c1"}, - {file = "psutil-5.9.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:46907fa62acaac364fff0b8a9da7b360265d217e4fdeaca0a2397a6883dffba2"}, - {file = "psutil-5.9.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a04a1836894c8279e5e0a0127c0db8e198ca133d28be8a2a72b4db16f6cf99c1"}, - {file = "psutil-5.9.3-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a4e07611997acf178ad13b842377e3d8e9d0a5bac43ece9bfc22a96735d9a4f"}, - {file = "psutil-5.9.3-cp38-cp38-win32.whl", hash = "sha256:6ced1ad823ecfa7d3ce26fe8aa4996e2e53fb49b7fed8ad81c80958501ec0619"}, - {file = "psutil-5.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:35feafe232d1aaf35d51bd42790cbccb882456f9f18cdc411532902370d660df"}, - {file = "psutil-5.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:538fcf6ae856b5e12d13d7da25ad67f02113c96f5989e6ad44422cb5994ca7fc"}, - {file = "psutil-5.9.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a3d81165b8474087bb90ec4f333a638ccfd1d69d34a9b4a1a7eaac06648f9fbe"}, - {file = "psutil-5.9.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a7826e68b0cf4ce2c1ee385d64eab7d70e3133171376cac53d7c1790357ec8f"}, - {file = "psutil-5.9.3-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ec296f565191f89c48f33d9544d8d82b0d2af7dd7d2d4e6319f27a818f8d1cc"}, - {file = "psutil-5.9.3-cp39-cp39-win32.whl", hash = "sha256:9ec95df684583b5596c82bb380c53a603bb051cf019d5c849c47e117c5064395"}, - {file = "psutil-5.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:4bd4854f0c83aa84a5a40d3b5d0eb1f3c128f4146371e03baed4589fe4f3c931"}, - {file = "psutil-5.9.3.tar.gz", hash = "sha256:7ccfcdfea4fc4b0a02ca2c31de7fcd186beb9cff8207800e14ab66f79c773af6"}, + {file = "psutil-5.9.4-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c1ca331af862803a42677c120aff8a814a804e09832f166f226bfd22b56feee8"}, + {file = "psutil-5.9.4-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:68908971daf802203f3d37e78d3f8831b6d1014864d7a85937941bb35f09aefe"}, + {file = "psutil-5.9.4-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:3ff89f9b835100a825b14c2808a106b6fdcc4b15483141482a12c725e7f78549"}, + {file = "psutil-5.9.4-cp27-cp27m-win32.whl", hash = "sha256:852dd5d9f8a47169fe62fd4a971aa07859476c2ba22c2254d4a1baa4e10b95ad"}, + {file = "psutil-5.9.4-cp27-cp27m-win_amd64.whl", hash = "sha256:9120cd39dca5c5e1c54b59a41d205023d436799b1c8c4d3ff71af18535728e94"}, + {file = "psutil-5.9.4-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6b92c532979bafc2df23ddc785ed116fced1f492ad90a6830cf24f4d1ea27d24"}, + {file = "psutil-5.9.4-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:efeae04f9516907be44904cc7ce08defb6b665128992a56957abc9b61dca94b7"}, + {file = "psutil-5.9.4-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:54d5b184728298f2ca8567bf83c422b706200bcbbfafdc06718264f9393cfeb7"}, + {file = "psutil-5.9.4-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16653106f3b59386ffe10e0bad3bb6299e169d5327d3f187614b1cb8f24cf2e1"}, + {file = "psutil-5.9.4-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54c0d3d8e0078b7666984e11b12b88af2db11d11249a8ac8920dd5ef68a66e08"}, + {file = "psutil-5.9.4-cp36-abi3-win32.whl", hash = "sha256:149555f59a69b33f056ba1c4eb22bb7bf24332ce631c44a319cec09f876aaeff"}, + {file = "psutil-5.9.4-cp36-abi3-win_amd64.whl", hash = "sha256:fd8522436a6ada7b4aad6638662966de0d61d241cb821239b2ae7013d41a43d4"}, + {file = "psutil-5.9.4-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:6001c809253a29599bc0dfd5179d9f8a5779f9dffea1da0f13c53ee568115e1e"}, + {file = "psutil-5.9.4.tar.gz", hash = "sha256:3d7f9739eb435d4b1338944abe23f49584bde5395f27487d2ee25ad9a8774a62"}, ] [package.extras] test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] -[[package]] -name = "py" -version = "1.11.0" -description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -files = [ - {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, - {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, -] - [[package]] name = "pygments" -version = "2.13.0" +version = "2.14.0" description = "Pygments is a syntax highlighting package written in Python." category = "dev" optional = false python-versions = ">=3.6" files = [ - {file = "Pygments-2.13.0-py3-none-any.whl", hash = "sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42"}, - {file = "Pygments-2.13.0.tar.gz", hash = "sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1"}, + {file = "Pygments-2.14.0-py3-none-any.whl", hash = "sha256:fa7bd7bd2771287c0de303af8bfdfc731f51bd2c6a47ab69d117138893b82717"}, + {file = "Pygments-2.14.0.tar.gz", hash = "sha256:b3ed06a9e8ac9a9aae5a6f5dbe78a8a58655d17b43b93c078f094ddc476ae297"}, ] [package.extras] @@ -945,86 +1040,86 @@ plugins = ["importlib-metadata"] [[package]] name = "pymongo" -version = "4.3.2" +version = "4.3.3" description = "Python driver for MongoDB " category = "main" optional = true python-versions = ">=3.7" files = [ - {file = "pymongo-4.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:68320e5326e2b1e49dcd901e6dcbe3009b8a0fd0da0c618579a2be7cf5f2d7be"}, - {file = "pymongo-4.3.2-cp310-cp310-manylinux1_i686.whl", hash = "sha256:3f41781c8310fe1ae3ed0b809e2d7be6ebba9f0954c08e1d18ac443916b82b29"}, - {file = "pymongo-4.3.2-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:372307185d8e17ea31d2f3ff6943e213a6c379ccf547f18b05a58a1620d6f92a"}, - {file = "pymongo-4.3.2-cp310-cp310-manylinux2014_i686.whl", hash = "sha256:1be15568e4b2be4c75bc54a542276c857628e09cbc283befcf4c45a0a22c1eec"}, - {file = "pymongo-4.3.2-cp310-cp310-manylinux2014_ppc64le.whl", hash = "sha256:cad31512e6956c95210fbd585d5b80df28425251260387164c6382894f0c6eca"}, - {file = "pymongo-4.3.2-cp310-cp310-manylinux2014_s390x.whl", hash = "sha256:b510843ea70e5bc9c096a93f683b28e8d43f1ad89da0126502d88b3d90f07ebe"}, - {file = "pymongo-4.3.2-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:253faefea46482ffa87c77fdd01cd95d430cc84aae8d7a78ba920ea6cebcf3c7"}, - {file = "pymongo-4.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a06c9ca15a2133478d1c775c4e7e5e782961b6254a3fc81ab5d0fb3cf9b8e358"}, - {file = "pymongo-4.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5231eb29e8174509250bc5fc609d6e8eceebfb209bf37bd6e014cbd7b6554344"}, - {file = "pymongo-4.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:178ffaa833d473b16fbd65c4a485af56484a50e2a201e8d0547f98cf5007f133"}, - {file = "pymongo-4.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95f41c4e3b9e315655d6d1136d904ceda24fe5ea2d273ec6f9d66dbef06f3446"}, - {file = "pymongo-4.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:352bc034e112c9f6a408e2796e74bae900d3167a804224b2c24ea75b5d57e9f9"}, - {file = "pymongo-4.3.2-cp310-cp310-win32.whl", hash = "sha256:28ab644adc92c21a249570e2d677ebf4f2ef374630ddec98f19d2630dcb154c6"}, - {file = "pymongo-4.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:6049927b50c39e7dc51e75b5bb30c8501fbf1f08414b3447bcc9f9f967c116ed"}, - {file = "pymongo-4.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:77436db17ab2baec2356cf38db32d13c7cd11267c8137864c67391f2dfdcc5e4"}, - {file = "pymongo-4.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cefd851fdea191fc4db780157a28a11e0a80bccd34c454a73f252a287d28b2c7"}, - {file = "pymongo-4.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7c22ad464688a807bec103734cbdf712489c74d439cdd346e6f12095070bfbf5"}, - {file = "pymongo-4.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:db94b741dde2cc44ec038495d041c8f6dd4d510bb4e5d0be1b9f9aae4fbb28c6"}, - {file = "pymongo-4.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21e1cfa3e73cd253afcad32e2a46a277f52553635ccc0dd4d643f5824af88428"}, - {file = "pymongo-4.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5db3bddbbc2657aa76088e76d24a616aefc98883c48dc27f3c3829ddb2ca10d"}, - {file = "pymongo-4.3.2-cp311-cp311-win32.whl", hash = "sha256:006799ddba1f2e73ce27689f016791ab80e51876c52ae2265d8c76016baaa10e"}, - {file = "pymongo-4.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:0c8f061eabef3a6b3696f7f7be3eaed7928864ff84a2248429f9c7eb564343cc"}, - {file = "pymongo-4.3.2-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:80bdfc7039674c670e1afbf95849ce2075731785527eeac7e3850e862dec239b"}, - {file = "pymongo-4.3.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:8d81f6f5f6e66481aadd2fc087a937833312de23cd94b5ea1b225f35fafb0a00"}, - {file = "pymongo-4.3.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:02140c1a9f2107a16c074c9e558a556faafb0dc3c2e9332c6685c5506823ab9d"}, - {file = "pymongo-4.3.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b4b683a40cf07b6d16704ead92a7aee24208d3af83d55d31248cdac003f8591c"}, - {file = "pymongo-4.3.2-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:dab1d89f969046057be2b904a7bbf40df114f43aebfb3ccdceb054d9c40ec56d"}, - {file = "pymongo-4.3.2-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:0f48c2562a1d1426b6db7567511dc62817df43357041e1fd4ea5c68278bfa11b"}, - {file = "pymongo-4.3.2-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:ce14598b8fa93e51aed0f400e446fddd6b26297ba5965fd0c0585614b60b9fc0"}, - {file = "pymongo-4.3.2-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:af46f635513c7339419374f46f4f662cee7140bfb86de4377885a2c1de2278d4"}, - {file = "pymongo-4.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96483316a799923f13bb61170f05feab22e8bd8630bf8cdcd440c78f307039a"}, - {file = "pymongo-4.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:07f58d05d2289f93e16ddc93be6e0453fa67afd33c1b015f6bd3d9741c0963ff"}, - {file = "pymongo-4.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8817b17db2013354aa7f187d5825d65da0d7720b5ca697af37ff5efdf97e7f62"}, - {file = "pymongo-4.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36e7a74bdab9aa19f5ac94dfd74111d2164ccea752afbef0aa039d1266e7c404"}, - {file = "pymongo-4.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6db95d3e955aa5dbe42db691dd77cdddc0bc15f9883aa1def51f3ca40d49c1d6"}, - {file = "pymongo-4.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aee8fafea8bb669deb0dd4878d947f79b2ef298e60f06e1fe799598929b68be2"}, - {file = "pymongo-4.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cea32bd14d8c0725e22e5fcc607a81e3636650c689697c12423a34f9a125c7e2"}, - {file = "pymongo-4.3.2-cp37-cp37m-win32.whl", hash = "sha256:3966dcba4b80dbc0eb4dd08d6f7127e3b1701cd829b6c13507a956c878b78546"}, - {file = "pymongo-4.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6461d29a967e1980ba7798e4da8178dbe4245fe4a66ebb3aa07339c9da383c3a"}, - {file = "pymongo-4.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b36da8aeb95cc1abea7b80e578fb6bcdbe395638d16b1b0068bc121e2111a00f"}, - {file = "pymongo-4.3.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:315fe5f628e9aee67cc4c17b91ddf08c5c0917b764f433a5acf9aed33164a8f0"}, - {file = "pymongo-4.3.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:07e05784578bf7f8ecdfc6d0fd1e684e6259e9b5fdb5439a58c4f0df950fae29"}, - {file = "pymongo-4.3.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:f84b8428a41d7d7f2931762c27b09ffa8b3bc51e3b5dab40ab2b1d008091247e"}, - {file = "pymongo-4.3.2-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:39308580bcdbc368a2664c48761226c06b1d3368cc3ab3492d3cca88dc2e5e27"}, - {file = "pymongo-4.3.2-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:7f907daec92208d748db4ea04568aa33e9254e0c27e4e40ac287e1b1ca8b12b5"}, - {file = "pymongo-4.3.2-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:cb47ba9c19da8fb4174f9d7bbbdb1796ad288c61dda35c96fb45d69e61d3a5cb"}, - {file = "pymongo-4.3.2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:0d7ad2112a705e992ca0cca98ccbb874276c495f8d9df627438c2ee94f810a3d"}, - {file = "pymongo-4.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4082d1b660e70d9df71da00050f7adb902b73a2287216e69ada124bd2f89636"}, - {file = "pymongo-4.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:26dd79e60f883b6467b91c8af0be484147365b18cebf9248f8e72c035aecb693"}, - {file = "pymongo-4.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:715ad027daff84e213ab74fa3ec98cad8dabb669653a71daa0dd6f80a1c32dd0"}, - {file = "pymongo-4.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ceded83530f5507dadd873f8d004b56f996de44d9c3f56b7f26c22ca823f12ee"}, - {file = "pymongo-4.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8f968621d019ed165f1cb5b037875ce3425ea7704407234895c7c52ad32190da"}, - {file = "pymongo-4.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4f7763c9e37e6d59406ce2defc25266980b24a86708ec6db753b02459db45715"}, - {file = "pymongo-4.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:f3861081540e1f06d1e5d131d1419b9fc507834b6865407e0f56735b4082566c"}, - {file = "pymongo-4.3.2-cp38-cp38-win32.whl", hash = "sha256:7424b7c59b16e7889a720a5b2e2dda518753c6fec6c6582ab2fcedf97df3df75"}, - {file = "pymongo-4.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:64b010681019c0b312f342e3aae1f3091a7dc7ff4b7a3dec72fc0e7238be9477"}, - {file = "pymongo-4.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cc7b269af274ac0d5d9a5c8d035b03ccc34438baa01705bf8ec7cc6a31093ace"}, - {file = "pymongo-4.3.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:68213f4c1531b95dcfef40f79dd95e94484f69ec5949b7f42f82ad2bee135f7f"}, - {file = "pymongo-4.3.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:11630f5b3287375c85f5b7a788d3a7241671af24fda2b49a3396bc53cbf1c0c6"}, - {file = "pymongo-4.3.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:35e9eec45a212306143367b0702c2aff75c375290015af00fa8b653641c20b34"}, - {file = "pymongo-4.3.2-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:94639935caf13af551429bd13e4cb20e7c110a57d07f0c6a84a9bf3c2c9000ad"}, - {file = "pymongo-4.3.2-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:7ce5d43c011e03cd1a42a4dcc0d5c8772f18533cdfe672a63607942d62581df4"}, - {file = "pymongo-4.3.2-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:98fd65c2aee7a55615dda1a1b0340ae8d756151983cb5040ea59a730083221e7"}, - {file = "pymongo-4.3.2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:c8e82d6cc2f1cf5017485f55d67375bacf73d95c40903759e46024a987bab86f"}, - {file = "pymongo-4.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab7f49c5ca3db7ae94743b0da1b21c5e7402a561a0614c1b0fba718aad591611"}, - {file = "pymongo-4.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:404bc7f7190e8975f41f0c7498e303e9cb291f6384e1889ac4333448652a83d6"}, - {file = "pymongo-4.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2c821c897498e3e3c3254f7a90195f71473361f502201fd396281869d8108857"}, - {file = "pymongo-4.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6498ae9a76ad64617703373a43e3cd8454271bca0d7d395b393b4f31aa68f734"}, - {file = "pymongo-4.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b2a8b2b7d9196d46e5181f88632eeca5bf79a69ca2e9911229c58f66aebfbeb"}, - {file = "pymongo-4.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f423e066de040f4f93dcac0e6ceec37ffc25cc591a609ecc3ab20adfdbb787ae"}, - {file = "pymongo-4.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:04597a5d877a984b5e3059e942b02d68f8af9bb4328592abca27e82015560112"}, - {file = "pymongo-4.3.2-cp39-cp39-win32.whl", hash = "sha256:53dd2c034fb92c019e5e581cd361ed3fa9833abb56cc76725d56dcba169746fe"}, - {file = "pymongo-4.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:d7bdfac2f3c87d0971691f2a091427f55bb6b94b23d74213ed2de87d8facba85"}, - {file = "pymongo-4.3.2.tar.gz", hash = "sha256:95913659d6c5fc714e662533d014836c988cc1561684f07b6a0a8343651afa66"}, + {file = "pymongo-4.3.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:74731c9e423c93cbe791f60c27030b6af6a948cef67deca079da6cd1bb583a8e"}, + {file = "pymongo-4.3.3-cp310-cp310-manylinux1_i686.whl", hash = "sha256:66413c50d510e5bcb0afc79880d1693a2185bcea003600ed898ada31338c004e"}, + {file = "pymongo-4.3.3-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:9b87b23570565a6ddaa9244d87811c2ee9cffb02a753c8a2da9c077283d85845"}, + {file = "pymongo-4.3.3-cp310-cp310-manylinux2014_i686.whl", hash = "sha256:695939036a320f4329ccf1627edefbbb67cc7892b8222d297b0dd2313742bfee"}, + {file = "pymongo-4.3.3-cp310-cp310-manylinux2014_ppc64le.whl", hash = "sha256:ffcc8394123ea8d43fff8e5d000095fe7741ce3f8988366c5c919c4f5eb179d3"}, + {file = "pymongo-4.3.3-cp310-cp310-manylinux2014_s390x.whl", hash = "sha256:943f208840777f34312c103a2d1caab02d780c4e9be26b3714acf6c4715ba7e1"}, + {file = "pymongo-4.3.3-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:01f7cbe88d22440b6594c955e37312d932fd632ffed1a86d0c361503ca82cc9d"}, + {file = "pymongo-4.3.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdb87309de97c63cb9a69132e1cb16be470e58cffdfbad68fdd1dc292b22a840"}, + {file = "pymongo-4.3.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d86c35d94b5499689354ccbc48438a79f449481ee6300f3e905748edceed78e7"}, + {file = "pymongo-4.3.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a966d5304b7d90c45c404914e06bbf02c5bf7e99685c6c12f0047ef2aa837142"}, + {file = "pymongo-4.3.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be1d2ce7e269215c3ee9a215e296b7a744aff4f39233486d2c4d77f5f0c561a6"}, + {file = "pymongo-4.3.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:55b6163dac53ef1e5d834297810c178050bd0548a4136cd4e0f56402185916ca"}, + {file = "pymongo-4.3.3-cp310-cp310-win32.whl", hash = "sha256:dc0cff74cd36d7e1edba91baa09622c35a8a57025f2f2b7a41e3f83b1db73186"}, + {file = "pymongo-4.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:cafa52873ae12baa512a8721afc20de67a36886baae6a5f394ddef0ce9391f91"}, + {file = "pymongo-4.3.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:599d3f6fbef31933b96e2d906b0f169b3371ff79ea6aaf6ecd76c947a3508a3d"}, + {file = "pymongo-4.3.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0640b4e9d008e13956b004d1971a23377b3d45491f87082161c92efb1e6c0d6"}, + {file = "pymongo-4.3.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:341221e2f2866a5960e6f8610f4cbac0bb13097f3b1a289aa55aba984fc0d969"}, + {file = "pymongo-4.3.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7fac06a539daef4fcf5d8288d0d21b412f9b750454cd5a3cf90484665db442a"}, + {file = "pymongo-4.3.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3a51901066696c4af38c6c63a1f0aeffd5e282367ff475de8c191ec9609b56d"}, + {file = "pymongo-4.3.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3055510fdfdb1775bc8baa359783022f70bb553f2d46e153c094dfcb08578ff"}, + {file = "pymongo-4.3.3-cp311-cp311-win32.whl", hash = "sha256:524d78673518dcd352a91541ecd2839c65af92dc883321c2109ef6e5cd22ef23"}, + {file = "pymongo-4.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:b8a03af1ce79b902a43f5f694c4ca8d92c2a4195db0966f08f266549e2fc49bc"}, + {file = "pymongo-4.3.3-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:39b03045c71f761aee96a12ebfbc2f4be89e724ff6f5e31c2574c1a0e2add8bd"}, + {file = "pymongo-4.3.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6fcfbf435eebf8a1765c6d1f46821740ebe9f54f815a05c8fc30d789ef43cb12"}, + {file = "pymongo-4.3.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:7d43ac9c7eeda5100fb0a7152fab7099c9cf9e5abd3bb36928eb98c7d7a339c6"}, + {file = "pymongo-4.3.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:3b93043b14ba7eb08c57afca19751658ece1cfa2f0b7b1fb5c7a41452fbb8482"}, + {file = "pymongo-4.3.3-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:c09956606c08c4a7c6178a04ba2dd9388fcc5db32002ade9c9bc865ab156ab6d"}, + {file = "pymongo-4.3.3-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:b0cfe925610f2fd59555bb7fc37bd739e4b197d33f2a8b2fae7b9c0c6640318c"}, + {file = "pymongo-4.3.3-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:4d00b91c77ceb064c9b0459f0d6ea5bfdbc53ea9e17cf75731e151ef25a830c7"}, + {file = "pymongo-4.3.3-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:c6258a3663780ae47ba73d43eb63c79c40ffddfb764e09b56df33be2f9479837"}, + {file = "pymongo-4.3.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c29e758f0e734e1e90357ae01ec9c6daf19ff60a051192fe110d8fb25c62600e"}, + {file = "pymongo-4.3.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12f3621a46cdc7a9ba8080422262398a91762a581d27e0647746588d3f995c88"}, + {file = "pymongo-4.3.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:47f7aa217b25833cd6f0e72b0d224be55393c2692b4f5e0561cb3beeb10296e9"}, + {file = "pymongo-4.3.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c2fdc855149efe7cdcc2a01ca02bfa24761c640203ea94df467f3baf19078be"}, + {file = "pymongo-4.3.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5effd87c7d363890259eac16c56a4e8da307286012c076223997f8cc4a8c435b"}, + {file = "pymongo-4.3.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6dd1cf2995fdbd64fc0802313e8323f5fa18994d51af059b5b8862b73b5e53f0"}, + {file = "pymongo-4.3.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:bb869707d8e30645ed6766e44098600ca6cdf7989c22a3ea2b7966bb1d98d4b2"}, + {file = "pymongo-4.3.3-cp37-cp37m-win32.whl", hash = "sha256:49210feb0be8051a64d71691f0acbfbedc33e149f0a5d6e271fddf6a12493fed"}, + {file = "pymongo-4.3.3-cp37-cp37m-win_amd64.whl", hash = "sha256:54c377893f2cbbffe39abcff5ff2e917b082c364521fa079305f6f064e1a24a9"}, + {file = "pymongo-4.3.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c184ec5be465c0319440734491e1aa4709b5f3ba75fdfc9dbbc2ae715a7f6829"}, + {file = "pymongo-4.3.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:dca34367a4e77fcab0693e603a959878eaf2351585e7d752cac544bc6b2dee46"}, + {file = "pymongo-4.3.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cd6a4afb20fb3c26a7bfd4611a0bbb24d93cbd746f5eb881f114b5e38fd55501"}, + {file = "pymongo-4.3.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:0c466710871d0026c190fc4141e810cf9d9affbf4935e1d273fbdc7d7cda6143"}, + {file = "pymongo-4.3.3-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:d07d06dba5b5f7d80f9cc45501456e440f759fe79f9895922ed486237ac378a8"}, + {file = "pymongo-4.3.3-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:711bc52cb98e7892c03e9b669bebd89c0a890a90dbc6d5bb2c47f30239bac6e9"}, + {file = "pymongo-4.3.3-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:34b040e095e1671df0c095ec0b04fc4ebb19c4c160f87c2b55c079b16b1a6b00"}, + {file = "pymongo-4.3.3-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:4ed00f96e147f40b565fe7530d1da0b0f3ab803d5dd5b683834500fa5d195ec4"}, + {file = "pymongo-4.3.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef888f48eb9203ee1e04b9fb27429017b290fb916f1e7826c2f7808c88798394"}, + {file = "pymongo-4.3.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:316498b642c00401370b2156b5233b256f9b33799e0a8d9d0b8a7da217a20fca"}, + {file = "pymongo-4.3.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fa7e202feb683dad74f00dea066690448d0cfa310f8a277db06ec8eb466601b5"}, + {file = "pymongo-4.3.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52896e22115c97f1c829db32aa2760b0d61839cfe08b168c2b1d82f31dbc5f55"}, + {file = "pymongo-4.3.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c051fe37c96b9878f37fa58906cb53ecd13dcb7341d3a85f1e2e2f6b10782d9"}, + {file = "pymongo-4.3.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5134d33286c045393c7beb51be29754647cec5ebc051cf82799c5ce9820a2ca2"}, + {file = "pymongo-4.3.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a9c2885b4a8e6e39db5662d8b02ca6dcec796a45e48c2de12552841f061692ba"}, + {file = "pymongo-4.3.3-cp38-cp38-win32.whl", hash = "sha256:a6cd6f1db75eb07332bd3710f58f5fce4967eadbf751bad653842750a61bda62"}, + {file = "pymongo-4.3.3-cp38-cp38-win_amd64.whl", hash = "sha256:d5571b6978750601f783cea07fb6b666837010ca57e5cefa389c1d456f6222e2"}, + {file = "pymongo-4.3.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:81d1a7303bd02ca1c5be4aacd4db73593f573ba8e0c543c04c6da6275fd7a47e"}, + {file = "pymongo-4.3.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:016c412118e1c23fef3a1eada4f83ae6e8844fd91986b2e066fc1b0013cdd9ae"}, + {file = "pymongo-4.3.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:8fd6e191b92a10310f5a6cfe10d6f839d79d192fb02480bda325286bd1c7b385"}, + {file = "pymongo-4.3.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:e2961b05f9c04a53da8bfc72f1910b6aec7205fcf3ac9c036d24619979bbee4b"}, + {file = "pymongo-4.3.3-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:b38a96b3eed8edc515b38257f03216f382c4389d022a8834667e2bc63c0c0c31"}, + {file = "pymongo-4.3.3-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:c1a70c51da9fa95bd75c167edb2eb3f3c4d27bc4ddd29e588f21649d014ec0b7"}, + {file = "pymongo-4.3.3-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:8a06a0c02f5606330e8f2e2f3b7949877ca7e4024fa2bff5a4506bec66c49ec7"}, + {file = "pymongo-4.3.3-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:6c2216d8b6a6d019c6f4b1ad55f890e5e77eb089309ffc05b6911c09349e7474"}, + {file = "pymongo-4.3.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eac0a143ef4f28f49670bf89cb15847eb80b375d55eba401ca2f777cd425f338"}, + {file = "pymongo-4.3.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:08fc250b5552ee97ceeae0f52d8b04f360291285fc7437f13daa516ce38fdbc6"}, + {file = "pymongo-4.3.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704d939656e21b073bfcddd7228b29e0e8a93dd27b54240eaafc0b9a631629a6"}, + {file = "pymongo-4.3.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1074f1a6f23e28b983c96142f2d45be03ec55d93035b471c26889a7ad2365db3"}, + {file = "pymongo-4.3.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b16250238de8dafca225647608dddc7bbb5dce3dd53b4d8e63c1cc287394c2f"}, + {file = "pymongo-4.3.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7761cacb8745093062695b11574effea69db636c2fd0a9269a1f0183712927b4"}, + {file = "pymongo-4.3.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:fd7bb378d82b88387dc10227cfd964f6273eb083e05299e9b97cbe075da12d11"}, + {file = "pymongo-4.3.3-cp39-cp39-win32.whl", hash = "sha256:dc24d245026a72d9b4953729d31813edd4bd4e5c13622d96e27c284942d33f24"}, + {file = "pymongo-4.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:fc28e8d85d392a06434e9a934908d97e2cf453d69488d2bcd0bfb881497fd975"}, + {file = "pymongo-4.3.3.tar.gz", hash = "sha256:34e95ffb0a68bffbc3b437f2d1f25fc916fef3df5cdeed0992da5f42fae9b807"}, ] [package.dependencies] @@ -1032,47 +1127,32 @@ dnspython = ">=1.16.0,<3.0.0" [package.extras] aws = ["pymongo-auth-aws (<2.0.0)"] -encryption = ["pymongocrypt (>=1.3.0,<2.0.0)"] +encryption = ["pymongo-auth-aws (<2.0.0)", "pymongocrypt (>=1.3.0,<2.0.0)"] gssapi = ["pykerberos"] ocsp = ["certifi", "pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)"] snappy = ["python-snappy"] zstd = ["zstandard"] -[[package]] -name = "pyparsing" -version = "3.0.9" -description = "pyparsing module - Classes and methods to define and execute parsing grammars" -category = "main" -optional = false -python-versions = ">=3.6.8" -files = [ - {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, - {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, -] - -[package.extras] -diagrams = ["jinja2", "railroad-diagrams"] - [[package]] name = "pytest" -version = "7.1.3" +version = "7.2.1" description = "pytest: simple powerful testing with Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.1.3-py3-none-any.whl", hash = "sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7"}, - {file = "pytest-7.1.3.tar.gz", hash = "sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39"}, + {file = "pytest-7.2.1-py3-none-any.whl", hash = "sha256:c7c6ca206e93355074ae32f7403e8ea12163b1163c976fee7d4d84027c162be5"}, + {file = "pytest-7.2.1.tar.gz", hash = "sha256:d45e0952f3727241918b8fd0f376f5ff6b301cc0777c6f9a556935c92d8a7d42"}, ] [package.dependencies] attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" -py = ">=1.8.2" -tomli = ">=1.0.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] @@ -1132,32 +1212,30 @@ six = ">=1.5" [[package]] name = "pytz" -version = "2022.5" +version = "2022.7.1" description = "World timezone definitions, modern and historical" category = "dev" optional = false python-versions = "*" files = [ - {file = "pytz-2022.5-py2.py3-none-any.whl", hash = "sha256:335ab46900b1465e714b4fda4963d87363264eb662aab5e65da039c25f1f5b22"}, - {file = "pytz-2022.5.tar.gz", hash = "sha256:c4d88f472f54d615e9cd582a5004d1e5f624854a6a27a6211591c251f22a6914"}, + {file = "pytz-2022.7.1-py2.py3-none-any.whl", hash = "sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a"}, + {file = "pytz-2022.7.1.tar.gz", hash = "sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0"}, ] [[package]] name = "redis" -version = "4.3.4" +version = "4.4.2" description = "Python client for Redis database and key-value store" category = "main" optional = true -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "redis-4.3.4-py3-none-any.whl", hash = "sha256:a52d5694c9eb4292770084fa8c863f79367ca19884b329ab574d5cb2036b3e54"}, - {file = "redis-4.3.4.tar.gz", hash = "sha256:ddf27071df4adf3821c4f2ca59d67525c3a82e5f268bed97b813cb4fabf87880"}, + {file = "redis-4.4.2-py3-none-any.whl", hash = "sha256:e6206448e2f8a432871d07d432c13ed6c2abcf6b74edb436c99752b1371be387"}, + {file = "redis-4.4.2.tar.gz", hash = "sha256:a010f6cb7378065040a02839c3f75c7e0fb37a87116fb4a95be82a95552776c7"}, ] [package.dependencies] async-timeout = ">=4.0.2" -deprecated = ">=1.2.3" -packaging = ">=20.4" [package.extras] hiredis = ["hiredis (>=1.0.0)"] @@ -1165,19 +1243,19 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)" [[package]] name = "requests" -version = "2.28.1" +version = "2.28.2" description = "Python HTTP for Humans." category = "main" optional = false python-versions = ">=3.7, <4" files = [ - {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, - {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, + {file = "requests-2.28.2-py3-none-any.whl", hash = "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa"}, + {file = "requests-2.28.2.tar.gz", hash = "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"}, ] [package.dependencies] certifi = ">=2017.4.17" -charset-normalizer = ">=2,<3" +charset-normalizer = ">=2,<4" idna = ">=2.5,<4" urllib3 = ">=1.21.1,<1.27" @@ -1220,14 +1298,14 @@ crt = ["botocore[crt] (>=1.20.29,<2.0a.0)"] [[package]] name = "sentry-sdk" -version = "1.10.0" +version = "1.14.0" description = "Python client for Sentry (https://sentry.io)" category = "main" optional = true python-versions = "*" files = [ - {file = "sentry-sdk-1.10.0.tar.gz", hash = "sha256:1b965bcdbfe52321bb1307c7c93c74035afdbfceb5f585f01a963327c5befc4e"}, - {file = "sentry_sdk-1.10.0-py2.py3-none-any.whl", hash = "sha256:8c648e96e0e2ec5e17ca75a28c442e2f523453fa7cf761ec093f4a656153490e"}, + {file = "sentry-sdk-1.14.0.tar.gz", hash = "sha256:273fe05adf052b40fd19f6d4b9a5556316807246bd817e5e3482930730726bb0"}, + {file = "sentry_sdk-1.14.0-py2.py3-none-any.whl", hash = "sha256:72c00322217d813cf493fe76590b23a757e063ff62fec59299f4af7201dd4448"}, ] [package.dependencies] @@ -1245,13 +1323,16 @@ falcon = ["falcon (>=1.4)"] fastapi = ["fastapi (>=0.79.0)"] flask = ["blinker (>=1.1)", "flask (>=0.11)"] httpx = ["httpx (>=0.16.0)"] +opentelemetry = ["opentelemetry-distro (>=0.35b0)"] pure-eval = ["asttokens", "executing", "pure-eval"] +pymongo = ["pymongo (>=3.1)"] pyspark = ["pyspark (>=2.4.4)"] quart = ["blinker (>=1.1)", "quart (>=0.16.1)"] rq = ["rq (>=0.6)"] sanic = ["sanic (>=0.8)"] sqlalchemy = ["sqlalchemy (>=1.2)"] starlette = ["starlette (>=0.19.1)"] +starlite = ["starlite (>=1.48)"] tornado = ["tornado (>=5)"] [[package]] @@ -1401,14 +1482,14 @@ test = ["cython", "html5lib", "pytest", "pytest-cov", "typed-ast"] [[package]] name = "sphinxcontrib-applehelp" -version = "1.0.2" -description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books" +version = "1.0.4" +description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" category = "dev" optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" files = [ - {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"}, - {file = "sphinxcontrib_applehelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a"}, + {file = "sphinxcontrib-applehelp-1.0.4.tar.gz", hash = "sha256:828f867945bbe39817c210a1abfd1bc4895c8b73fcaade56d45357a348a07d7e"}, + {file = "sphinxcontrib_applehelp-1.0.4-py3-none-any.whl", hash = "sha256:29d341f67fb0f6f586b23ad80e072c8e6ad0b48417db2bde114a4c9746feb228"}, ] [package.extras] @@ -1532,26 +1613,26 @@ files = [ [[package]] name = "tzdata" -version = "2022.5" +version = "2022.7" description = "Provider of IANA time zone data" category = "main" optional = false python-versions = ">=2" files = [ - {file = "tzdata-2022.5-py2.py3-none-any.whl", hash = "sha256:323161b22b7802fdc78f20ca5f6073639c64f1a7227c40cd3e19fd1d0ce6650a"}, - {file = "tzdata-2022.5.tar.gz", hash = "sha256:e15b2b3005e2546108af42a0eb4ccab4d9e225e2dfbf4f77aad50c70a4b1f3ab"}, + {file = "tzdata-2022.7-py2.py3-none-any.whl", hash = "sha256:2b88858b0e3120792a3c0635c23daf36a7d7eeeca657c323da299d2094402a0d"}, + {file = "tzdata-2022.7.tar.gz", hash = "sha256:fe5f866eddd8b96e9fcba978f8e503c909b19ea7efda11e52e39494bad3a7bfa"}, ] [[package]] name = "urllib3" -version = "1.26.12" +version = "1.26.14" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ - {file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"}, - {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"}, + {file = "urllib3-1.26.14-py2.py3-none-any.whl", hash = "sha256:75edcdc2f7d85b137124a6c3c9fc3933cdeaa12ecb9a6a959f22797a0feca7e1"}, + {file = "urllib3-1.26.14.tar.gz", hash = "sha256:076907bf8fd355cde77728471316625a4d2f7e713c125f51953bb5b3eecf4f72"}, ] [package.extras] @@ -1561,88 +1642,14 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "wcwidth" -version = "0.2.5" +version = "0.2.6" description = "Measures the displayed width of unicode strings in a terminal" category = "main" optional = true python-versions = "*" files = [ - {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, - {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, -] - -[[package]] -name = "wrapt" -version = "1.14.1" -description = "Module for decorators, wrappers and monkey patching." -category = "main" -optional = true -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -files = [ - {file = "wrapt-1.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3"}, - {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef"}, - {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28"}, - {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59"}, - {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87"}, - {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1"}, - {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b"}, - {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462"}, - {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1"}, - {file = "wrapt-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320"}, - {file = "wrapt-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2"}, - {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4"}, - {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069"}, - {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310"}, - {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f"}, - {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656"}, - {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c"}, - {file = "wrapt-1.14.1-cp310-cp310-win32.whl", hash = "sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8"}, - {file = "wrapt-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164"}, - {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907"}, - {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3"}, - {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3"}, - {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d"}, - {file = "wrapt-1.14.1-cp35-cp35m-win32.whl", hash = "sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7"}, - {file = "wrapt-1.14.1-cp35-cp35m-win_amd64.whl", hash = "sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00"}, - {file = "wrapt-1.14.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4"}, - {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1"}, - {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1"}, - {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff"}, - {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d"}, - {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1"}, - {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569"}, - {file = "wrapt-1.14.1-cp36-cp36m-win32.whl", hash = "sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed"}, - {file = "wrapt-1.14.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471"}, - {file = "wrapt-1.14.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248"}, - {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68"}, - {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d"}, - {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77"}, - {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7"}, - {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015"}, - {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a"}, - {file = "wrapt-1.14.1-cp37-cp37m-win32.whl", hash = "sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853"}, - {file = "wrapt-1.14.1-cp37-cp37m-win_amd64.whl", hash = "sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c"}, - {file = "wrapt-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456"}, - {file = "wrapt-1.14.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f"}, - {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc"}, - {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1"}, - {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af"}, - {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b"}, - {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0"}, - {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57"}, - {file = "wrapt-1.14.1-cp38-cp38-win32.whl", hash = "sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5"}, - {file = "wrapt-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d"}, - {file = "wrapt-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383"}, - {file = "wrapt-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7"}, - {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86"}, - {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735"}, - {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b"}, - {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3"}, - {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3"}, - {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe"}, - {file = "wrapt-1.14.1-cp39-cp39-win32.whl", hash = "sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5"}, - {file = "wrapt-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb"}, - {file = "wrapt-1.14.1.tar.gz", hash = "sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d"}, + {file = "wcwidth-0.2.6-py2.py3-none-any.whl", hash = "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e"}, + {file = "wcwidth-0.2.6.tar.gz", hash = "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"}, ] [[package]] @@ -1662,14 +1669,14 @@ requests = "*" [[package]] name = "zipp" -version = "3.9.0" +version = "3.11.0" description = "Backport of pathlib-compatible object wrapper for zip files" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "zipp-3.9.0-py3-none-any.whl", hash = "sha256:972cfa31bc2fedd3fa838a51e9bc7e64b7fb725a8c00e7431554311f180e9980"}, - {file = "zipp-3.9.0.tar.gz", hash = "sha256:3a7af91c3db40ec72dd9d154ae18e008c69efe8ca88dde4f9a731bb82fe2f9eb"}, + {file = "zipp-3.11.0-py3-none-any.whl", hash = "sha256:83a28fcb75844b5c0cdaf5aa4003c2d728c77e05f5aeabe8e95e56727005fbaa"}, + {file = "zipp-3.11.0.tar.gz", hash = "sha256:a7a22e05929290a67401440b39690ae6563279bced5f314609d9d03798f56766"}, ] [package.extras] @@ -1681,9 +1688,9 @@ build-backend = [] requires = [] rollbar = ["django-q-rollbar"] sentry = ["django-q-sentry"] -testing = ["django-redis", "croniter", "hiredis", "psutil", "iron-mq", "boto3", "pymongo", "blessed", "redis"] +testing = ["django-redis", "croniter", "hiredis", "psutil", "iron-mq", "boto3", "pymongo", "blessed", "redis", "setproctitle"] [metadata] lock-version = "2.0" python-versions = ">=3.8.14, <4" -content-hash = "6fd49a20d7ac72c3fb3e5941bbe46d1088aa8ff1592db7b8c3ec72be622dc43f" +content-hash = "0cd7cffd097c0c08c2e85d773bbef3f647a0f8df2c8f5690b7a1e07a8362e564" From f9e01699c51614663b656dc335a859df8fa0b223 Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Thu, 26 Jan 2023 16:45:44 +0100 Subject: [PATCH 35/39] Adding translation mo files automatically on build (#65) --- django_compilemessages.py | 9 +++++++++ pyproject.toml | 4 ++++ 2 files changed, 13 insertions(+) create mode 100644 django_compilemessages.py diff --git a/django_compilemessages.py b/django_compilemessages.py new file mode 100644 index 0000000..35b2853 --- /dev/null +++ b/django_compilemessages.py @@ -0,0 +1,9 @@ +import subprocess + + +def generate_mo_files(): + subprocess.run(["django-admin", "compilemessages"]) + + +if __name__ == "__main__": + generate_mo_files() diff --git a/pyproject.toml b/pyproject.toml index ba24385..83b219b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,3 +80,7 @@ sentry = ["django-q-sentry"] [tool.isort] profile = "black" multi_line_output = 3 + +[tool.poetry.build] +generate-setup-file = false +script = "django_compilemessages.py" From 25cd18041000bd8e5bbc706cc20073e4fc9fb814 Mon Sep 17 00:00:00 2001 From: GDay <1939656+GDay@users.noreply.github.com> Date: Fri, 27 Jan 2023 02:10:20 +0100 Subject: [PATCH 36/39] Release v1.4.10 --- CHANGELOG.md | 13 +++++++++++++ django_q/__init__.py | 2 +- docs/conf.py | 2 +- pyproject.toml | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb51b1d..815fcee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ ## [Unreleased](https://github.com/GDay/django-q2/tree/HEAD) +## [v1.4.10](https://github.com/GDay/django-q2/tree/v1.4.9) (2022-12-22) + +**Merged pull requests:** + +- Adding translation mo files automatically on build https://github.com/GDay/django-q2/pull/65 +- Update all dependencies https://github.com/GDay/django-q2/pull/64 +- Bump translations to latest changes https://github.com/GDay/django-q2/pull/63 +- Add meaningfull process titles with currently running task name https://github.com/GDay/django-q2/pull/57 +- Fix use of database router for write queries and remove Conf.HAS_REPLICA https://github.com/GDay/django-q2/pull/61 +- Add intended_date_kwarg field to Schedule https://github.com/GDay/django-q2/pull/62 +- Change task timeout logic to have now() as execution time https://github.com/GDay/django-q2/pull/58 +- More explicit log messages in exception handling https://github.com/GDay/django-q2/pull/59 + ## [v1.4.9](https://github.com/GDay/django-q2/tree/v1.4.9) (2022-12-22) **Merged pull requests:** diff --git a/django_q/__init__.py b/django_q/__init__.py index 2657991..86a795b 100644 --- a/django_q/__init__.py +++ b/django_q/__init__.py @@ -1,6 +1,6 @@ import django -VERSION = (1, 4, 9) +VERSION = (1, 4, 10) if django.VERSION < (3, 2): default_app_config = "django_q.apps.DjangoQConfig" diff --git a/docs/conf.py b/docs/conf.py index 5216862..459d707 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -75,7 +75,7 @@ author = "Ilan Steemers, Stan Triepels" # The short X.Y version. version = "1.4" # The full version, including alpha/beta/rc tags. -release = "1.4.9" +release = "1.4.10" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pyproject.toml b/pyproject.toml index 83b219b..ae452fb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "django-q2" -version = "1.4.9" +version = "1.4.10" packages = [ { include = "django_q" }, ] From b2bcffbcab23b5c3730badf251e9cd1cb5ef5444 Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Tue, 31 Jan 2023 00:09:33 +0100 Subject: [PATCH 37/39] Fix missing setup file for "No matching distribution" error (#69) --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ae452fb..9f47430 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -82,5 +82,4 @@ profile = "black" multi_line_output = 3 [tool.poetry.build] -generate-setup-file = false script = "django_compilemessages.py" From b9bdd64568eb26bd32eb81dfdc4373ed62ecd7da Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Tue, 31 Jan 2023 00:21:37 +0100 Subject: [PATCH 38/39] Remove custom build (revert to auto create setup file) (#70) --- pyproject.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 9f47430..1d5d454 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,6 +80,3 @@ sentry = ["django-q-sentry"] [tool.isort] profile = "black" multi_line_output = 3 - -[tool.poetry.build] -script = "django_compilemessages.py" From 01cb652071f2075961f65c2bae6aef74df88dce7 Mon Sep 17 00:00:00 2001 From: GDay <1939656+GDay@users.noreply.github.com> Date: Tue, 31 Jan 2023 00:24:44 +0100 Subject: [PATCH 39/39] Release v1.4.11 --- CHANGELOG.md | 9 ++++++++- django_q/__init__.py | 2 +- docs/conf.py | 2 +- pyproject.toml | 2 +- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 815fcee..f99ceb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,14 @@ ## [Unreleased](https://github.com/GDay/django-q2/tree/HEAD) -## [v1.4.10](https://github.com/GDay/django-q2/tree/v1.4.9) (2022-12-22) +## [v1.4.11](https://github.com/GDay/django-q2/tree/v1.4.11) (2023-01-30) + +**Merged pull requests:** + +- Fix missing setup file for "No matching distribution" error https://github.com/GDay/django-q2/pull/69 +- Remove custom build (revert to auto create setup file) https://github.com/GDay/django-q2/pull/70 + +## [v1.4.10](https://github.com/GDay/django-q2/tree/v1.4.10) (2023-01-26) **Merged pull requests:** diff --git a/django_q/__init__.py b/django_q/__init__.py index 86a795b..97d9ef5 100644 --- a/django_q/__init__.py +++ b/django_q/__init__.py @@ -1,6 +1,6 @@ import django -VERSION = (1, 4, 10) +VERSION = (1, 4, 11) if django.VERSION < (3, 2): default_app_config = "django_q.apps.DjangoQConfig" diff --git a/docs/conf.py b/docs/conf.py index 459d707..08ef671 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -75,7 +75,7 @@ author = "Ilan Steemers, Stan Triepels" # The short X.Y version. version = "1.4" # The full version, including alpha/beta/rc tags. -release = "1.4.10" +release = "1.4.11" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pyproject.toml b/pyproject.toml index 1d5d454..e375c7d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "django-q2" -version = "1.4.10" +version = "1.4.11" packages = [ { include = "django_q" }, ]