mirror of
https://github.com/django-q2/django-q2.git
synced 2026-09-15 13:37:56 +08:00
Build improvements (#569)
* Black linting * Adding Black to dev dependencies and upping minimal python to 3.6.2 for compatibility * Updating packages * Removing pip-tools input and exporting requirements with poetry * Deleting old setup files and test runner * Trying 1.3.7 * Looser extras requirements to prevent conflicts * Sorted imports with isort * Added iSort to dev dependencies * Fixes localtime for naive setups
This commit is contained in:
@@ -1,9 +0,0 @@
|
||||
include LICENSE
|
||||
include README.rst
|
||||
include CHANGELOG.
|
||||
recursive-include django_q/locale *
|
||||
include django_q/management/*.py
|
||||
include django_q/management/commands/*.py
|
||||
include django_q/migrations/*.py
|
||||
include django_q/brokers/*.py
|
||||
include django_q/tests/*.py
|
||||
@@ -1,4 +1,4 @@
|
||||
VERSION = (1, 3, 6)
|
||||
VERSION = (1, 3, 7)
|
||||
|
||||
default_app_config = "django_q.apps.DjangoQConfig"
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ from django.contrib import admin
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from django_q.conf import Conf, croniter
|
||||
from django_q.models import Success, Failure, Schedule, OrmQ
|
||||
from django_q.models import Failure, OrmQ, Schedule, Success
|
||||
from django_q.tasks import async_task
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ class FailAdmin(admin.ModelAdmin):
|
||||
|
||||
|
||||
class ScheduleAdmin(admin.ModelAdmin):
|
||||
""" model admin for schedules """
|
||||
"""model admin for schedules"""
|
||||
|
||||
list_display = (
|
||||
"id",
|
||||
@@ -84,7 +84,7 @@ class ScheduleAdmin(admin.ModelAdmin):
|
||||
|
||||
|
||||
class QueueAdmin(admin.ModelAdmin):
|
||||
""" queue admin for ORM broker """
|
||||
"""queue admin for ORM broker"""
|
||||
|
||||
list_display = ("id", "key", "task_id", "name", "func", "lock")
|
||||
|
||||
@@ -100,7 +100,7 @@ class QueueAdmin(admin.ModelAdmin):
|
||||
def has_add_permission(self, request):
|
||||
"""Don't allow adds."""
|
||||
return False
|
||||
|
||||
|
||||
list_filter = ("key",)
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import importlib
|
||||
from typing import Optional
|
||||
|
||||
from django.core.cache import caches, InvalidCacheBackendError
|
||||
from django.core.cache import InvalidCacheBackendError, caches
|
||||
|
||||
from django_q.conf import Conf
|
||||
|
||||
|
||||
@@ -38,7 +38,9 @@ class Sqs(Broker):
|
||||
if not isinstance(wait_time_second, int):
|
||||
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")
|
||||
raise ValueError(
|
||||
"receive_message_wait_time_seconds is invalid. Reason: Must be >= 0 and <= 20"
|
||||
)
|
||||
params.update({"WaitTimeSeconds": wait_time_second})
|
||||
|
||||
tasks = self.queue.receive_messages(**params)
|
||||
@@ -80,7 +82,7 @@ class Sqs(Broker):
|
||||
config["region_name"] = config["aws_region"]
|
||||
del config["aws_region"]
|
||||
|
||||
if 'receive_message_wait_time_seconds' in config:
|
||||
if "receive_message_wait_time_seconds" in config:
|
||||
del config["receive_message_wait_time_seconds"]
|
||||
|
||||
return Session(**config)
|
||||
|
||||
@@ -2,10 +2,11 @@ import random
|
||||
|
||||
# External
|
||||
import redis
|
||||
from redis import Redis
|
||||
|
||||
# Django
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from redis import Redis
|
||||
|
||||
from django_q.brokers import Broker
|
||||
from django_q.conf import Conf
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import signal
|
||||
import socket
|
||||
import traceback
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from multiprocessing import Event, Process, Value, current_process
|
||||
from time import sleep
|
||||
|
||||
@@ -13,13 +14,14 @@ from time import sleep
|
||||
import arrow
|
||||
|
||||
# Django
|
||||
from django import db, core
|
||||
from django import core, db
|
||||
from django.apps.registry import apps
|
||||
|
||||
try:
|
||||
apps.check_apps_ready()
|
||||
except core.exceptions.AppRegistryNotReady:
|
||||
import django
|
||||
|
||||
django.setup()
|
||||
|
||||
from django.conf import settings
|
||||
@@ -28,21 +30,21 @@ from django.utils.translation import gettext_lazy as _
|
||||
|
||||
# Local
|
||||
import django_q.tasks
|
||||
from django_q.brokers import get_broker, Broker
|
||||
from django_q.brokers import Broker, get_broker
|
||||
from django_q.conf import (
|
||||
Conf,
|
||||
croniter,
|
||||
error_reporter,
|
||||
get_ppid,
|
||||
logger,
|
||||
psutil,
|
||||
get_ppid,
|
||||
error_reporter,
|
||||
croniter,
|
||||
resource,
|
||||
)
|
||||
from django_q.humanhash import humanize
|
||||
from django_q.models import Task, Success, Schedule
|
||||
from django_q.models import Schedule, Success, Task
|
||||
from django_q.queues import Queue
|
||||
from django_q.signals import pre_execute
|
||||
from django_q.signing import SignedPackage, BadSignature
|
||||
from django_q.signing import BadSignature, SignedPackage
|
||||
from django_q.status import Stat, Status
|
||||
|
||||
|
||||
@@ -485,8 +487,11 @@ def save_task(task, broker: Broker):
|
||||
existing_task.attempt_count = existing_task.attempt_count + 1
|
||||
existing_task.save()
|
||||
|
||||
if Conf.MAX_ATTEMPTS > 0 and existing_task.attempt_count >= Conf.MAX_ATTEMPTS:
|
||||
broker.acknowledge(task['ack_id'])
|
||||
if (
|
||||
Conf.MAX_ATTEMPTS > 0
|
||||
and existing_task.attempt_count >= Conf.MAX_ATTEMPTS
|
||||
):
|
||||
broker.acknowledge(task["ack_id"])
|
||||
|
||||
else:
|
||||
func = task["func"]
|
||||
@@ -495,8 +500,8 @@ def save_task(task, broker: Broker):
|
||||
func = f"{func.__module__}.{func.__name__}"
|
||||
elif inspect.ismethod(func):
|
||||
func = (
|
||||
f'{func.__self__.__module__}.'
|
||||
f'{func.__self__.__name__}.{func.__name__}'
|
||||
f"{func.__self__.__module__}."
|
||||
f"{func.__self__.__name__}.{func.__name__}"
|
||||
)
|
||||
Task.objects.create(
|
||||
id=task["id"],
|
||||
@@ -510,7 +515,7 @@ def save_task(task, broker: Broker):
|
||||
result=task["result"],
|
||||
group=task.get("group"),
|
||||
success=task["success"],
|
||||
attempt_count=1
|
||||
attempt_count=1,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
@@ -582,7 +587,9 @@ def scheduler(broker: Broker = None):
|
||||
Schedule.objects.select_for_update()
|
||||
.exclude(repeats=0)
|
||||
.filter(next_run__lt=timezone.now())
|
||||
.filter(db.models.Q(cluster__isnull=True) | db.models.Q(cluster=Conf.PREFIX))
|
||||
.filter(
|
||||
db.models.Q(cluster__isnull=True) | db.models.Q(cluster=Conf.PREFIX)
|
||||
)
|
||||
):
|
||||
args = ()
|
||||
kwargs = {}
|
||||
@@ -627,7 +634,7 @@ def scheduler(broker: Broker = None):
|
||||
)
|
||||
)
|
||||
next_run = arrow.get(
|
||||
croniter(s.cron, timezone.localtime()).get_next()
|
||||
croniter(s.cron, localtime()).get_next()
|
||||
)
|
||||
if Conf.CATCH_UP or next_run > arrow.utcnow():
|
||||
break
|
||||
@@ -643,7 +650,7 @@ 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: # 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)
|
||||
@@ -734,4 +741,11 @@ def rss_check():
|
||||
return resource.getrusage(resource.RUSAGE_SELF).ru_maxrss >= Conf.MAX_RSS
|
||||
elif psutil:
|
||||
return psutil.Process().memory_info().rss >= Conf.MAX_RSS * 1024
|
||||
return False
|
||||
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()
|
||||
|
||||
@@ -135,12 +135,13 @@ class Conf:
|
||||
RETRY = conf.get("retry", 60)
|
||||
|
||||
# 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,
|
||||
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-q.readthedocs.io/en/latest/configure.html#retry for details.""")
|
||||
|
||||
|
||||
See https://django-q.readthedocs.io/en/latest/configure.html#retry for details."""
|
||||
)
|
||||
|
||||
# Sets the amount of tasks the cluster will try to pop off the broker.
|
||||
# If it supports bulk gets.
|
||||
BULK = conf.get("bulk", 1)
|
||||
@@ -176,7 +177,7 @@ class Conf:
|
||||
ERROR_REPORTER = conf.get("error_reporter", {})
|
||||
|
||||
# Optional attempt count. set to 0 for infinite attempts
|
||||
MAX_ATTEMPTS = conf.get('max_attempts', 0)
|
||||
MAX_ATTEMPTS = conf.get("max_attempts", 0)
|
||||
|
||||
# OSX doesn't implement qsize because of missing sem_getvalue()
|
||||
try:
|
||||
@@ -200,7 +201,8 @@ class Conf:
|
||||
|
||||
# to manage workarounds during testing
|
||||
TESTING = conf.get("testing", False)
|
||||
|
||||
|
||||
|
||||
# logger
|
||||
logger = logging.getLogger("django-q")
|
||||
|
||||
|
||||
@@ -2,15 +2,10 @@ import datetime
|
||||
import time
|
||||
import zlib
|
||||
|
||||
from django.core.signing import (
|
||||
BadSignature,
|
||||
SignatureExpired,
|
||||
b64_decode,
|
||||
JSONSerializer,
|
||||
Signer as Sgnr,
|
||||
TimestampSigner as TsS,
|
||||
dumps,
|
||||
)
|
||||
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
|
||||
from django.utils.crypto import constant_time_compare
|
||||
from django.utils.encoding import force_bytes, force_str
|
||||
|
||||
@@ -4,50 +4,269 @@ humanhash: Human-readable representations of digests.
|
||||
The simplest ways to use this module are the :func:`humanize` and :func:`uuid`
|
||||
functions. For tighter control over the output, see :class:`HumanHasher`.
|
||||
"""
|
||||
from argparse import ArgumentError
|
||||
|
||||
import operator
|
||||
import uuid as uuidlib
|
||||
from argparse import ArgumentError
|
||||
from functools import reduce
|
||||
|
||||
|
||||
DEFAULT_WORDLIST = (
|
||||
'ack', 'alabama', 'alanine', 'alaska', 'alpha', 'angel', 'apart', 'april',
|
||||
'arizona', 'arkansas', 'artist', 'asparagus', 'aspen', 'august', 'autumn',
|
||||
'avocado', 'bacon', 'bakerloo', 'batman', 'beer', 'berlin', 'beryllium',
|
||||
'black', 'blossom', 'blue', 'bluebird', 'bravo', 'bulldog', 'burger',
|
||||
'butter', 'california', 'carbon', 'cardinal', 'carolina', 'carpet', 'cat',
|
||||
'ceiling', 'charlie', 'chicken', 'coffee', 'cola', 'cold', 'colorado',
|
||||
'comet', 'connecticut', 'crazy', 'cup', 'dakota', 'december', 'delaware',
|
||||
'delta', 'diet', 'don', 'double', 'early', 'earth', 'east', 'echo',
|
||||
'edward', 'eight', 'eighteen', 'eleven', 'emma', 'enemy', 'equal',
|
||||
'failed', 'fanta', 'fifteen', 'fillet', 'finch', 'fish', 'five', 'fix',
|
||||
'floor', 'florida', 'football', 'four', 'fourteen', 'foxtrot', 'freddie',
|
||||
'friend', 'fruit', 'gee', 'georgia', 'glucose', 'golf', 'green', 'grey',
|
||||
'hamper', 'happy', 'harry', 'hawaii', 'helium', 'high', 'hot', 'hotel',
|
||||
'hydrogen', 'idaho', 'illinois', 'india', 'indigo', 'ink', 'iowa',
|
||||
'island', 'item', 'jersey', 'jig', 'johnny', 'juliet', 'july', 'jupiter',
|
||||
'kansas', 'kentucky', 'kilo', 'king', 'kitten', 'lactose', 'lake', 'lamp',
|
||||
'lemon', 'leopard', 'lima', 'lion', 'lithium', 'london', 'louisiana',
|
||||
'low', 'magazine', 'magnesium', 'maine', 'mango', 'march', 'mars',
|
||||
'maryland', 'massachusetts', 'may', 'mexico', 'michigan', 'mike',
|
||||
'minnesota', 'mirror', 'mississippi', 'missouri', 'mobile', 'mockingbird',
|
||||
'monkey', 'montana', 'moon', 'mountain', 'muppet', 'music', 'nebraska',
|
||||
'neptune', 'network', 'nevada', 'nine', 'nineteen', 'nitrogen', 'north',
|
||||
'november', 'nuts', 'october', 'ohio', 'oklahoma', 'one', 'orange',
|
||||
'oranges', 'oregon', 'oscar', 'oven', 'oxygen', 'papa', 'paris', 'pasta',
|
||||
'pennsylvania', 'pip', 'pizza', 'pluto', 'potato', 'princess', 'purple',
|
||||
'quebec', 'queen', 'quiet', 'red', 'river', 'robert', 'robin', 'romeo',
|
||||
'rugby', 'sad', 'salami', 'saturn', 'september', 'seven', 'seventeen',
|
||||
'shade', 'sierra', 'single', 'sink', 'six', 'sixteen', 'skylark', 'snake',
|
||||
'social', 'sodium', 'solar', 'south', 'spaghetti', 'speaker', 'spring',
|
||||
'stairway', 'steak', 'stream', 'summer', 'sweet', 'table', 'tango', 'ten',
|
||||
'tennessee', 'tennis', 'texas', 'thirteen', 'three', 'timing', 'triple',
|
||||
'twelve', 'twenty', 'two', 'uncle', 'undress', 'uniform', 'uranus', 'utah',
|
||||
'vegan', 'venus', 'vermont', 'victor', 'video', 'violet', 'virginia',
|
||||
'washington', 'west', 'whiskey', 'white', 'william', 'winner', 'winter',
|
||||
'wisconsin', 'wolfram', 'wyoming', 'xray', 'yankee', 'yellow', 'zebra',
|
||||
'zulu')
|
||||
"ack",
|
||||
"alabama",
|
||||
"alanine",
|
||||
"alaska",
|
||||
"alpha",
|
||||
"angel",
|
||||
"apart",
|
||||
"april",
|
||||
"arizona",
|
||||
"arkansas",
|
||||
"artist",
|
||||
"asparagus",
|
||||
"aspen",
|
||||
"august",
|
||||
"autumn",
|
||||
"avocado",
|
||||
"bacon",
|
||||
"bakerloo",
|
||||
"batman",
|
||||
"beer",
|
||||
"berlin",
|
||||
"beryllium",
|
||||
"black",
|
||||
"blossom",
|
||||
"blue",
|
||||
"bluebird",
|
||||
"bravo",
|
||||
"bulldog",
|
||||
"burger",
|
||||
"butter",
|
||||
"california",
|
||||
"carbon",
|
||||
"cardinal",
|
||||
"carolina",
|
||||
"carpet",
|
||||
"cat",
|
||||
"ceiling",
|
||||
"charlie",
|
||||
"chicken",
|
||||
"coffee",
|
||||
"cola",
|
||||
"cold",
|
||||
"colorado",
|
||||
"comet",
|
||||
"connecticut",
|
||||
"crazy",
|
||||
"cup",
|
||||
"dakota",
|
||||
"december",
|
||||
"delaware",
|
||||
"delta",
|
||||
"diet",
|
||||
"don",
|
||||
"double",
|
||||
"early",
|
||||
"earth",
|
||||
"east",
|
||||
"echo",
|
||||
"edward",
|
||||
"eight",
|
||||
"eighteen",
|
||||
"eleven",
|
||||
"emma",
|
||||
"enemy",
|
||||
"equal",
|
||||
"failed",
|
||||
"fanta",
|
||||
"fifteen",
|
||||
"fillet",
|
||||
"finch",
|
||||
"fish",
|
||||
"five",
|
||||
"fix",
|
||||
"floor",
|
||||
"florida",
|
||||
"football",
|
||||
"four",
|
||||
"fourteen",
|
||||
"foxtrot",
|
||||
"freddie",
|
||||
"friend",
|
||||
"fruit",
|
||||
"gee",
|
||||
"georgia",
|
||||
"glucose",
|
||||
"golf",
|
||||
"green",
|
||||
"grey",
|
||||
"hamper",
|
||||
"happy",
|
||||
"harry",
|
||||
"hawaii",
|
||||
"helium",
|
||||
"high",
|
||||
"hot",
|
||||
"hotel",
|
||||
"hydrogen",
|
||||
"idaho",
|
||||
"illinois",
|
||||
"india",
|
||||
"indigo",
|
||||
"ink",
|
||||
"iowa",
|
||||
"island",
|
||||
"item",
|
||||
"jersey",
|
||||
"jig",
|
||||
"johnny",
|
||||
"juliet",
|
||||
"july",
|
||||
"jupiter",
|
||||
"kansas",
|
||||
"kentucky",
|
||||
"kilo",
|
||||
"king",
|
||||
"kitten",
|
||||
"lactose",
|
||||
"lake",
|
||||
"lamp",
|
||||
"lemon",
|
||||
"leopard",
|
||||
"lima",
|
||||
"lion",
|
||||
"lithium",
|
||||
"london",
|
||||
"louisiana",
|
||||
"low",
|
||||
"magazine",
|
||||
"magnesium",
|
||||
"maine",
|
||||
"mango",
|
||||
"march",
|
||||
"mars",
|
||||
"maryland",
|
||||
"massachusetts",
|
||||
"may",
|
||||
"mexico",
|
||||
"michigan",
|
||||
"mike",
|
||||
"minnesota",
|
||||
"mirror",
|
||||
"mississippi",
|
||||
"missouri",
|
||||
"mobile",
|
||||
"mockingbird",
|
||||
"monkey",
|
||||
"montana",
|
||||
"moon",
|
||||
"mountain",
|
||||
"muppet",
|
||||
"music",
|
||||
"nebraska",
|
||||
"neptune",
|
||||
"network",
|
||||
"nevada",
|
||||
"nine",
|
||||
"nineteen",
|
||||
"nitrogen",
|
||||
"north",
|
||||
"november",
|
||||
"nuts",
|
||||
"october",
|
||||
"ohio",
|
||||
"oklahoma",
|
||||
"one",
|
||||
"orange",
|
||||
"oranges",
|
||||
"oregon",
|
||||
"oscar",
|
||||
"oven",
|
||||
"oxygen",
|
||||
"papa",
|
||||
"paris",
|
||||
"pasta",
|
||||
"pennsylvania",
|
||||
"pip",
|
||||
"pizza",
|
||||
"pluto",
|
||||
"potato",
|
||||
"princess",
|
||||
"purple",
|
||||
"quebec",
|
||||
"queen",
|
||||
"quiet",
|
||||
"red",
|
||||
"river",
|
||||
"robert",
|
||||
"robin",
|
||||
"romeo",
|
||||
"rugby",
|
||||
"sad",
|
||||
"salami",
|
||||
"saturn",
|
||||
"september",
|
||||
"seven",
|
||||
"seventeen",
|
||||
"shade",
|
||||
"sierra",
|
||||
"single",
|
||||
"sink",
|
||||
"six",
|
||||
"sixteen",
|
||||
"skylark",
|
||||
"snake",
|
||||
"social",
|
||||
"sodium",
|
||||
"solar",
|
||||
"south",
|
||||
"spaghetti",
|
||||
"speaker",
|
||||
"spring",
|
||||
"stairway",
|
||||
"steak",
|
||||
"stream",
|
||||
"summer",
|
||||
"sweet",
|
||||
"table",
|
||||
"tango",
|
||||
"ten",
|
||||
"tennessee",
|
||||
"tennis",
|
||||
"texas",
|
||||
"thirteen",
|
||||
"three",
|
||||
"timing",
|
||||
"triple",
|
||||
"twelve",
|
||||
"twenty",
|
||||
"two",
|
||||
"uncle",
|
||||
"undress",
|
||||
"uniform",
|
||||
"uranus",
|
||||
"utah",
|
||||
"vegan",
|
||||
"venus",
|
||||
"vermont",
|
||||
"victor",
|
||||
"video",
|
||||
"violet",
|
||||
"virginia",
|
||||
"washington",
|
||||
"west",
|
||||
"whiskey",
|
||||
"white",
|
||||
"william",
|
||||
"winner",
|
||||
"winter",
|
||||
"wisconsin",
|
||||
"wolfram",
|
||||
"wyoming",
|
||||
"xray",
|
||||
"yankee",
|
||||
"yellow",
|
||||
"zebra",
|
||||
"zulu",
|
||||
)
|
||||
|
||||
|
||||
class HumanHasher:
|
||||
@@ -70,7 +289,7 @@ class HumanHasher:
|
||||
raise ArgumentError("Wordlist must have exactly 256 items")
|
||||
self.wordlist = wordlist
|
||||
|
||||
def humanize(self, hexdigest, words=4, separator='-'):
|
||||
def humanize(self, hexdigest, words=4, separator="-"):
|
||||
|
||||
"""
|
||||
Humanize a given hexadecimal digest.
|
||||
@@ -84,7 +303,10 @@ class HumanHasher:
|
||||
"""
|
||||
|
||||
# Gets a list of byte values between 0-255.
|
||||
bytes = [int(x, 16) for x in list(map(''.join, list(zip(hexdigest[::2], hexdigest[1::2]))))]
|
||||
bytes = [
|
||||
int(x, 16)
|
||||
for x in list(map("".join, list(zip(hexdigest[::2], hexdigest[1::2]))))
|
||||
]
|
||||
# Compress an arbitrary number of bytes to `words`.
|
||||
compressed = self.compress(bytes, words)
|
||||
# Map the compressed byte values through the word list.
|
||||
@@ -115,10 +337,9 @@ 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)]
|
||||
segments = [bytes[i * seg_size : (i + 1) * seg_size] for i in range(target)]
|
||||
# Catch any left-over bytes in the last segment.
|
||||
segments[-1].extend(bytes[target * seg_size:])
|
||||
segments[-1].extend(bytes[target * seg_size :])
|
||||
|
||||
# Use a simple XOR checksum-like function for compression.
|
||||
checksum = lambda bytes: reduce(operator.xor, bytes, 0)
|
||||
@@ -134,7 +355,7 @@ class HumanHasher:
|
||||
as :meth:`humanize` (they'll be passed straight through).
|
||||
"""
|
||||
|
||||
digest = str(uuidlib.uuid4()).replace('-', '')
|
||||
digest = str(uuidlib.uuid4()).replace("-", "")
|
||||
return self.humanize(digest, **params), digest
|
||||
|
||||
|
||||
|
||||
@@ -10,15 +10,15 @@ class Command(BaseCommand):
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'--run-once',
|
||||
action='store_true',
|
||||
dest='run_once',
|
||||
"--run-once",
|
||||
action="store_true",
|
||||
dest="run_once",
|
||||
default=False,
|
||||
help='Run once and then stop.',
|
||||
help="Run once and then stop.",
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
q = Cluster()
|
||||
q.start()
|
||||
if options.get('run_once', False):
|
||||
if options.get("run_once", False):
|
||||
q.stop()
|
||||
|
||||
@@ -3,7 +3,7 @@ from django.utils.translation import gettext as _
|
||||
|
||||
from django_q import VERSION
|
||||
from django_q.conf import Conf
|
||||
from django_q.monitor import info, get_ids
|
||||
from django_q.monitor import get_ids, info
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
||||
@@ -27,5 +27,5 @@ class Command(BaseCommand):
|
||||
def handle(self, *args, **options):
|
||||
memory(
|
||||
run_once=options.get("run_once", False),
|
||||
workers=options.get("workers", False)
|
||||
workers=options.get("workers", False),
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from django.db import models, migrations
|
||||
import picklefield.fields
|
||||
import django.utils.timezone
|
||||
import picklefield.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from django.db import migrations
|
||||
import picklefield.fields
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Generated by Django 3.0.8 on 2020-07-02 16:08
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
import django_q.models
|
||||
|
||||
|
||||
|
||||
@@ -5,15 +5,16 @@ from blessed import Terminal
|
||||
|
||||
# django
|
||||
from django.db import connection
|
||||
from django.db.models import Sum, F
|
||||
from django.db.models import F, Sum
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from django_q import VERSION, models
|
||||
from django_q.brokers import get_broker
|
||||
|
||||
# local
|
||||
from django_q.conf import Conf
|
||||
from django_q.status import Stat
|
||||
from django_q.brokers import get_broker
|
||||
from django_q import models, VERSION
|
||||
|
||||
# optional
|
||||
try:
|
||||
@@ -27,7 +28,7 @@ def get_process_mb(pid):
|
||||
process = psutil.Process(pid)
|
||||
mb_used = round(process.memory_info().rss / 1024 ** 2, 2)
|
||||
except psutil.NoSuchProcess:
|
||||
mb_used = 'NO_PROCESS_FOUND'
|
||||
mb_used = "NO_PROCESS_FOUND"
|
||||
return mb_used
|
||||
|
||||
|
||||
@@ -39,7 +40,10 @@ def monitor(run_once=False, broker=None):
|
||||
with term.fullscreen(), term.hidden_cursor(), term.cbreak():
|
||||
val = None
|
||||
start_width = int(term.width / 8)
|
||||
while val not in ("q", "Q",):
|
||||
while val not in (
|
||||
"q",
|
||||
"Q",
|
||||
):
|
||||
col_width = int(term.width / 8)
|
||||
# In case of resize
|
||||
if col_width != start_width:
|
||||
@@ -294,7 +298,11 @@ def memory(run_once=False, workers=False, broker=None):
|
||||
broker.ping()
|
||||
if not psutil:
|
||||
print(term.clear_eos())
|
||||
print(term.white_on_red("Cannot start \"qmemory\" command. Missing \"psutil\" library."))
|
||||
print(
|
||||
term.white_on_red(
|
||||
'Cannot start "qmemory" command. Missing "psutil" library.'
|
||||
)
|
||||
)
|
||||
return
|
||||
with term.fullscreen(), term.hidden_cursor(), term.cbreak():
|
||||
MEMORY_AVAILABLE_LOWEST_PERCENTAGE = 100.0
|
||||
@@ -319,11 +327,15 @@ def memory(run_once=False, workers=False, broker=None):
|
||||
)
|
||||
print(
|
||||
term.move(0, 2 * col_width)
|
||||
+ term.black_on_green(term.center(_("Available (%)"), width=col_width - 1))
|
||||
+ term.black_on_green(
|
||||
term.center(_("Available (%)"), width=col_width - 1)
|
||||
)
|
||||
)
|
||||
print(
|
||||
term.move(0, 3 * col_width)
|
||||
+ term.black_on_green(term.center(_("Available (MB)"), width=col_width - 1))
|
||||
+ term.black_on_green(
|
||||
term.center(_("Available (MB)"), width=col_width - 1)
|
||||
)
|
||||
)
|
||||
print(
|
||||
term.move(0, 4 * col_width)
|
||||
@@ -331,24 +343,37 @@ def memory(run_once=False, workers=False, broker=None):
|
||||
)
|
||||
print(
|
||||
term.move(0, 5 * col_width)
|
||||
+ term.black_on_green(term.center(_("Sentinel (MB)"), width=col_width - 1))
|
||||
+ term.black_on_green(
|
||||
term.center(_("Sentinel (MB)"), width=col_width - 1)
|
||||
)
|
||||
)
|
||||
print(
|
||||
term.move(0, 6 * col_width)
|
||||
+ term.black_on_green(term.center(_("Monitor (MB)"), width=col_width - 1))
|
||||
+ term.black_on_green(
|
||||
term.center(_("Monitor (MB)"), width=col_width - 1)
|
||||
)
|
||||
)
|
||||
print(
|
||||
term.move(0, 7 * col_width)
|
||||
+ term.black_on_green(term.center(_("Workers (MB)"), width=col_width - 1))
|
||||
+ term.black_on_green(
|
||||
term.center(_("Workers (MB)"), width=col_width - 1)
|
||||
)
|
||||
)
|
||||
row = 2
|
||||
stats = Stat.get_all(broker=broker)
|
||||
print(term.clear_eos())
|
||||
for stat in stats:
|
||||
# memory available (%)
|
||||
memory_available_percentage = round(psutil.virtual_memory().available * 100 / psutil.virtual_memory().total, 2)
|
||||
memory_available_percentage = round(
|
||||
psutil.virtual_memory().available
|
||||
* 100
|
||||
/ psutil.virtual_memory().total,
|
||||
2,
|
||||
)
|
||||
# memory available (MB)
|
||||
memory_available = round(psutil.virtual_memory().available / 1024 ** 2, 2)
|
||||
memory_available = round(
|
||||
psutil.virtual_memory().available / 1024 ** 2, 2
|
||||
)
|
||||
if memory_available_percentage < MEMORY_AVAILABLE_LOWEST_PERCENTAGE:
|
||||
MEMORY_AVAILABLE_LOWEST_PERCENTAGE = memory_available_percentage
|
||||
MEMORY_AVAILABLE_LOWEST_PERCENTAGE_AT = timezone.now()
|
||||
@@ -370,7 +395,10 @@ 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), width=col_width - 1)
|
||||
+ term.center(
|
||||
round(psutil.virtual_memory().total / 1024 ** 2, 2),
|
||||
width=col_width - 1,
|
||||
)
|
||||
)
|
||||
print(
|
||||
term.move(row, 5 * col_width)
|
||||
@@ -378,7 +406,10 @@ def memory(run_once=False, workers=False, broker=None):
|
||||
)
|
||||
print(
|
||||
term.move(row, 6 * col_width)
|
||||
+ term.center(get_process_mb(getattr(stat, 'monitor', None)), width=col_width - 1)
|
||||
+ term.center(
|
||||
get_process_mb(getattr(stat, "monitor", None)),
|
||||
width=col_width - 1,
|
||||
)
|
||||
)
|
||||
workers_mb = 0
|
||||
for worker_pid in stat.workers:
|
||||
@@ -388,7 +419,9 @@ def memory(run_once=False, workers=False, broker=None):
|
||||
workers_mb += result
|
||||
print(
|
||||
term.move(row, 7 * col_width)
|
||||
+ term.center(workers_mb or 'NO_PROCESSES_FOUND', width=col_width - 1)
|
||||
+ term.center(
|
||||
workers_mb or "NO_PROCESSES_FOUND", width=col_width - 1
|
||||
)
|
||||
)
|
||||
row += 1
|
||||
# each worker's memory usage
|
||||
@@ -402,7 +435,12 @@ def memory(run_once=False, workers=False, broker=None):
|
||||
for worker_num in range(Conf.WORKERS):
|
||||
print(
|
||||
term.move(row, (worker_num + 1) * col_width)
|
||||
+ term.black_on_cyan(term.center("Worker #{} (MB)".format(worker_num + 1), width=col_width - 1))
|
||||
+ term.black_on_cyan(
|
||||
term.center(
|
||||
"Worker #{} (MB)".format(worker_num + 1),
|
||||
width=col_width - 1,
|
||||
)
|
||||
)
|
||||
)
|
||||
row += 2
|
||||
for stat in stats:
|
||||
@@ -422,7 +460,9 @@ def memory(run_once=False, workers=False, broker=None):
|
||||
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')
|
||||
MEMORY_AVAILABLE_LOWEST_PERCENTAGE_AT.strftime(
|
||||
"%Y-%m-%d %H:%M:%S+00:00"
|
||||
),
|
||||
)
|
||||
)
|
||||
# for testing
|
||||
|
||||
@@ -7,7 +7,7 @@ import sys
|
||||
|
||||
|
||||
class SharedCounter:
|
||||
""" A synchronized shared counter.
|
||||
"""A synchronized shared counter.
|
||||
|
||||
The locking done by multiprocessing.Value ensures that only a single
|
||||
process or thread may read or write the in-memory ctypes object. However,
|
||||
@@ -24,18 +24,18 @@ class SharedCounter:
|
||||
self.count = multiprocessing.Value("i", n)
|
||||
|
||||
def increment(self, n=1):
|
||||
""" Increment the counter by n (default = 1) """
|
||||
"""Increment the counter by n (default = 1)"""
|
||||
with self.count.get_lock():
|
||||
self.count.value += n
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
""" Return the value of the counter """
|
||||
"""Return the value of the counter"""
|
||||
return self.count.value
|
||||
|
||||
|
||||
class Queue(multiprocessing.queues.Queue):
|
||||
""" A portable implementation of multiprocessing.Queue.
|
||||
"""A portable implementation of multiprocessing.Queue.
|
||||
|
||||
Because of multithreading / multiprocessing semantics, Queue.qsize() may
|
||||
raise the NotImplementedError exception on Unix platforms like Mac OS X
|
||||
@@ -57,7 +57,7 @@ class Queue(multiprocessing.queues.Queue):
|
||||
self.size = SharedCounter(0)
|
||||
|
||||
def __getstate__(self):
|
||||
return super(Queue, self).__getstate__() + (self.size, )
|
||||
return super(Queue, self).__getstate__() + (self.size,)
|
||||
|
||||
def __setstate__(self, state):
|
||||
super(Queue, self).__setstate__(state[:-1])
|
||||
@@ -73,9 +73,9 @@ class Queue(multiprocessing.queues.Queue):
|
||||
return x
|
||||
|
||||
def qsize(self) -> int:
|
||||
""" Reliable implementation of multiprocessing.Queue.qsize() """
|
||||
"""Reliable implementation of multiprocessing.Queue.qsize()"""
|
||||
return self.size.value
|
||||
|
||||
def empty(self) -> bool:
|
||||
""" Reliable implementation of multiprocessing.Queue.empty() """
|
||||
"""Reliable implementation of multiprocessing.Queue.empty()"""
|
||||
return not self.qsize() > 0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import importlib
|
||||
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver, Signal
|
||||
from django.dispatch import Signal, receiver
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from django_q.conf import logger
|
||||
@@ -31,6 +31,7 @@ def call_hook(sender, instance, **kwargs):
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
# args: task
|
||||
pre_enqueue = Signal()
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@ from typing import Union
|
||||
|
||||
from django.utils import timezone
|
||||
|
||||
from django_q.brokers import get_broker, Broker
|
||||
from django_q.brokers import Broker, get_broker
|
||||
from django_q.conf import Conf, logger
|
||||
from django_q.signing import SignedPackage, BadSignature
|
||||
from django_q.signing import BadSignature, SignedPackage
|
||||
|
||||
|
||||
class Status:
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
"""Provides task functionality."""
|
||||
# Standard
|
||||
from multiprocessing import Value
|
||||
from time import sleep, time
|
||||
|
||||
# django
|
||||
from django.db import IntegrityError
|
||||
from django.utils import timezone
|
||||
from multiprocessing import Value
|
||||
|
||||
# local
|
||||
from django_q.brokers import get_broker
|
||||
@@ -153,7 +153,7 @@ def result(task_id, wait=0, cached=Conf.CACHED):
|
||||
|
||||
def result_cached(task_id, wait=0, broker=None):
|
||||
"""
|
||||
Return the result from the cache backend
|
||||
Return the result from the cache backend
|
||||
"""
|
||||
if not broker:
|
||||
broker = get_broker()
|
||||
@@ -755,7 +755,7 @@ class AsyncTask:
|
||||
|
||||
def _sync(pack):
|
||||
"""Simulate a package travelling through the cluster."""
|
||||
from django_q.cluster import worker, monitor
|
||||
from django_q.cluster import monitor, worker
|
||||
|
||||
task_queue = Queue()
|
||||
result_queue = Queue()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import os
|
||||
|
||||
import django
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
@@ -8,7 +9,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = ')cqmpi+p@n&!u&fu@!m@9h&1bz9mwmstsahe)nf!ms+c$uc=x7'
|
||||
SECRET_KEY = ")cqmpi+p@n&!u&fu@!m@9h&1bz9mwmstsahe)nf!ms+c$uc=x7"
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
@@ -19,41 +20,41 @@ ALLOWED_HOSTS = []
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = (
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'django_q',
|
||||
'django_redis'
|
||||
"django.contrib.admin",
|
||||
"django.contrib.auth",
|
||||
"django.contrib.contenttypes",
|
||||
"django.contrib.sessions",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
"django_q",
|
||||
"django_redis",
|
||||
)
|
||||
|
||||
|
||||
MIDDLEWARE_CLASSES = (
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.middleware.csrf.CsrfViewMiddleware",
|
||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||
"django.contrib.messages.middleware.MessageMiddleware",
|
||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||
)
|
||||
|
||||
MIDDLEWARE = MIDDLEWARE_CLASSES
|
||||
|
||||
ROOT_URLCONF = 'tests.urls'
|
||||
ROOT_URLCONF = "tests.urls"
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||
"DIRS": [],
|
||||
"APP_DIRS": True,
|
||||
"OPTIONS": {
|
||||
"context_processors": [
|
||||
"django.template.context_processors.debug",
|
||||
"django.template.context_processors.request",
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
],
|
||||
},
|
||||
},
|
||||
@@ -64,9 +65,9 @@ TEMPLATES = [
|
||||
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.sqlite3",
|
||||
"NAME": os.path.join(BASE_DIR, "db.sqlite3"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,9 +75,9 @@ DATABASES = {
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/2.2/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
LANGUAGE_CODE = "en-us"
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
TIME_ZONE = "UTC"
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
@@ -85,17 +86,17 @@ USE_L10N = True
|
||||
USE_TZ = True
|
||||
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'handlers': {
|
||||
'console': {
|
||||
'class': 'logging.StreamHandler',
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"handlers": {
|
||||
"console": {
|
||||
"class": "logging.StreamHandler",
|
||||
},
|
||||
},
|
||||
'loggers': {
|
||||
'django_q': {
|
||||
'handlers': ['console'],
|
||||
'level': 'INFO',
|
||||
"loggers": {
|
||||
"django_q": {
|
||||
"handlers": ["console"],
|
||||
"level": "INFO",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -103,7 +104,7 @@ LOGGING = {
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/2.2/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
STATIC_URL = "/static/"
|
||||
|
||||
# Django Redis
|
||||
CACHES = {
|
||||
@@ -113,13 +114,15 @@ CACHES = {
|
||||
"OPTIONS": {
|
||||
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
||||
"PARSER_CLASS": "redis.connection.HiredisParser",
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
# Django Q specific
|
||||
Q_CLUSTER = {'name': 'django_q_test',
|
||||
'cpu_affinity': 1,
|
||||
'testing': True,
|
||||
'log_level': 'DEBUG',
|
||||
'django_redis': 'default'}
|
||||
Q_CLUSTER = {
|
||||
"name": "django_q_test",
|
||||
"cpu_affinity": 1,
|
||||
"testing": True,
|
||||
"log_level": "DEBUG",
|
||||
"django_redis": "default",
|
||||
}
|
||||
|
||||
@@ -1,80 +1,86 @@
|
||||
import pytest
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
|
||||
import pytest
|
||||
|
||||
from django_q.tasks import schedule
|
||||
from django_q.models import Task, Failure, OrmQ
|
||||
from django_q.humanhash import uuid
|
||||
from django_q.conf import Conf
|
||||
from django_q.humanhash import uuid
|
||||
from django_q.models import Failure, OrmQ, Task
|
||||
from django_q.signing import SignedPackage
|
||||
from django_q.tasks import schedule
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_admin_views(admin_client, monkeypatch):
|
||||
monkeypatch.setattr(Conf, 'ORM', 'default')
|
||||
s = schedule('schedule.test')
|
||||
monkeypatch.setattr(Conf, "ORM", "default")
|
||||
s = schedule("schedule.test")
|
||||
tag = uuid()
|
||||
f = Task.objects.create(
|
||||
id=tag[1],
|
||||
name=tag[0],
|
||||
func='test.fail',
|
||||
func="test.fail",
|
||||
started=timezone.now(),
|
||||
stopped=timezone.now(),
|
||||
success=False)
|
||||
success=False,
|
||||
)
|
||||
tag = uuid()
|
||||
t = Task.objects.create(
|
||||
id=tag[1],
|
||||
name=tag[0],
|
||||
func='test.success',
|
||||
func="test.success",
|
||||
started=timezone.now(),
|
||||
stopped=timezone.now(),
|
||||
success=True)
|
||||
success=True,
|
||||
)
|
||||
q = OrmQ.objects.create(
|
||||
key='test',
|
||||
payload=SignedPackage.dumps({'id': 1, 'func': 'test', 'name': 'test'}))
|
||||
key="test",
|
||||
payload=SignedPackage.dumps({"id": 1, "func": "test", "name": "test"}),
|
||||
)
|
||||
admin_urls = (
|
||||
# schedule
|
||||
reverse('admin:django_q_schedule_changelist'),
|
||||
reverse('admin:django_q_schedule_add'),
|
||||
reverse('admin:django_q_schedule_change', args=(s.id,)),
|
||||
reverse('admin:django_q_schedule_history', args=(s.id,)),
|
||||
reverse('admin:django_q_schedule_delete', args=(s.id,)),
|
||||
reverse("admin:django_q_schedule_changelist"),
|
||||
reverse("admin:django_q_schedule_add"),
|
||||
reverse("admin:django_q_schedule_change", args=(s.id,)),
|
||||
reverse("admin:django_q_schedule_history", args=(s.id,)),
|
||||
reverse("admin:django_q_schedule_delete", args=(s.id,)),
|
||||
# success
|
||||
reverse('admin:django_q_success_changelist'),
|
||||
reverse('admin:django_q_success_change', args=(t.id,)),
|
||||
reverse('admin:django_q_success_history', args=(t.id,)),
|
||||
reverse('admin:django_q_success_delete', args=(t.id,)),
|
||||
reverse("admin:django_q_success_changelist"),
|
||||
reverse("admin:django_q_success_change", args=(t.id,)),
|
||||
reverse("admin:django_q_success_history", args=(t.id,)),
|
||||
reverse("admin:django_q_success_delete", args=(t.id,)),
|
||||
# failure
|
||||
reverse('admin:django_q_failure_changelist'),
|
||||
reverse('admin:django_q_failure_change', args=(f.id,)),
|
||||
reverse('admin:django_q_failure_history', args=(f.id,)),
|
||||
reverse('admin:django_q_failure_delete', args=(f.id,)),
|
||||
reverse("admin:django_q_failure_changelist"),
|
||||
reverse("admin:django_q_failure_change", args=(f.id,)),
|
||||
reverse("admin:django_q_failure_history", args=(f.id,)),
|
||||
reverse("admin:django_q_failure_delete", args=(f.id,)),
|
||||
# orm queue
|
||||
reverse('admin:django_q_ormq_changelist'),
|
||||
reverse('admin:django_q_ormq_change', args=(q.id,)),
|
||||
reverse('admin:django_q_ormq_history', args=(q.id,)),
|
||||
reverse('admin:django_q_ormq_delete', args=(q.id,)),
|
||||
|
||||
reverse("admin:django_q_ormq_changelist"),
|
||||
reverse("admin:django_q_ormq_change", args=(q.id,)),
|
||||
reverse("admin:django_q_ormq_history", args=(q.id,)),
|
||||
reverse("admin:django_q_ormq_delete", args=(q.id,)),
|
||||
)
|
||||
for url in admin_urls:
|
||||
response = admin_client.get(url)
|
||||
assert response.status_code == 200
|
||||
|
||||
# resubmit the failure
|
||||
url = reverse('admin:django_q_failure_changelist')
|
||||
data = {'action': 'retry_failed',
|
||||
'_selected_action': [f.pk]}
|
||||
url = reverse("admin:django_q_failure_changelist")
|
||||
data = {"action": "retry_failed", "_selected_action": [f.pk]}
|
||||
response = admin_client.post(url, data)
|
||||
assert response.status_code == 302
|
||||
assert Failure.objects.filter(name=f.id).exists() is False
|
||||
# change q
|
||||
url = reverse('admin:django_q_ormq_change', args=(q.id,))
|
||||
data = {'key': 'default', 'payload': 'test', 'lock_0': '2015-09-17', 'lock_1': '14:31:51', '_save': 'Save'}
|
||||
url = reverse("admin:django_q_ormq_change", args=(q.id,))
|
||||
data = {
|
||||
"key": "default",
|
||||
"payload": "test",
|
||||
"lock_0": "2015-09-17",
|
||||
"lock_1": "14:31:51",
|
||||
"_save": "Save",
|
||||
}
|
||||
response = admin_client.post(url, data)
|
||||
assert response.status_code == 302
|
||||
# delete q
|
||||
url = reverse('admin:django_q_ormq_delete', args=(q.id,))
|
||||
data = {'post': 'yes'}
|
||||
url = reverse("admin:django_q_ormq_delete", args=(q.id,))
|
||||
data = {"post": "yes"}
|
||||
response = admin_client.post(url, data)
|
||||
assert response.status_code == 302
|
||||
|
||||
@@ -4,7 +4,7 @@ from time import sleep
|
||||
import pytest
|
||||
import redis
|
||||
|
||||
from django_q.brokers import get_broker, Broker
|
||||
from django_q.brokers import Broker, get_broker
|
||||
from django_q.conf import Conf
|
||||
from django_q.humanhash import uuid
|
||||
|
||||
@@ -194,7 +194,7 @@ def canceled_sqs(monkeypatch):
|
||||
"aws_region": os.getenv("AWS_REGION"),
|
||||
"aws_access_key_id": os.getenv("AWS_ACCESS_KEY_ID"),
|
||||
"aws_secret_access_key": os.getenv("AWS_SECRET_ACCESS_KEY"),
|
||||
"receive_message_wait_time_seconds": 20
|
||||
"receive_message_wait_time_seconds": 20,
|
||||
},
|
||||
)
|
||||
# check broker
|
||||
|
||||
@@ -2,17 +2,30 @@ from multiprocessing import Event, Value
|
||||
|
||||
import pytest
|
||||
|
||||
from django_q.cluster import pusher, worker, monitor
|
||||
from django_q.conf import Conf
|
||||
from django_q.tasks import async_task, result, fetch, count_group, result_group, fetch_group, delete_group, delete_cached, \
|
||||
async_iter, Chain, async_chain, Iter, AsyncTask
|
||||
from django_q.brokers import get_broker
|
||||
from django_q.cluster import monitor, pusher, worker
|
||||
from django_q.conf import Conf
|
||||
from django_q.queues import Queue
|
||||
from django_q.tasks import (
|
||||
AsyncTask,
|
||||
Chain,
|
||||
Iter,
|
||||
async_chain,
|
||||
async_iter,
|
||||
async_task,
|
||||
count_group,
|
||||
delete_cached,
|
||||
delete_group,
|
||||
fetch,
|
||||
fetch_group,
|
||||
result,
|
||||
result_group,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def broker(monkeypatch):
|
||||
monkeypatch.setattr(Conf, 'DJANGO_REDIS', 'default')
|
||||
monkeypatch.setattr(Conf, "DJANGO_REDIS", "default")
|
||||
return get_broker()
|
||||
|
||||
|
||||
@@ -20,16 +33,16 @@ def broker(monkeypatch):
|
||||
def test_cached(broker):
|
||||
broker.purge_queue()
|
||||
broker.cache.clear()
|
||||
group = 'cache_test'
|
||||
group = "cache_test"
|
||||
# queue the tests
|
||||
task_id = async_task('math.copysign', 1, -1, cached=True, broker=broker)
|
||||
async_task('math.copysign', 1, -1, cached=True, broker=broker, group=group)
|
||||
async_task('math.copysign', 1, -1, cached=True, broker=broker, group=group)
|
||||
async_task('math.copysign', 1, -1, cached=True, broker=broker, group=group)
|
||||
async_task('math.copysign', 1, -1, cached=True, broker=broker, group=group)
|
||||
async_task('math.copysign', 1, -1, cached=True, broker=broker, group=group)
|
||||
async_task('math.popysign', 1, -1, cached=True, broker=broker, group=group)
|
||||
iter_id = async_iter('math.floor', [i for i in range(10)], cached=True)
|
||||
task_id = async_task("math.copysign", 1, -1, cached=True, broker=broker)
|
||||
async_task("math.copysign", 1, -1, cached=True, broker=broker, group=group)
|
||||
async_task("math.copysign", 1, -1, cached=True, broker=broker, group=group)
|
||||
async_task("math.copysign", 1, -1, cached=True, broker=broker, group=group)
|
||||
async_task("math.copysign", 1, -1, cached=True, broker=broker, group=group)
|
||||
async_task("math.copysign", 1, -1, cached=True, broker=broker, group=group)
|
||||
async_task("math.popysign", 1, -1, cached=True, broker=broker, group=group)
|
||||
iter_id = async_iter("math.floor", [i for i in range(10)], cached=True)
|
||||
# test wait on cache
|
||||
# test wait timeout
|
||||
assert result(task_id, wait=10, cached=True) is None
|
||||
@@ -48,11 +61,11 @@ def test_cached(broker):
|
||||
pusher(task_queue, stop_event, broker=broker)
|
||||
assert broker.queue_size() == 0
|
||||
assert task_queue.qsize() == task_count
|
||||
task_queue.put('STOP')
|
||||
task_queue.put("STOP")
|
||||
result_queue = Queue()
|
||||
worker(task_queue, result_queue, Value('f', -1))
|
||||
worker(task_queue, result_queue, Value("f", -1))
|
||||
assert result_queue.qsize() == task_count
|
||||
result_queue.put('STOP')
|
||||
result_queue.put("STOP")
|
||||
monitor(result_queue)
|
||||
assert result_queue.qsize() == 0
|
||||
# assert results
|
||||
@@ -85,10 +98,10 @@ def test_iter(broker):
|
||||
it = [i for i in range(10)]
|
||||
it2 = [(1, -1), (2, -1), (3, -4), (5, 6)]
|
||||
it3 = (1, 2, 3, 4, 5)
|
||||
t = async_iter('math.floor', it, sync=True)
|
||||
t2 = async_iter('math.copysign', it2, sync=True)
|
||||
t3 = async_iter('math.floor', it3, sync=True)
|
||||
t4 = async_iter('math.floor', (1,), sync=True)
|
||||
t = async_iter("math.floor", it, sync=True)
|
||||
t2 = async_iter("math.copysign", it2, sync=True)
|
||||
t3 = async_iter("math.floor", it3, sync=True)
|
||||
t4 = async_iter("math.floor", (1,), sync=True)
|
||||
result_t = result(t)
|
||||
assert result_t is not None
|
||||
task_t = fetch(t)
|
||||
@@ -97,7 +110,7 @@ def test_iter(broker):
|
||||
assert result(t3) is not None
|
||||
assert result(t4)[0] == 1
|
||||
# test iter class
|
||||
i = Iter('math.copysign', sync=True, cached=True)
|
||||
i = Iter("math.copysign", sync=True, cached=True)
|
||||
i.append(1, -1)
|
||||
i.append(2, -1)
|
||||
i.append(3, -4)
|
||||
@@ -118,9 +131,9 @@ def test_chain(broker):
|
||||
broker.purge_queue()
|
||||
broker.cache.clear()
|
||||
task_chain = Chain(sync=True)
|
||||
task_chain.append('math.floor', 1)
|
||||
task_chain.append('math.copysign', 1, -1)
|
||||
task_chain.append('math.floor', 2)
|
||||
task_chain.append("math.floor", 1)
|
||||
task_chain.append("math.copysign", 1, -1)
|
||||
task_chain.append("math.floor", 2)
|
||||
assert task_chain.length() == 3
|
||||
assert task_chain.current() is None
|
||||
task_chain.run()
|
||||
@@ -130,7 +143,7 @@ def test_chain(broker):
|
||||
t = task_chain.fetch()
|
||||
assert len(t) == task_chain.length()
|
||||
task_chain.cached = True
|
||||
task_chain.append('math.floor', 3)
|
||||
task_chain.append("math.floor", 3)
|
||||
assert task_chain.length() == 4
|
||||
task_chain.run()
|
||||
r = task_chain.result(wait=1000)
|
||||
@@ -139,16 +152,20 @@ def test_chain(broker):
|
||||
t = task_chain.fetch()
|
||||
assert len(t) == task_chain.length()
|
||||
# test single
|
||||
rid = async_chain(['django_q.tests.tasks.hello', 'django_q.tests.tasks.hello'], sync=True, cached=True)
|
||||
assert result_group(rid, cached=True) == ['hello', 'hello']
|
||||
rid = async_chain(
|
||||
["django_q.tests.tasks.hello", "django_q.tests.tasks.hello"],
|
||||
sync=True,
|
||||
cached=True,
|
||||
)
|
||||
assert result_group(rid, cached=True) == ["hello", "hello"]
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_asynctask_class(broker, monkeypatch):
|
||||
broker.purge_queue()
|
||||
broker.cache.clear()
|
||||
a = AsyncTask('math.copysign')
|
||||
assert a.func == 'math.copysign'
|
||||
a = AsyncTask("math.copysign")
|
||||
assert a.func == "math.copysign"
|
||||
a.args = (1, -1)
|
||||
assert a.started is False
|
||||
a.cached = True
|
||||
@@ -161,29 +178,34 @@ def test_asynctask_class(broker, monkeypatch):
|
||||
assert a.result() == -1
|
||||
assert a.fetch().result == -1
|
||||
# again with kwargs
|
||||
a = AsyncTask('math.copysign', 1, -1, cached=True, sync=True, broker=broker)
|
||||
a = AsyncTask("math.copysign", 1, -1, cached=True, sync=True, broker=broker)
|
||||
a.run()
|
||||
assert a.result() == -1
|
||||
# with q_options
|
||||
a = AsyncTask('math.copysign', 1, -1, q_options={'cached': True, 'sync': False, 'broker': broker})
|
||||
a = AsyncTask(
|
||||
"math.copysign",
|
||||
1,
|
||||
-1,
|
||||
q_options={"cached": True, "sync": False, "broker": broker},
|
||||
)
|
||||
assert not a.sync
|
||||
a.sync = True
|
||||
assert a.kwargs['q_options']['sync'] is True
|
||||
assert a.kwargs["q_options"]["sync"] is True
|
||||
a.run()
|
||||
assert a.result() == -1
|
||||
a.group = 'async_class_test'
|
||||
assert a.group == 'async_class_test'
|
||||
a.group = "async_class_test"
|
||||
assert a.group == "async_class_test"
|
||||
a.save = False
|
||||
assert not a.save
|
||||
a.hook = 'djq.tests.tasks.hello'
|
||||
assert a.hook == 'djq.tests.tasks.hello'
|
||||
a.hook = "djq.tests.tasks.hello"
|
||||
assert a.hook == "djq.tests.tasks.hello"
|
||||
assert a.started is False
|
||||
a.run()
|
||||
assert a.result_group() == [-1]
|
||||
assert a.fetch_group() == [a.fetch()]
|
||||
# global overrides
|
||||
monkeypatch.setattr(Conf, 'SYNC', True)
|
||||
monkeypatch.setattr(Conf, 'CACHED', True)
|
||||
a = AsyncTask('math.floor', 1.5)
|
||||
monkeypatch.setattr(Conf, "SYNC", True)
|
||||
monkeypatch.setattr(Conf, "CACHED", True)
|
||||
a = AsyncTask("math.floor", 1.5)
|
||||
a.run()
|
||||
assert a.result() == 1
|
||||
|
||||
@@ -1,25 +1,34 @@
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
import uuid as uuidlib
|
||||
from multiprocessing import Event, Value
|
||||
from time import sleep
|
||||
from django.utils import timezone
|
||||
import uuid as uuidlib
|
||||
|
||||
import os
|
||||
import pytest
|
||||
from django.utils import timezone
|
||||
|
||||
myPath = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, myPath + '/../')
|
||||
sys.path.insert(0, myPath + "/../")
|
||||
|
||||
from django_q.cluster import Cluster, Sentinel, pusher, worker, monitor, save_task
|
||||
from django_q.humanhash import DEFAULT_WORDLIST, uuid
|
||||
from django_q.tasks import fetch, fetch_group, async_task, result, result_group, count_group, delete_group, queue_size
|
||||
from django_q.models import Task, Success
|
||||
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
|
||||
from django_q.status import Stat
|
||||
from django_q.brokers import get_broker, Broker
|
||||
from django_q.tests.tasks import multiply, TaskError
|
||||
from django_q.humanhash import DEFAULT_WORDLIST, uuid
|
||||
from django_q.models import Success, Task
|
||||
from django_q.queues import Queue
|
||||
from django_q.status import Stat
|
||||
from django_q.tasks import (
|
||||
async_task,
|
||||
count_group,
|
||||
delete_group,
|
||||
fetch,
|
||||
fetch_group,
|
||||
queue_size,
|
||||
result,
|
||||
result_group,
|
||||
)
|
||||
from django_q.tests.tasks import TaskError, multiply
|
||||
|
||||
|
||||
class WordClass:
|
||||
@@ -32,7 +41,7 @@ class WordClass:
|
||||
|
||||
@pytest.fixture
|
||||
def broker(monkeypatch):
|
||||
monkeypatch.setattr(Conf, 'DJANGO_REDIS', 'default')
|
||||
monkeypatch.setattr(Conf, "DJANGO_REDIS", "default")
|
||||
return get_broker()
|
||||
|
||||
|
||||
@@ -42,19 +51,21 @@ def test_redis_connection(broker):
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_sync(broker):
|
||||
task = async_task('django_q.tests.tasks.count_letters', DEFAULT_WORDLIST, broker=broker, sync=True)
|
||||
task = async_task(
|
||||
"django_q.tests.tasks.count_letters", DEFAULT_WORDLIST, broker=broker, sync=True
|
||||
)
|
||||
assert result(task) == 1506
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_sync_raise_exception(broker):
|
||||
with pytest.raises(TaskError):
|
||||
async_task('django_q.tests.tasks.raise_exception', broker=broker, sync=True)
|
||||
async_task("django_q.tests.tasks.raise_exception", broker=broker, sync=True)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_cluster_initial(broker):
|
||||
broker.list_key = 'initial_test:q'
|
||||
broker.list_key = "initial_test:q"
|
||||
broker.delete_queue()
|
||||
c = Cluster(broker=broker)
|
||||
assert c.sentinel is None
|
||||
@@ -80,16 +91,23 @@ def test_sentinel():
|
||||
stop_event = Event()
|
||||
stop_event.set()
|
||||
cluster_id = uuidlib.uuid4()
|
||||
s = Sentinel(stop_event, start_event, cluster_id=cluster_id, broker=get_broker('sentinel_test:q'))
|
||||
s = Sentinel(
|
||||
stop_event,
|
||||
start_event,
|
||||
cluster_id=cluster_id,
|
||||
broker=get_broker("sentinel_test:q"),
|
||||
)
|
||||
assert start_event.is_set()
|
||||
assert s.status() == Conf.STOPPED
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_cluster(broker):
|
||||
broker.list_key = 'cluster_test:q'
|
||||
broker.list_key = "cluster_test:q"
|
||||
broker.delete_queue()
|
||||
task = async_task('django_q.tests.tasks.count_letters', DEFAULT_WORDLIST, broker=broker)
|
||||
task = async_task(
|
||||
"django_q.tests.tasks.count_letters", DEFAULT_WORDLIST, broker=broker
|
||||
)
|
||||
assert broker.queue_size() == 1
|
||||
task_queue = Queue()
|
||||
assert task_queue.qsize() == 0
|
||||
@@ -102,12 +120,12 @@ def test_cluster(broker):
|
||||
assert task_queue.qsize() == 1
|
||||
assert queue_size(broker=broker) == 0
|
||||
# Test work
|
||||
task_queue.put('STOP')
|
||||
worker(task_queue, result_queue, Value('f', -1))
|
||||
task_queue.put("STOP")
|
||||
worker(task_queue, result_queue, Value("f", -1))
|
||||
assert task_queue.qsize() == 0
|
||||
assert result_queue.qsize() == 1
|
||||
# Test monitor
|
||||
result_queue.put('STOP')
|
||||
result_queue.put("STOP")
|
||||
monitor(result_queue)
|
||||
assert result_queue.qsize() == 0
|
||||
# check result
|
||||
@@ -117,33 +135,63 @@ def test_cluster(broker):
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_enqueue(broker, admin_user):
|
||||
broker.list_key = 'cluster_test:q'
|
||||
broker.list_key = "cluster_test:q"
|
||||
broker.delete_queue()
|
||||
a = async_task('django_q.tests.tasks.count_letters', DEFAULT_WORDLIST, hook='django_q.tests.test_cluster.assert_result',
|
||||
broker=broker)
|
||||
b = async_task('django_q.tests.tasks.count_letters2', WordClass(), hook='django_q.tests.test_cluster.assert_result',
|
||||
broker=broker)
|
||||
a = async_task(
|
||||
"django_q.tests.tasks.count_letters",
|
||||
DEFAULT_WORDLIST,
|
||||
hook="django_q.tests.test_cluster.assert_result",
|
||||
broker=broker,
|
||||
)
|
||||
b = async_task(
|
||||
"django_q.tests.tasks.count_letters2",
|
||||
WordClass(),
|
||||
hook="django_q.tests.test_cluster.assert_result",
|
||||
broker=broker,
|
||||
)
|
||||
# unknown argument
|
||||
c = async_task('django_q.tests.tasks.count_letters', DEFAULT_WORDLIST, 'oneargumentoomany',
|
||||
hook='django_q.tests.test_cluster.assert_bad_result', broker=broker)
|
||||
c = async_task(
|
||||
"django_q.tests.tasks.count_letters",
|
||||
DEFAULT_WORDLIST,
|
||||
"oneargumentoomany",
|
||||
hook="django_q.tests.test_cluster.assert_bad_result",
|
||||
broker=broker,
|
||||
)
|
||||
# unknown function
|
||||
d = async_task('django_q.tests.tasks.does_not_exist', WordClass(), hook='django_q.tests.test_cluster.assert_bad_result',
|
||||
broker=broker)
|
||||
d = async_task(
|
||||
"django_q.tests.tasks.does_not_exist",
|
||||
WordClass(),
|
||||
hook="django_q.tests.test_cluster.assert_bad_result",
|
||||
broker=broker,
|
||||
)
|
||||
# function without result
|
||||
e = async_task('django_q.tests.tasks.countdown', 100000, broker=broker)
|
||||
e = async_task("django_q.tests.tasks.countdown", 100000, broker=broker)
|
||||
# function as instance
|
||||
f = async_task(multiply, 753, 2, hook=assert_result, broker=broker)
|
||||
# model as argument
|
||||
g = async_task('django_q.tests.tasks.get_task_name', Task(name='John'), broker=broker)
|
||||
g = async_task(
|
||||
"django_q.tests.tasks.get_task_name", Task(name="John"), broker=broker
|
||||
)
|
||||
# args,kwargs, group and broken hook
|
||||
h = async_task('django_q.tests.tasks.word_multiply', 2, word='django', hook='fail.me', broker=broker)
|
||||
h = async_task(
|
||||
"django_q.tests.tasks.word_multiply",
|
||||
2,
|
||||
word="django",
|
||||
hook="fail.me",
|
||||
broker=broker,
|
||||
)
|
||||
# args unpickle test
|
||||
j = async_task('django_q.tests.tasks.get_user_id', admin_user, broker=broker, group='test_j')
|
||||
j = async_task(
|
||||
"django_q.tests.tasks.get_user_id", admin_user, broker=broker, group="test_j"
|
||||
)
|
||||
# q_options and save opt_out test
|
||||
k = async_task('django_q.tests.tasks.get_user_id', admin_user,
|
||||
q_options={'broker': broker, 'group': 'test_k', 'save': False, 'timeout': 90})
|
||||
k = async_task(
|
||||
"django_q.tests.tasks.get_user_id",
|
||||
admin_user,
|
||||
q_options={"broker": broker, "group": "test_k", "save": False, "timeout": 90},
|
||||
)
|
||||
# test unicode
|
||||
assert Task(name='Amalia').__str__()=='Amalia'
|
||||
assert Task(name="Amalia").__str__() == "Amalia"
|
||||
# check if everything has a task id
|
||||
assert isinstance(a, str)
|
||||
assert isinstance(b, str)
|
||||
@@ -166,19 +214,19 @@ def test_enqueue(broker, admin_user):
|
||||
pusher(task_queue, stop_event, broker=broker)
|
||||
assert broker.queue_size() == 0
|
||||
assert task_queue.qsize() == task_count
|
||||
task_queue.put('STOP')
|
||||
task_queue.put("STOP")
|
||||
# test wait timeout
|
||||
assert result(j, wait=10) is None
|
||||
assert fetch(j, wait=10) is None
|
||||
assert result_group('test_j', wait=10) is None
|
||||
assert result_group('test_j', count=2, wait=10) is None
|
||||
assert fetch_group('test_j', wait=10) is None
|
||||
assert fetch_group('test_j', count=2, wait=10) is None
|
||||
assert result_group("test_j", wait=10) is None
|
||||
assert result_group("test_j", count=2, wait=10) is None
|
||||
assert fetch_group("test_j", wait=10) is None
|
||||
assert fetch_group("test_j", count=2, wait=10) is None
|
||||
# let a worker handle them
|
||||
result_queue = Queue()
|
||||
worker(task_queue, result_queue, Value('f', -1))
|
||||
worker(task_queue, result_queue, Value("f", -1))
|
||||
assert result_queue.qsize() == task_count
|
||||
result_queue.put('STOP')
|
||||
result_queue.put("STOP")
|
||||
# store the results
|
||||
monitor(result_queue)
|
||||
assert result_queue.qsize() == 0
|
||||
@@ -215,7 +263,7 @@ def test_enqueue(broker, admin_user):
|
||||
result_g = fetch(g)
|
||||
assert result_g is not None
|
||||
assert result_g.success is True
|
||||
assert result(g) == 'John'
|
||||
assert result(g) == "John"
|
||||
# task h
|
||||
result_h = fetch(h)
|
||||
assert result_h is not None
|
||||
@@ -230,19 +278,19 @@ def test_enqueue(broker, admin_user):
|
||||
assert fetch(result_j.name) == result_j
|
||||
assert result(result_j.name) == result_j.result
|
||||
# groups
|
||||
assert result_group('test_j')[0] == result_j.result
|
||||
assert result_group("test_j")[0] == result_j.result
|
||||
assert result_j.group_result()[0] == result_j.result
|
||||
assert result_group('test_j', failures=True)[0] == result_j.result
|
||||
assert result_group("test_j", failures=True)[0] == result_j.result
|
||||
assert result_j.group_result(failures=True)[0] == result_j.result
|
||||
assert fetch_group('test_j')[0].id == [result_j][0].id
|
||||
assert fetch_group('test_j', failures=False)[0].id == [result_j][0].id
|
||||
assert count_group('test_j') == 1
|
||||
assert fetch_group("test_j")[0].id == [result_j][0].id
|
||||
assert fetch_group("test_j", failures=False)[0].id == [result_j][0].id
|
||||
assert count_group("test_j") == 1
|
||||
assert result_j.group_count() == 1
|
||||
assert count_group('test_j', failures=True) == 0
|
||||
assert count_group("test_j", failures=True) == 0
|
||||
assert result_j.group_count(failures=True) == 0
|
||||
assert delete_group('test_j') == 1
|
||||
assert delete_group("test_j") == 1
|
||||
assert result_j.group_delete() == 0
|
||||
deleted_group = delete_group('test_j', tasks=True)
|
||||
deleted_group = delete_group("test_j", tasks=True)
|
||||
assert deleted_group is None or deleted_group[0] == 0 # Django 1.9
|
||||
deleted_group = result_j.group_delete(tasks=True)
|
||||
assert deleted_group is None or deleted_group[0] == 0 # Django 1.9
|
||||
@@ -254,22 +302,31 @@ def test_enqueue(broker, admin_user):
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize('cluster_config_timeout, async_task_kwargs', (
|
||||
(1, {}),
|
||||
(10, {'timeout': 1}),
|
||||
(None, {'timeout': 1}),
|
||||
))
|
||||
@pytest.mark.parametrize(
|
||||
"cluster_config_timeout, async_task_kwargs",
|
||||
(
|
||||
(1, {}),
|
||||
(10, {"timeout": 1}),
|
||||
(None, {"timeout": 1}),
|
||||
),
|
||||
)
|
||||
def test_timeout(broker, cluster_config_timeout, async_task_kwargs):
|
||||
# set up the Sentinel
|
||||
broker.list_key = 'timeout_test:q'
|
||||
broker.list_key = "timeout_test:q"
|
||||
broker.purge_queue()
|
||||
async_task('time.sleep', 5, broker=broker, **async_task_kwargs)
|
||||
async_task("time.sleep", 5, broker=broker, **async_task_kwargs)
|
||||
start_event = Event()
|
||||
stop_event = Event()
|
||||
cluster_id = uuidlib.uuid4()
|
||||
# Set a timer to stop the Sentinel
|
||||
threading.Timer(3, stop_event.set).start()
|
||||
s = Sentinel(stop_event, start_event, cluster_id=cluster_id, broker=broker, timeout=cluster_config_timeout)
|
||||
s = Sentinel(
|
||||
stop_event,
|
||||
start_event,
|
||||
cluster_id=cluster_id,
|
||||
broker=broker,
|
||||
timeout=cluster_config_timeout,
|
||||
)
|
||||
assert start_event.is_set()
|
||||
assert s.status() == Conf.STOPPED
|
||||
assert s.reincarnations == 1
|
||||
@@ -277,23 +334,32 @@ def test_timeout(broker, cluster_config_timeout, async_task_kwargs):
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize('cluster_config_timeout, async_task_kwargs', (
|
||||
(5, {}),
|
||||
(10, {'timeout': 5}),
|
||||
(1, {'timeout': 5}),
|
||||
(None, {'timeout': 5}),
|
||||
))
|
||||
@pytest.mark.parametrize(
|
||||
"cluster_config_timeout, async_task_kwargs",
|
||||
(
|
||||
(5, {}),
|
||||
(10, {"timeout": 5}),
|
||||
(1, {"timeout": 5}),
|
||||
(None, {"timeout": 5}),
|
||||
),
|
||||
)
|
||||
def test_timeout_task_finishes(broker, cluster_config_timeout, async_task_kwargs):
|
||||
# set up the Sentinel
|
||||
broker.list_key = 'timeout_test:q'
|
||||
broker.list_key = "timeout_test:q"
|
||||
broker.purge_queue()
|
||||
async_task('time.sleep', 3, broker=broker, **async_task_kwargs)
|
||||
async_task("time.sleep", 3, broker=broker, **async_task_kwargs)
|
||||
start_event = Event()
|
||||
stop_event = Event()
|
||||
cluster_id = uuidlib.uuid4()
|
||||
# Set a timer to stop the Sentinel
|
||||
threading.Timer(6, stop_event.set).start()
|
||||
s = Sentinel(stop_event, start_event, cluster_id=cluster_id, broker=broker, timeout=cluster_config_timeout)
|
||||
s = Sentinel(
|
||||
stop_event,
|
||||
start_event,
|
||||
cluster_id=cluster_id,
|
||||
broker=broker,
|
||||
timeout=cluster_config_timeout,
|
||||
)
|
||||
assert start_event.is_set()
|
||||
assert s.status() == Conf.STOPPED
|
||||
assert s.reincarnations == 0
|
||||
@@ -303,70 +369,71 @@ def test_timeout_task_finishes(broker, cluster_config_timeout, async_task_kwargs
|
||||
@pytest.mark.django_db
|
||||
def test_recycle(broker, monkeypatch):
|
||||
# set up the Sentinel
|
||||
broker.list_key = 'test_recycle_test:q'
|
||||
async_task('django_q.tests.tasks.multiply', 2, 2, broker=broker)
|
||||
async_task('django_q.tests.tasks.multiply', 2, 2, broker=broker)
|
||||
async_task('django_q.tests.tasks.multiply', 2, 2, broker=broker)
|
||||
broker.list_key = "test_recycle_test:q"
|
||||
async_task("django_q.tests.tasks.multiply", 2, 2, broker=broker)
|
||||
async_task("django_q.tests.tasks.multiply", 2, 2, broker=broker)
|
||||
async_task("django_q.tests.tasks.multiply", 2, 2, broker=broker)
|
||||
start_event = Event()
|
||||
stop_event = Event()
|
||||
cluster_id = uuidlib.uuid4()
|
||||
# override settings
|
||||
monkeypatch.setattr(Conf, 'RECYCLE', 2)
|
||||
monkeypatch.setattr(Conf, 'WORKERS', 1)
|
||||
monkeypatch.setattr(Conf, "RECYCLE", 2)
|
||||
monkeypatch.setattr(Conf, "WORKERS", 1)
|
||||
# set a timer to stop the Sentinel
|
||||
threading.Timer(3, stop_event.set).start()
|
||||
s = Sentinel(stop_event, start_event, cluster_id=cluster_id, broker=broker)
|
||||
assert start_event.is_set()
|
||||
assert s.status() == Conf.STOPPED
|
||||
assert s.reincarnations == 1
|
||||
async_task('django_q.tests.tasks.multiply', 2, 2, broker=broker)
|
||||
async_task('django_q.tests.tasks.multiply', 2, 2, broker=broker)
|
||||
async_task("django_q.tests.tasks.multiply", 2, 2, broker=broker)
|
||||
async_task("django_q.tests.tasks.multiply", 2, 2, broker=broker)
|
||||
task_queue = Queue()
|
||||
result_queue = Queue()
|
||||
# push two tasks
|
||||
pusher(task_queue, stop_event, broker=broker)
|
||||
pusher(task_queue, stop_event, broker=broker)
|
||||
# worker should exit on recycle
|
||||
worker(task_queue, result_queue, Value('f', -1))
|
||||
worker(task_queue, result_queue, Value("f", -1))
|
||||
# check if the work has been done
|
||||
assert result_queue.qsize() == 2
|
||||
# save_limit test
|
||||
monkeypatch.setattr(Conf, 'SAVE_LIMIT', 1)
|
||||
result_queue.put('STOP')
|
||||
monkeypatch.setattr(Conf, "SAVE_LIMIT", 1)
|
||||
result_queue.put("STOP")
|
||||
# run monitor
|
||||
monitor(result_queue)
|
||||
assert Success.objects.count() == Conf.SAVE_LIMIT
|
||||
broker.delete_queue()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_max_rss(broker, monkeypatch):
|
||||
# set up the Sentinel
|
||||
broker.list_key = 'test_max_rss_test:q'
|
||||
async_task('django_q.tests.tasks.multiply', 2, 2, broker=broker)
|
||||
broker.list_key = "test_max_rss_test:q"
|
||||
async_task("django_q.tests.tasks.multiply", 2, 2, broker=broker)
|
||||
start_event = Event()
|
||||
stop_event = Event()
|
||||
cluster_id = uuidlib.uuid4()
|
||||
# override settings
|
||||
monkeypatch.setattr(Conf, 'MAX_RSS', 40000)
|
||||
monkeypatch.setattr(Conf, 'WORKERS', 1)
|
||||
monkeypatch.setattr(Conf, "MAX_RSS", 40000)
|
||||
monkeypatch.setattr(Conf, "WORKERS", 1)
|
||||
# set a timer to stop the Sentinel
|
||||
threading.Timer(3, stop_event.set).start()
|
||||
s = Sentinel(stop_event, start_event, cluster_id=cluster_id, broker=broker)
|
||||
assert start_event.is_set()
|
||||
assert s.status() == Conf.STOPPED
|
||||
assert s.reincarnations == 1
|
||||
async_task('django_q.tests.tasks.multiply', 2, 2, broker=broker)
|
||||
async_task("django_q.tests.tasks.multiply", 2, 2, broker=broker)
|
||||
task_queue = Queue()
|
||||
result_queue = Queue()
|
||||
# push the task
|
||||
pusher(task_queue, stop_event, broker=broker)
|
||||
# worker should exit on recycle
|
||||
worker(task_queue, result_queue, Value('f', -1))
|
||||
worker(task_queue, result_queue, Value("f", -1))
|
||||
# check if the work has been done
|
||||
assert result_queue.qsize() == 1
|
||||
# save_limit test
|
||||
monkeypatch.setattr(Conf, 'SAVE_LIMIT', 1)
|
||||
result_queue.put('STOP')
|
||||
monkeypatch.setattr(Conf, "SAVE_LIMIT", 1)
|
||||
result_queue.put("STOP")
|
||||
# run monitor
|
||||
monitor(result_queue)
|
||||
assert Success.objects.count() == Conf.SAVE_LIMIT
|
||||
@@ -375,13 +442,15 @@ def test_max_rss(broker, monkeypatch):
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_bad_secret(broker, monkeypatch):
|
||||
broker.list_key = 'test_bad_secret:q'
|
||||
async_task('math.copysign', 1, -1, broker=broker)
|
||||
broker.list_key = "test_bad_secret:q"
|
||||
async_task("math.copysign", 1, -1, broker=broker)
|
||||
stop_event = Event()
|
||||
stop_event.set()
|
||||
start_event = Event()
|
||||
cluster_id = uuidlib.uuid4()
|
||||
s = Sentinel(stop_event, start_event, cluster_id=cluster_id, broker=broker, start=False)
|
||||
s = Sentinel(
|
||||
stop_event, start_event, cluster_id=cluster_id, broker=broker, start=False
|
||||
)
|
||||
Stat(s).save()
|
||||
# change the SECRET
|
||||
monkeypatch.setattr(Conf, "SECRET_KEY", "OOPS")
|
||||
@@ -391,87 +460,94 @@ def test_bad_secret(broker, monkeypatch):
|
||||
task_queue = Queue()
|
||||
pusher(task_queue, stop_event, broker=broker)
|
||||
result_queue = Queue()
|
||||
task_queue.put('STOP')
|
||||
worker(task_queue, result_queue, Value('f', -1), )
|
||||
task_queue.put("STOP")
|
||||
worker(
|
||||
task_queue,
|
||||
result_queue,
|
||||
Value("f", -1),
|
||||
)
|
||||
assert result_queue.qsize() == 0
|
||||
broker.delete_queue()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_attempt_count(broker, monkeypatch):
|
||||
monkeypatch.setattr(Conf, 'MAX_ATTEMPTS', 3)
|
||||
monkeypatch.setattr(Conf, "MAX_ATTEMPTS", 3)
|
||||
tag = uuid()
|
||||
task = {'id': tag[1],
|
||||
'name': tag[0],
|
||||
'func': 'math.copysign',
|
||||
'args': (1, -1),
|
||||
'kwargs': {},
|
||||
'started': timezone.now(),
|
||||
'stopped': timezone.now(),
|
||||
'success': False,
|
||||
'result': None}
|
||||
task = {
|
||||
"id": tag[1],
|
||||
"name": tag[0],
|
||||
"func": "math.copysign",
|
||||
"args": (1, -1),
|
||||
"kwargs": {},
|
||||
"started": timezone.now(),
|
||||
"stopped": timezone.now(),
|
||||
"success": False,
|
||||
"result": None,
|
||||
}
|
||||
# initial save - no success
|
||||
save_task(task, broker)
|
||||
assert Task.objects.filter(id=task['id']).exists()
|
||||
saved_task = Task.objects.get(id=task['id'])
|
||||
assert Task.objects.filter(id=task["id"]).exists()
|
||||
saved_task = Task.objects.get(id=task["id"])
|
||||
assert saved_task.attempt_count == 1
|
||||
sleep(0.5)
|
||||
# second save
|
||||
old_stopped = task['stopped']
|
||||
task['stopped'] = timezone.now()
|
||||
old_stopped = task["stopped"]
|
||||
task["stopped"] = timezone.now()
|
||||
save_task(task, broker)
|
||||
saved_task = Task.objects.get(id=task['id'])
|
||||
saved_task = Task.objects.get(id=task["id"])
|
||||
assert saved_task.attempt_count == 2
|
||||
# third save -
|
||||
task['stopped'] = timezone.now()
|
||||
task["stopped"] = timezone.now()
|
||||
save_task(task, broker)
|
||||
saved_task = Task.objects.get(id=task['id'])
|
||||
saved_task = Task.objects.get(id=task["id"])
|
||||
assert saved_task.attempt_count == 3
|
||||
# task should be removed from queue
|
||||
assert broker.queue_size() == 0
|
||||
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_update_failed(broker):
|
||||
tag = uuid()
|
||||
task = {'id': tag[1],
|
||||
'name': tag[0],
|
||||
'func': 'math.copysign',
|
||||
'args': (1, -1),
|
||||
'kwargs': {},
|
||||
'started': timezone.now(),
|
||||
'stopped': timezone.now(),
|
||||
'success': False,
|
||||
'result': None}
|
||||
task = {
|
||||
"id": tag[1],
|
||||
"name": tag[0],
|
||||
"func": "math.copysign",
|
||||
"args": (1, -1),
|
||||
"kwargs": {},
|
||||
"started": timezone.now(),
|
||||
"stopped": timezone.now(),
|
||||
"success": False,
|
||||
"result": None,
|
||||
}
|
||||
# initial save - no success
|
||||
save_task(task, broker)
|
||||
assert Task.objects.filter(id=task['id']).exists()
|
||||
saved_task = Task.objects.get(id=task['id'])
|
||||
assert Task.objects.filter(id=task["id"]).exists()
|
||||
saved_task = Task.objects.get(id=task["id"])
|
||||
assert saved_task.success is False
|
||||
sleep(0.5)
|
||||
# second save - no success
|
||||
old_stopped = task['stopped']
|
||||
task['stopped'] = timezone.now()
|
||||
old_stopped = task["stopped"]
|
||||
task["stopped"] = timezone.now()
|
||||
save_task(task, broker)
|
||||
saved_task = Task.objects.get(id=task['id'])
|
||||
saved_task = Task.objects.get(id=task["id"])
|
||||
assert saved_task.stopped > old_stopped
|
||||
# third save - success
|
||||
task['stopped'] = timezone.now()
|
||||
task['result'] = 'result'
|
||||
task['success'] = True
|
||||
task["stopped"] = timezone.now()
|
||||
task["result"] = "result"
|
||||
task["success"] = True
|
||||
save_task(task, broker)
|
||||
saved_task = Task.objects.get(id=task['id'])
|
||||
saved_task = Task.objects.get(id=task["id"])
|
||||
assert saved_task.success is True
|
||||
# fourth save - no success
|
||||
task['result'] = None
|
||||
task['success'] = False
|
||||
task['stopped'] = old_stopped
|
||||
task["result"] = None
|
||||
task["success"] = False
|
||||
task["stopped"] = old_stopped
|
||||
save_task(task, broker)
|
||||
# should not overwrite success
|
||||
saved_task = Task.objects.get(id=task['id'])
|
||||
saved_task = Task.objects.get(id=task["id"])
|
||||
assert saved_task.success is True
|
||||
assert saved_task.result == 'result'
|
||||
assert saved_task.result == "result"
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@@ -486,47 +562,51 @@ def test_acknowledge_failure_override():
|
||||
self.acknowledgements[task_id] = count + 1
|
||||
|
||||
tag = uuid()
|
||||
task_fail_ack = {'id': tag[1],
|
||||
'name': tag[0],
|
||||
'ack_id': 'test_fail_ack_id',
|
||||
'ack_failure': True,
|
||||
'func': 'math.copysign',
|
||||
'args': (1, -1),
|
||||
'kwargs': {},
|
||||
'started': timezone.now(),
|
||||
'stopped': timezone.now(),
|
||||
'success': False,
|
||||
'result': None}
|
||||
task_fail_ack = {
|
||||
"id": tag[1],
|
||||
"name": tag[0],
|
||||
"ack_id": "test_fail_ack_id",
|
||||
"ack_failure": True,
|
||||
"func": "math.copysign",
|
||||
"args": (1, -1),
|
||||
"kwargs": {},
|
||||
"started": timezone.now(),
|
||||
"stopped": timezone.now(),
|
||||
"success": False,
|
||||
"result": None,
|
||||
}
|
||||
|
||||
tag = uuid()
|
||||
task_fail_no_ack = task_fail_ack.copy()
|
||||
task_fail_no_ack.update({'id': tag[1],
|
||||
'name': tag[0],
|
||||
'ack_id': 'test_fail_no_ack_id'})
|
||||
del task_fail_no_ack['ack_failure']
|
||||
task_fail_no_ack.update(
|
||||
{"id": tag[1], "name": tag[0], "ack_id": "test_fail_no_ack_id"}
|
||||
)
|
||||
del task_fail_no_ack["ack_failure"]
|
||||
|
||||
tag = uuid()
|
||||
task_success_ack = task_fail_ack.copy()
|
||||
task_success_ack.update({
|
||||
'id': tag[1],
|
||||
'name': tag[0],
|
||||
'ack_id': 'test_success_ack_id',
|
||||
'success': True,
|
||||
})
|
||||
del task_success_ack['ack_failure']
|
||||
task_success_ack.update(
|
||||
{
|
||||
"id": tag[1],
|
||||
"name": tag[0],
|
||||
"ack_id": "test_success_ack_id",
|
||||
"success": True,
|
||||
}
|
||||
)
|
||||
del task_success_ack["ack_failure"]
|
||||
|
||||
result_queue = Queue()
|
||||
result_queue.put(task_fail_ack)
|
||||
result_queue.put(task_fail_no_ack)
|
||||
result_queue.put(task_success_ack)
|
||||
result_queue.put('STOP')
|
||||
broker = VerifyAckMockBroker(list_key='key')
|
||||
result_queue.put("STOP")
|
||||
broker = VerifyAckMockBroker(list_key="key")
|
||||
|
||||
monitor(result_queue, broker)
|
||||
|
||||
assert broker.acknowledgements.get('test_fail_ack_id') == 1
|
||||
assert broker.acknowledgements.get('test_fail_no_ack_id') is None
|
||||
assert broker.acknowledgements.get('test_success_ack_id') == 1
|
||||
assert broker.acknowledgements.get("test_fail_ack_id") == 1
|
||||
assert broker.acknowledgements.get("test_fail_no_ack_id") is None
|
||||
assert broker.acknowledgements.get("test_success_ack_id") == 1
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
|
||||
@@ -4,22 +4,22 @@ from django.core.management import call_command
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_qcluster():
|
||||
call_command('qcluster', run_once=True)
|
||||
call_command("qcluster", run_once=True)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_qmonitor():
|
||||
call_command('qmonitor', run_once=True)
|
||||
call_command("qmonitor", run_once=True)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_qinfo():
|
||||
call_command('qinfo')
|
||||
call_command('qinfo', config=True)
|
||||
call_command('qinfo', ids=True)
|
||||
call_command("qinfo")
|
||||
call_command("qinfo", config=True)
|
||||
call_command("qinfo", ids=True)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_qmemory():
|
||||
call_command('qmemory', run_once=True)
|
||||
call_command('qmemory', workers=True, run_once=True)
|
||||
call_command("qmemory", run_once=True)
|
||||
call_command("qmemory", workers=True, run_once=True)
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import pytest
|
||||
import uuid
|
||||
|
||||
from django_q.tasks import async_task
|
||||
import pytest
|
||||
|
||||
from django_q.brokers import get_broker
|
||||
from django_q.cluster import Cluster
|
||||
from django_q.monitor import monitor, info, get_ids
|
||||
from django_q.status import Stat
|
||||
from django_q.conf import Conf
|
||||
from django_q.monitor import get_ids, info, monitor
|
||||
from django_q.status import Stat
|
||||
from django_q.tasks import async_task
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@@ -28,9 +29,9 @@ def test_monitor(monkeypatch):
|
||||
break
|
||||
assert found_c
|
||||
# test lock size
|
||||
monkeypatch.setattr(Conf, 'ORM', 'default')
|
||||
b = get_broker('monitor_test')
|
||||
b.enqueue('test')
|
||||
monkeypatch.setattr(Conf, "ORM", "default")
|
||||
b = get_broker("monitor_test")
|
||||
b.enqueue("test")
|
||||
b.dequeue()
|
||||
assert b.lock_size() == 1
|
||||
monitor(run_once=True, broker=b)
|
||||
@@ -48,4 +49,4 @@ def test_info():
|
||||
|
||||
|
||||
def do_sync():
|
||||
async_task('django_q.tests.tasks.countdown', 1, sync=True, save=True)
|
||||
async_task("django_q.tests.tasks.countdown", 1, sync=True, save=True)
|
||||
|
||||
@@ -9,89 +9,102 @@ from django.core.exceptions import ValidationError
|
||||
from django.db import IntegrityError
|
||||
from django.test import override_settings
|
||||
from django.utils import timezone
|
||||
from django.utils.timezone import is_naive
|
||||
|
||||
from django_q.brokers import get_broker, Broker
|
||||
from django_q.cluster import pusher, worker, monitor, scheduler
|
||||
from django_q.brokers import Broker, get_broker
|
||||
from django_q.cluster import monitor, pusher, scheduler, worker, localtime
|
||||
from django_q.conf import Conf
|
||||
from django_q.queues import Queue
|
||||
from django_q.tasks import Schedule, fetch, schedule as create_schedule
|
||||
from django_q.tasks import Schedule, fetch
|
||||
from django_q.tasks import schedule as create_schedule
|
||||
from django_q.tests.settings import BASE_DIR
|
||||
from django_q.tests.testing_utilities.multiple_database_routers import (TestingReplicaDatabaseRouter,
|
||||
TestingMultipleAppsDatabaseRouter)
|
||||
from django_q.tests.testing_utilities.multiple_database_routers import (
|
||||
TestingMultipleAppsDatabaseRouter,
|
||||
TestingReplicaDatabaseRouter,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def broker(monkeypatch) -> Broker:
|
||||
"""Patches the Conf object setting the DJANGO_REDIS attribute allowing a default redis configuration."""
|
||||
monkeypatch.setattr(Conf, 'DJANGO_REDIS', 'default')
|
||||
monkeypatch.setattr(Conf, "DJANGO_REDIS", "default")
|
||||
return get_broker()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def orm_broker(monkeypatch) -> None:
|
||||
"""Patches the Conf object setting the ORM attribute to a database named default."""
|
||||
monkeypatch.setattr(Conf, 'ORM', 'default')
|
||||
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')
|
||||
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')
|
||||
monkeypatch.setattr(Conf, "HAS_REPLICA", True)
|
||||
return get_broker(list_key="scheduler_test:q")
|
||||
|
||||
|
||||
REPLICA_DATABASE_ROUTERS = [f"{TestingReplicaDatabaseRouter.__module__}.{TestingReplicaDatabaseRouter.__name__}"]
|
||||
REPLICA_DATABASE_ROUTERS = [
|
||||
f"{TestingReplicaDatabaseRouter.__module__}.{TestingReplicaDatabaseRouter.__name__}"
|
||||
]
|
||||
REPLICA_DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.sqlite3",
|
||||
"NAME": os.path.join(BASE_DIR, "db.sqlite3"),
|
||||
},
|
||||
'replica': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||
"replica": {
|
||||
"ENGINE": "django.db.backends.sqlite3",
|
||||
"NAME": os.path.join(BASE_DIR, "db.sqlite3"),
|
||||
},
|
||||
}
|
||||
|
||||
MULTIPLE_APPS_DATABASE_ROUTERS = [
|
||||
f"{TestingMultipleAppsDatabaseRouter.__module__}.{TestingMultipleAppsDatabaseRouter.__name__}"]
|
||||
f"{TestingMultipleAppsDatabaseRouter.__module__}.{TestingMultipleAppsDatabaseRouter.__name__}"
|
||||
]
|
||||
MULTIPLE_APPS_DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.sqlite3",
|
||||
"NAME": os.path.join(BASE_DIR, "db.sqlite3"),
|
||||
},
|
||||
'admin': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||
"admin": {
|
||||
"ENGINE": "django.db.backends.sqlite3",
|
||||
"NAME": os.path.join(BASE_DIR, "db.sqlite3"),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_scheduler(broker, monkeypatch):
|
||||
broker.list_key = 'scheduler_test:q'
|
||||
broker.list_key = "scheduler_test:q"
|
||||
broker.delete_queue()
|
||||
schedule = create_schedule('math.copysign',
|
||||
1, -1,
|
||||
name='test math',
|
||||
hook='django_q.tests.tasks.result',
|
||||
schedule_type=Schedule.HOURLY,
|
||||
repeats=1)
|
||||
schedule = create_schedule(
|
||||
"math.copysign",
|
||||
1,
|
||||
-1,
|
||||
name="test math",
|
||||
hook="django_q.tests.tasks.result",
|
||||
schedule_type=Schedule.HOURLY,
|
||||
repeats=1,
|
||||
)
|
||||
assert schedule.last_run() is None
|
||||
# check duplicate constraint
|
||||
with pytest.raises(IntegrityError):
|
||||
schedule = create_schedule('math.copysign',
|
||||
1, -1,
|
||||
name='test math',
|
||||
hook='django_q.tests.tasks.result',
|
||||
schedule_type=Schedule.HOURLY,
|
||||
repeats=1)
|
||||
schedule = create_schedule(
|
||||
"math.copysign",
|
||||
1,
|
||||
-1,
|
||||
name="test math",
|
||||
hook="django_q.tests.tasks.result",
|
||||
schedule_type=Schedule.HOURLY,
|
||||
repeats=1,
|
||||
)
|
||||
# run scheduler
|
||||
scheduler(broker=broker)
|
||||
# set up the workflow
|
||||
@@ -102,12 +115,12 @@ def test_scheduler(broker, monkeypatch):
|
||||
pusher(task_queue, stop_event, broker=broker)
|
||||
assert task_queue.qsize() == 1
|
||||
assert broker.queue_size() == 0
|
||||
task_queue.put('STOP')
|
||||
task_queue.put("STOP")
|
||||
# let a worker handle them
|
||||
result_queue = Queue()
|
||||
worker(task_queue, result_queue, Value('b', -1))
|
||||
worker(task_queue, result_queue, Value("b", -1))
|
||||
assert result_queue.qsize() == 1
|
||||
result_queue.put('STOP')
|
||||
result_queue.put("STOP")
|
||||
# store the results
|
||||
monitor(result_queue)
|
||||
assert result_queue.qsize() == 0
|
||||
@@ -121,99 +134,113 @@ def test_scheduler(broker, monkeypatch):
|
||||
assert task.success is True
|
||||
assert task.result < 0
|
||||
# Once schedule with delete
|
||||
once_schedule = create_schedule('django_q.tests.tasks.word_multiply',
|
||||
2,
|
||||
word='django',
|
||||
schedule_type=Schedule.ONCE,
|
||||
repeats=-1,
|
||||
hook='django_q.tests.tasks.result'
|
||||
)
|
||||
assert hasattr(once_schedule, 'pk') is True
|
||||
once_schedule = create_schedule(
|
||||
"django_q.tests.tasks.word_multiply",
|
||||
2,
|
||||
word="django",
|
||||
schedule_type=Schedule.ONCE,
|
||||
repeats=-1,
|
||||
hook="django_q.tests.tasks.result",
|
||||
)
|
||||
assert hasattr(once_schedule, "pk") is True
|
||||
# negative repeats
|
||||
always_schedule = create_schedule('django_q.tests.tasks.word_multiply',
|
||||
2,
|
||||
word='django',
|
||||
schedule_type=Schedule.DAILY,
|
||||
repeats=-1,
|
||||
hook='django_q.tests.tasks.result'
|
||||
)
|
||||
assert hasattr(always_schedule, 'pk') is True
|
||||
always_schedule = create_schedule(
|
||||
"django_q.tests.tasks.word_multiply",
|
||||
2,
|
||||
word="django",
|
||||
schedule_type=Schedule.DAILY,
|
||||
repeats=-1,
|
||||
hook="django_q.tests.tasks.result",
|
||||
)
|
||||
assert hasattr(always_schedule, "pk") is True
|
||||
# Minute schedule
|
||||
minute_schedule = create_schedule('django_q.tests.tasks.word_multiply',
|
||||
2,
|
||||
word='django',
|
||||
schedule_type=Schedule.MINUTES,
|
||||
minutes=10)
|
||||
assert hasattr(minute_schedule, 'pk') is True
|
||||
minute_schedule = create_schedule(
|
||||
"django_q.tests.tasks.word_multiply",
|
||||
2,
|
||||
word="django",
|
||||
schedule_type=Schedule.MINUTES,
|
||||
minutes=10,
|
||||
)
|
||||
assert hasattr(minute_schedule, "pk") is True
|
||||
# Cron schedule
|
||||
cron_schedule = create_schedule('django_q.tests.tasks.word_multiply',
|
||||
2,
|
||||
word='django',
|
||||
schedule_type=Schedule.CRON,
|
||||
cron="0 22 * * 1-5")
|
||||
assert hasattr(cron_schedule, 'pk') is True
|
||||
cron_schedule = create_schedule(
|
||||
"django_q.tests.tasks.word_multiply",
|
||||
2,
|
||||
word="django",
|
||||
schedule_type=Schedule.CRON,
|
||||
cron="0 22 * * 1-5",
|
||||
)
|
||||
assert hasattr(cron_schedule, "pk") is True
|
||||
assert cron_schedule.full_clean() is None
|
||||
assert cron_schedule.__str__() == 'django_q.tests.tasks.word_multiply'
|
||||
assert cron_schedule.__str__() == "django_q.tests.tasks.word_multiply"
|
||||
with pytest.raises(ValidationError):
|
||||
create_schedule('django_q.tests.tasks.word_multiply',
|
||||
2,
|
||||
word='django',
|
||||
schedule_type=Schedule.CRON,
|
||||
cron="0 22 * * 1-12")
|
||||
create_schedule(
|
||||
"django_q.tests.tasks.word_multiply",
|
||||
2,
|
||||
word="django",
|
||||
schedule_type=Schedule.CRON,
|
||||
cron="0 22 * * 1-12",
|
||||
)
|
||||
# All other types
|
||||
for t in Schedule.TYPE:
|
||||
if t[0] == Schedule.CRON:
|
||||
continue
|
||||
schedule = create_schedule('django_q.tests.tasks.word_multiply',
|
||||
2,
|
||||
word='django',
|
||||
schedule_type=t[0],
|
||||
repeats=1,
|
||||
hook='django_q.tests.tasks.result'
|
||||
)
|
||||
schedule = create_schedule(
|
||||
"django_q.tests.tasks.word_multiply",
|
||||
2,
|
||||
word="django",
|
||||
schedule_type=t[0],
|
||||
repeats=1,
|
||||
hook="django_q.tests.tasks.result",
|
||||
)
|
||||
assert schedule is not None
|
||||
assert schedule.last_run() is None
|
||||
scheduler(broker=broker)
|
||||
# via model
|
||||
Schedule.objects.create(func='django_q.tests.tasks.word_multiply',
|
||||
args='2',
|
||||
kwargs='word="django"',
|
||||
schedule_type=Schedule.DAILY
|
||||
)
|
||||
Schedule.objects.create(
|
||||
func="django_q.tests.tasks.word_multiply",
|
||||
args="2",
|
||||
kwargs='word="django"',
|
||||
schedule_type=Schedule.DAILY,
|
||||
)
|
||||
# scheduler
|
||||
scheduler(broker=broker)
|
||||
# ONCE schedule should be deleted
|
||||
assert Schedule.objects.filter(pk=once_schedule.pk).exists() is False
|
||||
# Catch up On
|
||||
monkeypatch.setattr(Conf, 'CATCH_UP', True)
|
||||
monkeypatch.setattr(Conf, "CATCH_UP", True)
|
||||
now = timezone.now()
|
||||
schedule = create_schedule('django_q.tests.tasks.word_multiply',
|
||||
2,
|
||||
word='catch_up',
|
||||
schedule_type=Schedule.HOURLY,
|
||||
next_run=timezone.now() - timedelta(hours=12),
|
||||
repeats=-1
|
||||
)
|
||||
schedule = create_schedule(
|
||||
"django_q.tests.tasks.word_multiply",
|
||||
2,
|
||||
word="catch_up",
|
||||
schedule_type=Schedule.HOURLY,
|
||||
next_run=timezone.now() - timedelta(hours=12),
|
||||
repeats=-1,
|
||||
)
|
||||
scheduler(broker=broker)
|
||||
schedule = Schedule.objects.get(pk=schedule.pk)
|
||||
assert schedule.next_run < now
|
||||
# Catch up off
|
||||
monkeypatch.setattr(Conf, 'CATCH_UP', False)
|
||||
monkeypatch.setattr(Conf, "CATCH_UP", False)
|
||||
scheduler(broker=broker)
|
||||
schedule = Schedule.objects.get(pk=schedule.pk)
|
||||
assert schedule.next_run > now
|
||||
# Done
|
||||
broker.delete_queue()
|
||||
|
||||
monkeypatch.setattr(Conf, 'PREFIX', 'some_cluster_name')
|
||||
monkeypatch.setattr(Conf, "PREFIX", "some_cluster_name")
|
||||
# create a schedule on another cluster
|
||||
schedule = create_schedule('math.copysign',
|
||||
1, -1,
|
||||
name='test schedule on a another cluster',
|
||||
hook='django_q.tests.tasks.result',
|
||||
schedule_type=Schedule.HOURLY,
|
||||
cluster="some_other_cluster_name",
|
||||
repeats=1)
|
||||
schedule = create_schedule(
|
||||
"math.copysign",
|
||||
1,
|
||||
-1,
|
||||
name="test schedule on a another cluster",
|
||||
hook="django_q.tests.tasks.result",
|
||||
schedule_type=Schedule.HOURLY,
|
||||
cluster="some_other_cluster_name",
|
||||
repeats=1,
|
||||
)
|
||||
# run scheduler
|
||||
scheduler(broker=broker)
|
||||
# set up the workflow
|
||||
@@ -226,15 +253,18 @@ def test_scheduler(broker, monkeypatch):
|
||||
# queue must be empty
|
||||
assert task_queue.qsize() == 0
|
||||
|
||||
monkeypatch.setattr(Conf, 'PREFIX', 'default')
|
||||
monkeypatch.setattr(Conf, "PREFIX", "default")
|
||||
# create a schedule on the same cluster
|
||||
schedule = create_schedule('math.copysign',
|
||||
1, -1,
|
||||
name='test schedule with no cluster',
|
||||
hook='django_q.tests.tasks.result',
|
||||
schedule_type=Schedule.HOURLY,
|
||||
cluster="default",
|
||||
repeats=1)
|
||||
schedule = create_schedule(
|
||||
"math.copysign",
|
||||
1,
|
||||
-1,
|
||||
name="test schedule with no cluster",
|
||||
hook="django_q.tests.tasks.result",
|
||||
schedule_type=Schedule.HOURLY,
|
||||
cluster="default",
|
||||
repeats=1,
|
||||
)
|
||||
# run scheduler
|
||||
scheduler(broker=broker)
|
||||
# set up the workflow
|
||||
@@ -249,11 +279,12 @@ def test_scheduler(broker, monkeypatch):
|
||||
|
||||
|
||||
@override_settings(
|
||||
DATABASE_ROUTERS=REPLICA_DATABASE_ROUTERS,
|
||||
DATABASES=REPLICA_DATABASES
|
||||
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):
|
||||
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
|
||||
@@ -267,12 +298,12 @@ def test_scheduler_atomic_transaction_must_specify_a_database_when_no_replicas_a
|
||||
|
||||
|
||||
@override_settings(
|
||||
DATABASE_ROUTERS=REPLICA_DATABASE_ROUTERS,
|
||||
DATABASES=REPLICA_DATABASES
|
||||
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(
|
||||
orm_replica_broker: Broker):
|
||||
orm_replica_broker: Broker,
|
||||
):
|
||||
"""
|
||||
GIVEN a environment with a read/write configured replica database
|
||||
WHEN the scheduler is called
|
||||
@@ -285,12 +316,12 @@ def test_scheduler_atomic_transaction_must_specify_no_database_when_read_write_r
|
||||
|
||||
|
||||
@override_settings(
|
||||
DATABASE_ROUTERS=MULTIPLE_APPS_DATABASE_ROUTERS,
|
||||
DATABASES=MULTIPLE_APPS_DATABASES
|
||||
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(
|
||||
orm_no_replica_broker: Broker):
|
||||
orm_no_replica_broker: Broker,
|
||||
):
|
||||
"""
|
||||
GIVEN a environment without a read replica database
|
||||
WHEN the scheduler is called
|
||||
@@ -300,5 +331,14 @@ def test_scheduler_atomic_transaction_must_specify_the_database_based_on_router_
|
||||
with mock.patch("django_q.cluster.db") as mocked_db:
|
||||
scheduler(broker=broker)
|
||||
# The router should correctly set the database to use!
|
||||
assert broker.connection.db == 'default'
|
||||
assert broker.connection.db == "default"
|
||||
mocked_db.transaction.atomic.assert_called_with(using=broker.connection.db)
|
||||
|
||||
|
||||
def test_localtime():
|
||||
assert not is_naive(localtime())
|
||||
|
||||
|
||||
@override_settings(USE_TZ=False)
|
||||
def test_naive_localtime():
|
||||
assert is_naive(localtime())
|
||||
|
||||
@@ -25,14 +25,14 @@ class TestingMultipleAppsDatabaseRouter:
|
||||
|
||||
@staticmethod
|
||||
def is_admin(model):
|
||||
return model._meta.app_label in ['admin']
|
||||
return model._meta.app_label in ["admin"]
|
||||
|
||||
def db_for_read(self, model, **hints):
|
||||
if self.is_admin(model):
|
||||
return 'admin'
|
||||
return 'default'
|
||||
return "admin"
|
||||
return "default"
|
||||
|
||||
def db_for_write(self, model, **hints):
|
||||
if self.is_admin(model):
|
||||
return 'admin'
|
||||
return 'default'
|
||||
return "admin"
|
||||
return "default"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from django.urls import re_path
|
||||
from django.contrib import admin
|
||||
from django.urls import re_path
|
||||
|
||||
urlpatterns = [
|
||||
re_path(r'^admin/', admin.site.urls),
|
||||
re_path(r"^admin/", admin.site.urls),
|
||||
]
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys
|
||||
import os
|
||||
import sys
|
||||
|
||||
import alabaster
|
||||
|
||||
@@ -73,7 +73,7 @@ author = 'Ilan Steemers'
|
||||
# The short X.Y version.
|
||||
version = '1.3'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '1.3.6'
|
||||
release = '1.3.7'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
264
poetry.lock
generated
264
poetry.lock
generated
@@ -14,6 +14,14 @@ category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "appdirs"
|
||||
version = "1.4.4"
|
||||
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "arrow"
|
||||
version = "0.15.8"
|
||||
@@ -72,6 +80,30 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
[package.dependencies]
|
||||
pytz = ">=2015.7"
|
||||
|
||||
[[package]]
|
||||
name = "black"
|
||||
version = "21.5b1"
|
||||
description = "The uncompromising code formatter."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6.2"
|
||||
|
||||
[package.dependencies]
|
||||
appdirs = "*"
|
||||
click = ">=7.1.2"
|
||||
dataclasses = {version = ">=0.6", markers = "python_version < \"3.7\""}
|
||||
mypy-extensions = ">=0.4.3"
|
||||
pathspec = ">=0.8.1,<1"
|
||||
regex = ">=2020.1.8"
|
||||
toml = ">=0.10.1"
|
||||
typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\""}
|
||||
typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""}
|
||||
|
||||
[package.extras]
|
||||
colorama = ["colorama (>=0.4.3)"]
|
||||
d = ["aiohttp (>=3.6.0)", "aiohttp-cors"]
|
||||
python2 = ["typed-ast (>=1.4.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "blessed"
|
||||
version = "1.18.0"
|
||||
@@ -130,6 +162,18 @@ category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.0.1"
|
||||
description = "Composable command line interface toolkit"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
||||
importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.4"
|
||||
@@ -164,6 +208,14 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
natsort = "*"
|
||||
python-dateutil = "*"
|
||||
|
||||
[[package]]
|
||||
name = "dataclasses"
|
||||
version = "0.8"
|
||||
description = "A backport of the dataclasses module for Python 3.6"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6, <3.7"
|
||||
|
||||
[[package]]
|
||||
name = "django"
|
||||
version = "3.2.3"
|
||||
@@ -229,6 +281,14 @@ python-versions = ">=3.5"
|
||||
Django = ">=2.2"
|
||||
redis = ">=3.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"
|
||||
@@ -300,6 +360,23 @@ python-versions = "*"
|
||||
[package.dependencies]
|
||||
iron_core = "*"
|
||||
|
||||
[[package]]
|
||||
name = "isort"
|
||||
version = "5.8.0"
|
||||
description = "A Python utility / library to sort Python imports."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6,<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]
|
||||
pipfile_deprecated_finder = ["pipreqs", "requirementslib"]
|
||||
requirements_deprecated_finder = ["pipreqs", "pip-api"]
|
||||
colors = ["colorama (>=0.4.3,<0.5.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "jinja2"
|
||||
version = "3.0.1"
|
||||
@@ -349,6 +426,14 @@ category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
|
||||
[[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 = "natsort"
|
||||
version = "7.1.1"
|
||||
@@ -372,6 +457,34 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
[package.dependencies]
|
||||
pyparsing = ">=2.0.2"
|
||||
|
||||
[[package]]
|
||||
name = "pathspec"
|
||||
version = "0.8.1"
|
||||
description = "Utility library for gitignore style pattern matching of file paths."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
|
||||
[[package]]
|
||||
name = "pip-api"
|
||||
version = "0.0.20"
|
||||
description = "An unofficial, importable pip API"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
|
||||
[[package]]
|
||||
name = "pipreqs"
|
||||
version = "0.4.10"
|
||||
description = "Pip requirements.txt generator based on imports in project"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[package.dependencies]
|
||||
docopt = "*"
|
||||
yarg = "*"
|
||||
|
||||
[[package]]
|
||||
name = "pluggy"
|
||||
version = "0.13.1"
|
||||
@@ -522,6 +635,14 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
[package.extras]
|
||||
hiredis = ["hiredis (>=0.1.3)"]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "2021.4.4"
|
||||
description = "Alternative regular expression module, to replace re."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "requests"
|
||||
version = "2.25.1"
|
||||
@@ -728,6 +849,14 @@ category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
|
||||
[[package]]
|
||||
name = "typed-ast"
|
||||
version = "1.4.3"
|
||||
description = "a fork of Python 2 and 3 ast modules with type comment support"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "3.10.0.0"
|
||||
@@ -757,6 +886,17 @@ category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[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.4.1"
|
||||
@@ -773,13 +913,13 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pyt
|
||||
build-backend = []
|
||||
requires = []
|
||||
rollbar = ["django-q-rollbar"]
|
||||
sentry = []
|
||||
sentry = ["django-q-sentry"]
|
||||
testing = ["django-redis", "croniter", "hiredis", "psutil", "iron-mq", "boto3", "pymongo"]
|
||||
|
||||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = ">=3.6, <4"
|
||||
content-hash = "a01254ca3ea005712906e0952b82d8edb1eabfd0d75129ffa97858bc0bbaf47a"
|
||||
python-versions = ">=3.6.2, <4"
|
||||
content-hash = "4f8af88fa16a4689155dff796affc021e1983e80f9b8ff8a902139c4ad3610e5"
|
||||
|
||||
[metadata.files]
|
||||
alabaster = [
|
||||
@@ -790,6 +930,10 @@ ansicon = [
|
||||
{file = "ansicon-1.89.0-py2.py3-none-any.whl", hash = "sha256:f1def52d17f65c2c9682cf8370c03f541f410c1752d6a14029f97318e4b9dfec"},
|
||||
{file = "ansicon-1.89.0.tar.gz", hash = "sha256:e4d039def5768a47e4afec8e89e83ec3ae5a26bf00ad851f914d1240b444d2b1"},
|
||||
]
|
||||
appdirs = [
|
||||
{file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
|
||||
{file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
|
||||
]
|
||||
arrow = [
|
||||
{file = "arrow-0.15.8-py2.py3-none-any.whl", hash = "sha256:271b8e05174d48e50324ed0dc5d74796c839c7e579a4f21cf1a7394665f9e94f"},
|
||||
{file = "arrow-0.15.8.tar.gz", hash = "sha256:edc31dc051db12c95da9bac0271cd1027b8e36912daf6d4580af53b23e62721a"},
|
||||
@@ -810,6 +954,10 @@ babel = [
|
||||
{file = "Babel-2.9.1-py2.py3-none-any.whl", hash = "sha256:ab49e12b91d937cd11f0b67cb259a57ab4ad2b59ac7a3b41d6c06c0ac5b0def9"},
|
||||
{file = "Babel-2.9.1.tar.gz", hash = "sha256:bc0c176f9f6a994582230df350aa6e05ba2ebe4b3ac317eab29d9be5d2768da0"},
|
||||
]
|
||||
black = [
|
||||
{file = "black-21.5b1-py3-none-any.whl", hash = "sha256:8a60071a0043876a4ae96e6c69bd3a127dad2c1ca7c8083573eb82f92705d008"},
|
||||
{file = "black-21.5b1.tar.gz", hash = "sha256:23695358dbcb3deafe7f0a3ad89feee5999a46be5fec21f4f1d108be0bcdb3b1"},
|
||||
]
|
||||
blessed = [
|
||||
{file = "blessed-1.18.0-py2.py3-none-any.whl", hash = "sha256:5b5e2f0563d5a668c282f3f5946f7b1abb70c85829461900e607e74d7725106e"},
|
||||
{file = "blessed-1.18.0.tar.gz", hash = "sha256:1312879f971330a1b7f2c6341f2ae7e2cbac244bfc9d0ecfbbecd4b0293bc755"},
|
||||
@@ -830,6 +978,10 @@ chardet = [
|
||||
{file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"},
|
||||
{file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"},
|
||||
]
|
||||
click = [
|
||||
{file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"},
|
||||
{file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"},
|
||||
]
|
||||
colorama = [
|
||||
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
|
||||
{file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
|
||||
@@ -892,6 +1044,10 @@ croniter = [
|
||||
{file = "croniter-0.3.37-py2.py3-none-any.whl", hash = "sha256:8f573a889ca9379e08c336193435c57c02698c2dd22659cdbe04fee57426d79b"},
|
||||
{file = "croniter-0.3.37.tar.gz", hash = "sha256:12ced475dfc107bf7c6c1440af031f34be14cd97bbbfaf0f62221a9c11e86404"},
|
||||
]
|
||||
dataclasses = [
|
||||
{file = "dataclasses-0.8-py3-none-any.whl", hash = "sha256:0201d89fa866f68c8ebd9d08ee6ff50c0b255f8ec63a71c16fda7af82bb887bf"},
|
||||
{file = "dataclasses-0.8.tar.gz", hash = "sha256:8479067f342acf957dc82ec415d355ab5edb7e7646b90dc6e2fd1d96ad084c97"},
|
||||
]
|
||||
django = [
|
||||
{file = "Django-3.2.3-py3-none-any.whl", hash = "sha256:7e0a1393d18c16b503663752a8b6790880c5084412618990ce8a81cc908b4962"},
|
||||
{file = "Django-3.2.3.tar.gz", hash = "sha256:13ac78dbfd189532cad8f383a27e58e18b3d33f80009ceb476d7fcbfc5dcebd8"},
|
||||
@@ -911,6 +1067,9 @@ django-redis = [
|
||||
{file = "django-redis-4.12.1.tar.gz", hash = "sha256:306589c7021e6468b2656edc89f62b8ba67e8d5a1c8877e2688042263daa7a63"},
|
||||
{file = "django_redis-4.12.1-py3-none-any.whl", hash = "sha256:1133b26b75baa3664164c3f44b9d5d133d1b8de45d94d79f38d1adc5b1d502e5"},
|
||||
]
|
||||
docopt = [
|
||||
{file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"},
|
||||
]
|
||||
docutils = [
|
||||
{file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"},
|
||||
{file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"},
|
||||
@@ -981,6 +1140,10 @@ iron-core = [
|
||||
iron-mq = [
|
||||
{file = "iron-mq-0.9.tar.gz", hash = "sha256:c90441d872d9c08968343810a2ad1cca1664d80fd2ad3a3a2dbec57b7b38ecfa"},
|
||||
]
|
||||
isort = [
|
||||
{file = "isort-5.8.0-py3-none-any.whl", hash = "sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d"},
|
||||
{file = "isort-5.8.0.tar.gz", hash = "sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6"},
|
||||
]
|
||||
jinja2 = [
|
||||
{file = "Jinja2-3.0.1-py3-none-any.whl", hash = "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4"},
|
||||
{file = "Jinja2-3.0.1.tar.gz", hash = "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4"},
|
||||
@@ -1033,6 +1196,10 @@ more-itertools = [
|
||||
{file = "more-itertools-8.8.0.tar.gz", hash = "sha256:83f0308e05477c68f56ea3a888172c78ed5d5b3c282addb67508e7ba6c8f813a"},
|
||||
{file = "more_itertools-8.8.0-py3-none-any.whl", hash = "sha256:2cf89ec599962f2ddc4d568a05defc40e0a587fbc10d5989713638864c36be4d"},
|
||||
]
|
||||
mypy-extensions = [
|
||||
{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"},
|
||||
]
|
||||
natsort = [
|
||||
{file = "natsort-7.1.1-py3-none-any.whl", hash = "sha256:d0f4fc06ca163fa4a5ef638d9bf111c67f65eedcc7920f98dec08e489045b67e"},
|
||||
{file = "natsort-7.1.1.tar.gz", hash = "sha256:00c603a42365830c4722a2eb7663a25919551217ec09a243d3399fa8dd4ac403"},
|
||||
@@ -1041,6 +1208,18 @@ packaging = [
|
||||
{file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"},
|
||||
{file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"},
|
||||
]
|
||||
pathspec = [
|
||||
{file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"},
|
||||
{file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"},
|
||||
]
|
||||
pip-api = [
|
||||
{file = "pip-api-0.0.20.tar.gz", hash = "sha256:1da0b47824c0b6c2830f2767e7304820d148475e4d08979add271da32917598e"},
|
||||
{file = "pip_api-0.0.20-py3-none-any.whl", hash = "sha256:74227da7102523339d7b6e2f6e105821b04415bdb5f096e170b0ababf88d074f"},
|
||||
]
|
||||
pipreqs = [
|
||||
{file = "pipreqs-0.4.10-py2.py3-none-any.whl", hash = "sha256:cafe42ab70628d408c147fb8944bc303355ea8f91fddca4a98d273e572e39905"},
|
||||
{file = "pipreqs-0.4.10.tar.gz", hash = "sha256:9e351d644b28b98d7386b046a73806cbb3bb66b23a30e74feeb95ed9571db939"},
|
||||
]
|
||||
pluggy = [
|
||||
{file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
|
||||
{file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
|
||||
@@ -1177,6 +1356,49 @@ redis = [
|
||||
{file = "redis-3.5.3-py2.py3-none-any.whl", hash = "sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24"},
|
||||
{file = "redis-3.5.3.tar.gz", hash = "sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2"},
|
||||
]
|
||||
regex = [
|
||||
{file = "regex-2021.4.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:619d71c59a78b84d7f18891fe914446d07edd48dc8328c8e149cbe0929b4e000"},
|
||||
{file = "regex-2021.4.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:47bf5bf60cf04d72bf6055ae5927a0bd9016096bf3d742fa50d9bf9f45aa0711"},
|
||||
{file = "regex-2021.4.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:281d2fd05555079448537fe108d79eb031b403dac622621c78944c235f3fcf11"},
|
||||
{file = "regex-2021.4.4-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bd28bc2e3a772acbb07787c6308e00d9626ff89e3bfcdebe87fa5afbfdedf968"},
|
||||
{file = "regex-2021.4.4-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:7c2a1af393fcc09e898beba5dd59196edaa3116191cc7257f9224beaed3e1aa0"},
|
||||
{file = "regex-2021.4.4-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c38c71df845e2aabb7fb0b920d11a1b5ac8526005e533a8920aea97efb8ec6a4"},
|
||||
{file = "regex-2021.4.4-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:96fcd1888ab4d03adfc9303a7b3c0bd78c5412b2bfbe76db5b56d9eae004907a"},
|
||||
{file = "regex-2021.4.4-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:ade17eb5d643b7fead300a1641e9f45401c98eee23763e9ed66a43f92f20b4a7"},
|
||||
{file = "regex-2021.4.4-cp36-cp36m-win32.whl", hash = "sha256:e8e5b509d5c2ff12f8418006d5a90e9436766133b564db0abaec92fd27fcee29"},
|
||||
{file = "regex-2021.4.4-cp36-cp36m-win_amd64.whl", hash = "sha256:11d773d75fa650cd36f68d7ca936e3c7afaae41b863b8c387a22aaa78d3c5c79"},
|
||||
{file = "regex-2021.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d3029c340cfbb3ac0a71798100ccc13b97dddf373a4ae56b6a72cf70dfd53bc8"},
|
||||
{file = "regex-2021.4.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:18c071c3eb09c30a264879f0d310d37fe5d3a3111662438889ae2eb6fc570c31"},
|
||||
{file = "regex-2021.4.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:4c557a7b470908b1712fe27fb1ef20772b78079808c87d20a90d051660b1d69a"},
|
||||
{file = "regex-2021.4.4-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:01afaf2ec48e196ba91b37451aa353cb7eda77efe518e481707e0515025f0cd5"},
|
||||
{file = "regex-2021.4.4-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:3a9cd17e6e5c7eb328517969e0cb0c3d31fd329298dd0c04af99ebf42e904f82"},
|
||||
{file = "regex-2021.4.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:90f11ff637fe8798933fb29f5ae1148c978cccb0452005bf4c69e13db951e765"},
|
||||
{file = "regex-2021.4.4-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:919859aa909429fb5aa9cf8807f6045592c85ef56fdd30a9a3747e513db2536e"},
|
||||
{file = "regex-2021.4.4-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:339456e7d8c06dd36a22e451d58ef72cef293112b559010db3d054d5560ef439"},
|
||||
{file = "regex-2021.4.4-cp37-cp37m-win32.whl", hash = "sha256:67bdb9702427ceddc6ef3dc382455e90f785af4c13d495f9626861763ee13f9d"},
|
||||
{file = "regex-2021.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:32e65442138b7b76dd8173ffa2cf67356b7bc1768851dded39a7a13bf9223da3"},
|
||||
{file = "regex-2021.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1e1c20e29358165242928c2de1482fb2cf4ea54a6a6dea2bd7a0e0d8ee321500"},
|
||||
{file = "regex-2021.4.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:314d66636c494ed9c148a42731b3834496cc9a2c4251b1661e40936814542b14"},
|
||||
{file = "regex-2021.4.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6d1b01031dedf2503631d0903cb563743f397ccaf6607a5e3b19a3d76fc10480"},
|
||||
{file = "regex-2021.4.4-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:741a9647fcf2e45f3a1cf0e24f5e17febf3efe8d4ba1281dcc3aa0459ef424dc"},
|
||||
{file = "regex-2021.4.4-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:4c46e22a0933dd783467cf32b3516299fb98cfebd895817d685130cc50cd1093"},
|
||||
{file = "regex-2021.4.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e512d8ef5ad7b898cdb2d8ee1cb09a8339e4f8be706d27eaa180c2f177248a10"},
|
||||
{file = "regex-2021.4.4-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:980d7be47c84979d9136328d882f67ec5e50008681d94ecc8afa8a65ed1f4a6f"},
|
||||
{file = "regex-2021.4.4-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:ce15b6d103daff8e9fee13cf7f0add05245a05d866e73926c358e871221eae87"},
|
||||
{file = "regex-2021.4.4-cp38-cp38-win32.whl", hash = "sha256:a91aa8619b23b79bcbeb37abe286f2f408d2f2d6f29a17237afda55bb54e7aac"},
|
||||
{file = "regex-2021.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:c0502c0fadef0d23b128605d69b58edb2c681c25d44574fc673b0e52dce71ee2"},
|
||||
{file = "regex-2021.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:598585c9f0af8374c28edd609eb291b5726d7cbce16be6a8b95aa074d252ee17"},
|
||||
{file = "regex-2021.4.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:ee54ff27bf0afaf4c3b3a62bcd016c12c3fdb4ec4f413391a90bd38bc3624605"},
|
||||
{file = "regex-2021.4.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7d9884d86dd4dd489e981d94a65cd30d6f07203d90e98f6f657f05170f6324c9"},
|
||||
{file = "regex-2021.4.4-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:bf5824bfac591ddb2c1f0a5f4ab72da28994548c708d2191e3b87dd207eb3ad7"},
|
||||
{file = "regex-2021.4.4-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:563085e55b0d4fb8f746f6a335893bda5c2cef43b2f0258fe1020ab1dd874df8"},
|
||||
{file = "regex-2021.4.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9c3db21af35e3b3c05764461b262d6f05bbca08a71a7849fd79d47ba7bc33ed"},
|
||||
{file = "regex-2021.4.4-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3916d08be28a1149fb97f7728fca1f7c15d309a9f9682d89d79db75d5e52091c"},
|
||||
{file = "regex-2021.4.4-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:fd45ff9293d9274c5008a2054ecef86a9bfe819a67c7be1afb65e69b405b3042"},
|
||||
{file = "regex-2021.4.4-cp39-cp39-win32.whl", hash = "sha256:fa4537fb4a98fe8fde99626e4681cc644bdcf2a795038533f9f711513a862ae6"},
|
||||
{file = "regex-2021.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:97f29f57d5b84e73fbaf99ab3e26134e6687348e95ef6b48cfd2c06807005a07"},
|
||||
{file = "regex-2021.4.4.tar.gz", hash = "sha256:52ba3d3f9b942c49d7e4bc105bb28551c44065f139a65062ab7912bef10c9afb"},
|
||||
]
|
||||
requests = [
|
||||
{file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"},
|
||||
{file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"},
|
||||
@@ -1236,6 +1458,38 @@ toml = [
|
||||
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
|
||||
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
|
||||
]
|
||||
typed-ast = [
|
||||
{file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6"},
|
||||
{file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075"},
|
||||
{file = "typed_ast-1.4.3-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528"},
|
||||
{file = "typed_ast-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428"},
|
||||
{file = "typed_ast-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3"},
|
||||
{file = "typed_ast-1.4.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f"},
|
||||
{file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341"},
|
||||
{file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace"},
|
||||
{file = "typed_ast-1.4.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f"},
|
||||
{file = "typed_ast-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363"},
|
||||
{file = "typed_ast-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7"},
|
||||
{file = "typed_ast-1.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266"},
|
||||
{file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e"},
|
||||
{file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04"},
|
||||
{file = "typed_ast-1.4.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899"},
|
||||
{file = "typed_ast-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c"},
|
||||
{file = "typed_ast-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805"},
|
||||
{file = "typed_ast-1.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a"},
|
||||
{file = "typed_ast-1.4.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff"},
|
||||
{file = "typed_ast-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41"},
|
||||
{file = "typed_ast-1.4.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39"},
|
||||
{file = "typed_ast-1.4.3-cp38-cp38-win32.whl", hash = "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927"},
|
||||
{file = "typed_ast-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40"},
|
||||
{file = "typed_ast-1.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3"},
|
||||
{file = "typed_ast-1.4.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4"},
|
||||
{file = "typed_ast-1.4.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0"},
|
||||
{file = "typed_ast-1.4.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3"},
|
||||
{file = "typed_ast-1.4.3-cp39-cp39-win32.whl", hash = "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808"},
|
||||
{file = "typed_ast-1.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c"},
|
||||
{file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"},
|
||||
]
|
||||
typing-extensions = [
|
||||
{file = "typing_extensions-3.10.0.0-py2-none-any.whl", hash = "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497"},
|
||||
{file = "typing_extensions-3.10.0.0-py3-none-any.whl", hash = "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"},
|
||||
@@ -1249,6 +1503,10 @@ wcwidth = [
|
||||
{file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"},
|
||||
{file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"},
|
||||
]
|
||||
yarg = [
|
||||
{file = "yarg-0.1.9-py2.py3-none-any.whl", hash = "sha256:4f9cebdc00fac946c9bf2783d634e538a71c7d280a4d806d45fd4dc0ef441492"},
|
||||
{file = "yarg-0.1.9.tar.gz", hash = "sha256:55695bf4d1e3e7f756496c36a69ba32c40d18f821e38f61d028f6049e5e15911"},
|
||||
]
|
||||
zipp = [
|
||||
{file = "zipp-3.4.1-py3-none-any.whl", hash = "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"},
|
||||
{file = "zipp-3.4.1.tar.gz", hash = "sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76"},
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
[tool.poetry]
|
||||
name = "django-q"
|
||||
version = "1.3.6"
|
||||
version = "1.3.7"
|
||||
description = "A multiprocessing distributed task queue for Django"
|
||||
authors = ["Ilan Steemers <koed00@gmail.com>"]
|
||||
maintainers = ["Ilan Steemers <koed00@gmail.com>"]
|
||||
license = "MIT"
|
||||
readme = 'README.rst'
|
||||
|
||||
@@ -32,20 +33,20 @@ classifiers = [
|
||||
]
|
||||
include = ['CHANGELOG.md']
|
||||
|
||||
[tool.poetry.plugins] # Optional super table
|
||||
|
||||
[tool.poetry.plugins."djangoq.errorreporters"]
|
||||
"rollbar" = "django_q_rollbar:Rollbar"
|
||||
"sentry" = "django_q_sentry:Sentry"
|
||||
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.6, <4"
|
||||
python = ">=3.6.2, <4"
|
||||
django = ">=2.2"
|
||||
blessed = "^1.17.6"
|
||||
arrow = "^0.15.6"
|
||||
django-picklefield = "^3.0.1"
|
||||
|
||||
django-q-rollbar = { version = "^0.1", optional = true }
|
||||
django-q-sentry = { version = "^0.1", optional = true }
|
||||
hiredis = { version = "^1.0.1", optional = true }
|
||||
redis = { version = "^3.5.3", optional = true }
|
||||
psutil = { version = "^5.7.0", optional = true }
|
||||
@@ -54,17 +55,24 @@ iron-mq = { version = "^0.9", optional = true }
|
||||
boto3 = { version = "^1.14.12", optional = true }
|
||||
pymongo = { version = "^3.10.1", optional = true }
|
||||
croniter = { version = "^0.3.34", optional = true }
|
||||
django-q-rollbar = {version = ">=0.1", optional = true}
|
||||
django-q-sentry = {version = ">=0.1", optional = true}
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
pytest = "^5.4.2"
|
||||
pytest-django = "^3.9.0"
|
||||
Sphinx = "^4.0.2"
|
||||
pytest-cov = "^2.12.0"
|
||||
black = { version = "^21.5b1", allow-prereleases = true }
|
||||
isort = {extras = ["requirements_deprecated_finder"], version = "^5.8.0"}
|
||||
|
||||
[tool.poetry.extras]
|
||||
rollbar = ["django-q-rollbar"]
|
||||
sentry = ["django-q-sentry "]
|
||||
requires = ["poetry>=0.12"]
|
||||
build-backend = ["poetry.masonry.api"]
|
||||
requires = ["poetry_core>=1.0.0"]
|
||||
build-backend = ["poetry.core.masonry.api"]
|
||||
testing = ["django-redis", "croniter", "hiredis", "psutil", "iron-mq", "boto3", "pymongo"]
|
||||
rollbar = ["django-q-rollbar"]
|
||||
sentry = ["django-q-sentry"]
|
||||
|
||||
[tool.isort]
|
||||
profile = "black"
|
||||
multi_line_output = 3
|
||||
@@ -1,11 +0,0 @@
|
||||
arrow
|
||||
blessed
|
||||
django-picklefield
|
||||
hiredis
|
||||
redis
|
||||
psutil
|
||||
django-redis
|
||||
iron-mq
|
||||
boto3
|
||||
pymongo
|
||||
croniter
|
||||
300
requirements.txt
300
requirements.txt
@@ -1,76 +1,224 @@
|
||||
#
|
||||
# This file is autogenerated by pip-compile
|
||||
# To update, run:
|
||||
#
|
||||
# pip-compile requirements.in
|
||||
#
|
||||
arrow==1.1.0
|
||||
# via -r requirements.in
|
||||
asgiref==3.3.4
|
||||
# via django
|
||||
blessed==1.18.0
|
||||
# via -r requirements.in
|
||||
boto3==1.17.78
|
||||
# via -r requirements.in
|
||||
botocore==1.20.78
|
||||
# via
|
||||
# boto3
|
||||
# s3transfer
|
||||
certifi==2020.12.5
|
||||
# via requests
|
||||
chardet==4.0.0
|
||||
# via requests
|
||||
croniter==1.0.13
|
||||
# via -r requirements.in
|
||||
django-picklefield==3.0.1
|
||||
# via -r requirements.in
|
||||
django-redis==4.12.1
|
||||
# via -r requirements.in
|
||||
django==3.2.3
|
||||
# via
|
||||
# django-picklefield
|
||||
# django-redis
|
||||
hiredis==2.0.0
|
||||
# via -r requirements.in
|
||||
idna==2.10
|
||||
# via requests
|
||||
iron-core==1.2.0
|
||||
# via iron-mq
|
||||
iron-mq==0.9
|
||||
# via -r requirements.in
|
||||
jmespath==0.10.0
|
||||
# via
|
||||
# boto3
|
||||
# botocore
|
||||
psutil==5.8.0
|
||||
# via -r requirements.in
|
||||
pymongo==3.11.4
|
||||
# via -r requirements.in
|
||||
python-dateutil==2.8.1
|
||||
# via
|
||||
# arrow
|
||||
# botocore
|
||||
# croniter
|
||||
# iron-core
|
||||
pytz==2021.1
|
||||
# via django
|
||||
redis==3.5.3
|
||||
# via
|
||||
# -r requirements.in
|
||||
# django-redis
|
||||
requests==2.25.1
|
||||
# via iron-core
|
||||
s3transfer==0.4.2
|
||||
# via boto3
|
||||
six==1.16.0
|
||||
# via
|
||||
# blessed
|
||||
# python-dateutil
|
||||
sqlparse==0.4.1
|
||||
# via django
|
||||
urllib3==1.26.4
|
||||
# via
|
||||
# botocore
|
||||
# requests
|
||||
wcwidth==0.2.5
|
||||
# via blessed
|
||||
ansicon==1.89.0; platform_system == "Windows" \
|
||||
--hash=sha256:f1def52d17f65c2c9682cf8370c03f541f410c1752d6a14029f97318e4b9dfec \
|
||||
--hash=sha256:e4d039def5768a47e4afec8e89e83ec3ae5a26bf00ad851f914d1240b444d2b1
|
||||
arrow==0.15.8; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.5.0") \
|
||||
--hash=sha256:271b8e05174d48e50324ed0dc5d74796c839c7e579a4f21cf1a7394665f9e94f \
|
||||
--hash=sha256:edc31dc051db12c95da9bac0271cd1027b8e36912daf6d4580af53b23e62721a
|
||||
asgiref==3.3.4; python_version >= "3.6" \
|
||||
--hash=sha256:92906c611ce6c967347bbfea733f13d6313901d54dcca88195eaeb52b2a8e8ee \
|
||||
--hash=sha256:d1216dfbdfb63826470995d31caed36225dcaf34f182e0fa257a4dd9e86f1b78
|
||||
blessed==1.18.0 \
|
||||
--hash=sha256:5b5e2f0563d5a668c282f3f5946f7b1abb70c85829461900e607e74d7725106e \
|
||||
--hash=sha256:1312879f971330a1b7f2c6341f2ae7e2cbac244bfc9d0ecfbbecd4b0293bc755
|
||||
boto3==1.17.78; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.6.0") \
|
||||
--hash=sha256:1a87855123df1f18081a5fb8c1abde28d0096a03f6f3ebb06bcfb77cdffdae5e \
|
||||
--hash=sha256:2a5caee63d45fbdcc85e710c7f4146112f5d10b22fd0176643d2f2914cce54df
|
||||
botocore==1.20.78; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" \
|
||||
--hash=sha256:37105b9434d73f9c4d4960ee54c8eb129120f4c6681eb16edf483f03c5e2326d \
|
||||
--hash=sha256:e74775f9e64e975787d76390fc5ac5aba875d726bb9ece3b7bd900205b430389
|
||||
certifi==2020.12.5; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" \
|
||||
--hash=sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830 \
|
||||
--hash=sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c
|
||||
chardet==4.0.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" \
|
||||
--hash=sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5 \
|
||||
--hash=sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa
|
||||
croniter==0.3.37; (python_version >= "2.6" and python_full_version < "3.0.0") or (python_full_version >= "3.4.0") \
|
||||
--hash=sha256:8f573a889ca9379e08c336193435c57c02698c2dd22659cdbe04fee57426d79b \
|
||||
--hash=sha256:12ced475dfc107bf7c6c1440af031f34be14cd97bbbfaf0f62221a9c11e86404
|
||||
django-picklefield==3.0.1; python_version >= "3" \
|
||||
--hash=sha256:15ccba592ca953b9edf9532e64640329cd47b136b7f8f10f2939caa5f9ce4287 \
|
||||
--hash=sha256:3c702a54fde2d322fe5b2f39b8f78d9f655b8f77944ab26f703be6c0ed335a35
|
||||
django-redis==4.12.1; python_version >= "3.5" \
|
||||
--hash=sha256:306589c7021e6468b2656edc89f62b8ba67e8d5a1c8877e2688042263daa7a63 \
|
||||
--hash=sha256:1133b26b75baa3664164c3f44b9d5d133d1b8de45d94d79f38d1adc5b1d502e5
|
||||
django==3.2.3; python_version >= "3.6" \
|
||||
--hash=sha256:7e0a1393d18c16b503663752a8b6790880c5084412618990ce8a81cc908b4962 \
|
||||
--hash=sha256:13ac78dbfd189532cad8f383a27e58e18b3d33f80009ceb476d7fcbfc5dcebd8
|
||||
hiredis==1.1.0; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.4.0") \
|
||||
--hash=sha256:289b31885b4996ce04cadfd5fc03d034dce8e2a8234479f7c9e23b9e245db06b \
|
||||
--hash=sha256:7b0f63f10a166583ab744a58baad04e0f52cfea1ac27bfa1b0c21a48d1003c23 \
|
||||
--hash=sha256:6996883a8a6ff9117cbb3d6f5b0dcbbae6fb9e31e1a3e4e2f95e0214d9a1c655 \
|
||||
--hash=sha256:b33aea449e7f46738811fbc6f0b3177c6777a572207412bbbf6f525ffed001ae \
|
||||
--hash=sha256:8daecd778c1da45b8bd54fd41ffcd471a86beed3d8e57a43acf7a8d63bba4058 \
|
||||
--hash=sha256:e82d6b930e02e80e5109b678c663a9ed210680ded81c1abaf54635d88d1da298 \
|
||||
--hash=sha256:d2c0caffa47606d6d7c8af94ba42547bd2a441f06c74fd90a1ffe328524a6c64 \
|
||||
--hash=sha256:47bcf3c5e6c1e87ceb86cdda2ee983fa0fe56a999e6185099b3c93a223f2fa9b \
|
||||
--hash=sha256:dcb2db95e629962db5a355047fb8aefb012df6c8ae608930d391619dbd96fd86 \
|
||||
--hash=sha256:7332d5c3e35154cd234fd79573736ddcf7a0ade7a986db35b6196b9171493e75 \
|
||||
--hash=sha256:6c96f64a54f030366657a54bb90b3093afc9c16c8e0dfa29fc0d6dbe169103a5 \
|
||||
--hash=sha256:b44f9421c4505c548435244d74037618f452844c5d3c67719d8a55e2613549da \
|
||||
--hash=sha256:abfb15a6a7822f0fae681785cb38860e7a2cb1616a708d53df557b3d76c5bfd4 \
|
||||
--hash=sha256:89ebf69cb19a33d625db72d2ac589d26e936b8f7628531269accf4a3196e7872 \
|
||||
--hash=sha256:5b1451727f02e7acbdf6aae4e06d75f66ee82966ff9114550381c3271a90f56c \
|
||||
--hash=sha256:7885b6f32c4a898e825bb7f56f36a02781ac4a951c63e4169f0afcf9c8c30dfb \
|
||||
--hash=sha256:a04901757cb0fb0f5602ac11dda48f5510f94372144d06c2563ba56c480b467c \
|
||||
--hash=sha256:3bb9b63d319402cead8bbd9dd55dca3b667d2997e9a0d8a1f9b6cc274db4baee \
|
||||
--hash=sha256:e0eeb9c112fec2031927a1745788a181d0eecbacbed941fc5c4f7bc3f7b273bf \
|
||||
--hash=sha256:18402d9e54fb278cb9a8c638df6f1550aca36a009d47ecf5aa263a38600f35b0 \
|
||||
--hash=sha256:cdfd501c7ac5b198c15df800a3a34c38345f5182e5f80770caf362bccca65628 \
|
||||
--hash=sha256:43b8ed3dbfd9171e44c554cb4acf4ee4505caa84c5e341858b50ea27dd2b6e12 \
|
||||
--hash=sha256:c2851deeabd96d3f6283e9c6b26e0bfed4de2dc6fb15edf913e78b79fc5909ed \
|
||||
--hash=sha256:955ba8ea73cf3ed8bd2f963b4cb9f8f0dcb27becd2f4b3dd536fd24c45533454 \
|
||||
--hash=sha256:5263db1e2e1e8ae30500cdd75a979ff99dcc184201e6b4b820d0de74834d2323 \
|
||||
--hash=sha256:e154891263306200260d7f3051982774d7b9ef35af3509d5adbbe539afd2610c \
|
||||
--hash=sha256:964f18a59f5a64c0170f684c417f4fe3e695a536612e13074c4dd5d1c6d7c882 \
|
||||
--hash=sha256:23344e3c2177baf6975fbfa361ed92eb7d36d08f454636e5054b3faa7c2aff8a \
|
||||
--hash=sha256:b27f082f47d23cffc4cf1388b84fdc45c4ef6015f906cd7e0d988d9e35d36349 \
|
||||
--hash=sha256:aa0af2deb166a5e26e0d554b824605e660039b161e37ed4f01b8d04beec184f3 \
|
||||
--hash=sha256:819f95d4eba3f9e484dd115ab7ab72845cf766b84286a00d4ecf76d33f1edca1 \
|
||||
--hash=sha256:2c1c570ae7bf1bab304f29427e2475fe1856814312c4a1cf1cd0ee133f07a3c6 \
|
||||
--hash=sha256:9e9c9078a7ce07e6fce366bd818be89365a35d2e4b163268f0ca9ba7e13bb2f6 \
|
||||
--hash=sha256:2c227c0ed371771ffda256034427320870e8ea2e4fd0c0a618c766e7c49aad73 \
|
||||
--hash=sha256:0a909bf501459062aa1552be1461456518f367379fdc9fdb1f2ca5e4a1fdd7c0 \
|
||||
--hash=sha256:1e4cbbc3858ec7e680006e5ca590d89a5e083235988f26a004acf7244389ac01 \
|
||||
--hash=sha256:a7bf1492429f18d205f3a818da3ff1f242f60aa59006e53dee00b4ef592a3363 \
|
||||
--hash=sha256:bcc371151d1512201d0214c36c0c150b1dc64f19c2b1a8c9cb1d7c7c15ebd93f \
|
||||
--hash=sha256:e64be68255234bb489a574c4f2f8df7029c98c81ec4d160d6cd836e7f0679390 \
|
||||
--hash=sha256:8968eeaa4d37a38f8ca1f9dbe53526b69628edc9c42229a5b2f56d98bb828c1f \
|
||||
--hash=sha256:b253fe4df2afea4dfa6b1fa8c5fef212aff8bcaaeb4207e81eed05cb5e4a7919 \
|
||||
--hash=sha256:969843fbdfbf56cdb71da6f0bdf50f9985b8b8aeb630102945306cf10a9c6af2 \
|
||||
--hash=sha256:e2e023a42dcbab8ed31f97c2bcdb980b7fbe0ada34037d87ba9d799664b58ded \
|
||||
--hash=sha256:06a039208f83744a702279b894c8cf24c14fd63c59cd917dcde168b79eef0680 \
|
||||
--hash=sha256:3ef2183de67b59930d2db8b8e8d4d58e00a50fcc5e92f4f678f6eed7a1c72d55 \
|
||||
--hash=sha256:996021ef33e0f50b97ff2d6b5f422a0fe5577de21a8873b58a779a5ddd1c3132
|
||||
idna==2.10; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" \
|
||||
--hash=sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0 \
|
||||
--hash=sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6
|
||||
iron-core==1.2.0 \
|
||||
--hash=sha256:38f0942e86bf72d426560a66e4e14ffafdc52da5bee9925a2ac3968b30c3725b
|
||||
iron-mq==0.9 \
|
||||
--hash=sha256:c90441d872d9c08968343810a2ad1cca1664d80fd2ad3a3a2dbec57b7b38ecfa
|
||||
jinxed==1.1.0; platform_system == "Windows" \
|
||||
--hash=sha256:6a61ccf963c16aa885304f27e6e5693783676897cea0c7f223270c8b8e78baf8 \
|
||||
--hash=sha256:d8f1731f134e9e6b04d95095845ae6c10eb15cb223a5f0cabdea87d4a279c305
|
||||
jmespath==0.10.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" \
|
||||
--hash=sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f \
|
||||
--hash=sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9
|
||||
natsort==7.1.1; python_version >= "3.4" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.4" \
|
||||
--hash=sha256:d0f4fc06ca163fa4a5ef638d9bf111c67f65eedcc7920f98dec08e489045b67e \
|
||||
--hash=sha256:00c603a42365830c4722a2eb7663a25919551217ec09a243d3399fa8dd4ac403
|
||||
psutil==5.8.0; (python_version >= "2.6" and python_full_version < "3.0.0") or (python_full_version >= "3.4.0") \
|
||||
--hash=sha256:0066a82f7b1b37d334e68697faba68e5ad5e858279fd6351c8ca6024e8d6ba64 \
|
||||
--hash=sha256:0ae6f386d8d297177fd288be6e8d1afc05966878704dad9847719650e44fc49c \
|
||||
--hash=sha256:12d844996d6c2b1d3881cfa6fa201fd635971869a9da945cf6756105af73d2df \
|
||||
--hash=sha256:02b8292609b1f7fcb34173b25e48d0da8667bc85f81d7476584d889c6e0f2131 \
|
||||
--hash=sha256:6ffe81843131ee0ffa02c317186ed1e759a145267d54fdef1bc4ea5f5931ab60 \
|
||||
--hash=sha256:ea313bb02e5e25224e518e4352af4bf5e062755160f77e4b1767dd5ccb65f876 \
|
||||
--hash=sha256:5da29e394bdedd9144c7331192e20c1f79283fb03b06e6abd3a8ae45ffecee65 \
|
||||
--hash=sha256:74fb2557d1430fff18ff0d72613c5ca30c45cdbfcddd6a5773e9fc1fe9364be8 \
|
||||
--hash=sha256:74f2d0be88db96ada78756cb3a3e1b107ce8ab79f65aa885f76d7664e56928f6 \
|
||||
--hash=sha256:99de3e8739258b3c3e8669cb9757c9a861b2a25ad0955f8e53ac662d66de61ac \
|
||||
--hash=sha256:36b3b6c9e2a34b7d7fbae330a85bf72c30b1c827a4366a07443fc4b6270449e2 \
|
||||
--hash=sha256:52de075468cd394ac98c66f9ca33b2f54ae1d9bff1ef6b67a212ee8f639ec06d \
|
||||
--hash=sha256:c6a5fd10ce6b6344e616cf01cc5b849fa8103fbb5ba507b6b2dee4c11e84c935 \
|
||||
--hash=sha256:61f05864b42fedc0771d6d8e49c35f07efd209ade09a5afe6a5059e7bb7bf83d \
|
||||
--hash=sha256:0dd4465a039d343925cdc29023bb6960ccf4e74a65ad53e768403746a9207023 \
|
||||
--hash=sha256:1bff0d07e76114ec24ee32e7f7f8d0c4b0514b3fae93e3d2aaafd65d22502394 \
|
||||
--hash=sha256:fcc01e900c1d7bee2a37e5d6e4f9194760a93597c97fee89c4ae51701de03563 \
|
||||
--hash=sha256:6223d07a1ae93f86451d0198a0c361032c4c93ebd4bf6d25e2fb3edfad9571ef \
|
||||
--hash=sha256:d225cd8319aa1d3c85bf195c4e07d17d3cd68636b8fc97e6cf198f782f99af28 \
|
||||
--hash=sha256:28ff7c95293ae74bf1ca1a79e8805fcde005c18a122ca983abf676ea3466362b \
|
||||
--hash=sha256:ce8b867423291cb65cfc6d9c4955ee9bfc1e21fe03bb50e177f2b957f1c2469d \
|
||||
--hash=sha256:90f31c34d25b1b3ed6c40cdd34ff122b1887a825297c017e4cbd6796dd8b672d \
|
||||
--hash=sha256:6323d5d845c2785efb20aded4726636546b26d3b577aded22492908f7c1bdda7 \
|
||||
--hash=sha256:245b5509968ac0bd179287d91210cd3f37add77dad385ef238b275bad35fa1c4 \
|
||||
--hash=sha256:90d4091c2d30ddd0a03e0b97e6a33a48628469b99585e2ad6bf21f17423b112b \
|
||||
--hash=sha256:ea372bcc129394485824ae3e3ddabe67dc0b118d262c568b4d2602a7070afdb0 \
|
||||
--hash=sha256:f4634b033faf0d968bb9220dd1c793b897ab7f1189956e1aa9eae752527127d3 \
|
||||
--hash=sha256:0c9ccb99ab76025f2f0bbecf341d4656e9c1351db8cc8a03ccd62e318ab4b5c6
|
||||
pymongo==3.11.4 \
|
||||
--hash=sha256:b7efc7e7049ef366777cfd35437c18a4166bb50a5606a1c840ee3b9624b54fc9 \
|
||||
--hash=sha256:517ba47ca04a55b1f50ee8df9fd97f6c37df5537d118fb2718952b8623860466 \
|
||||
--hash=sha256:225c61e08fe517aede7912937939e09adf086c8e6f7e40d4c85ad678c2c2aea3 \
|
||||
--hash=sha256:e4e9db78b71db2b1684ee4ecc3e32c4600f18cdf76e6b9ae03e338e52ee4b168 \
|
||||
--hash=sha256:8e0004b0393d72d76de94b4792a006cb960c1c65c7659930fbf9a81ce4341982 \
|
||||
--hash=sha256:fedf0dee7a412ca6d1d6d92c158fe9cbaa8ea0cae90d268f9ccc0744de7a97d0 \
|
||||
--hash=sha256:f947b359cc4769af8b49be7e37af01f05fcf15b401da2528021148e4a54426d1 \
|
||||
--hash=sha256:3a3498a8326111221560e930f198b495ea6926937e249f475052ffc6893a6680 \
|
||||
--hash=sha256:9a4f6e0b01df820ba9ed0b4e618ca83a1c089e48d4f268d0e00dcd49893d4549 \
|
||||
--hash=sha256:d65bac5f6724d9ea6f0b5a0f0e4952fbbf209adcf6b5583b54c54bd2fcd74dc0 \
|
||||
--hash=sha256:15b083d1b789b230e5ac284442d9ecb113c93f3785a6824f748befaab803b812 \
|
||||
--hash=sha256:f08665d3cc5abc2f770f472a9b5f720a9b3ab0b8b3bb97c7c1487515e5653d39 \
|
||||
--hash=sha256:977b1d4f868986b4ba5d03c317fde4d3b66e687d74473130cd598e3103db34fa \
|
||||
--hash=sha256:510cd3bfabb63a07405b7b79fae63127e34c118b7531a2cbbafc7a24fd878594 \
|
||||
--hash=sha256:071552b065e809d24c5653fcc14968cfd6fde4e279408640d5ac58e3353a3c5f \
|
||||
--hash=sha256:f4ba58157e8ae33ee86fadf9062c506e535afd904f07f9be32731f4410a23b7f \
|
||||
--hash=sha256:b413117210fa6d92664c3d860571e8e8727c3e8f2ff197276c5d0cb365abd3ad \
|
||||
--hash=sha256:08b8723248730599c9803ae4c97b8f3f76c55219104303c88cb962a31e3bb5ee \
|
||||
--hash=sha256:8a41fdc751dc4707a4fafb111c442411816a7c225ebb5cadb57599534b5d5372 \
|
||||
--hash=sha256:f664ed7613b8b18f0ce5696b146776266a038c19c5cd6efffa08ecc189b01b73 \
|
||||
--hash=sha256:5c36428cc4f7fae56354db7f46677fd21222fc3cb1e8829549b851172033e043 \
|
||||
--hash=sha256:d0a70151d7de8a3194cdc906bcc1a42e14594787c64b0c1c9c975e5a2af3e251 \
|
||||
--hash=sha256:9b9298964389c180a063a9e8bac8a80ed42de11d04166b20249bfa0a489e0e0f \
|
||||
--hash=sha256:b2f41261b648cf5dee425f37ff14f4ad151c2f24b827052b402637158fd056ef \
|
||||
--hash=sha256:e02beaab433fd1104b2804f909e694cfbdb6578020740a9051597adc1cd4e19f \
|
||||
--hash=sha256:8898f6699f740ca93a0879ed07d8e6db02d68af889d0ebb3d13ab017e6b1af1e \
|
||||
--hash=sha256:62c29bc36a6d9be68fe7b5aaf1e120b4aa66a958d1e146601fcd583eb12cae7b \
|
||||
--hash=sha256:424799c71ff435094e5fb823c40eebb4500f0e048133311e9c026467e8ccebac \
|
||||
--hash=sha256:3551912f5c34d8dd7c32c6bb00ae04192af47f7b9f653608f107d19c1a21a194 \
|
||||
--hash=sha256:5db59223ed1e634d842a053325f85f908359c6dac9c8ddce8ef145061fae7df8 \
|
||||
--hash=sha256:fea5cb1c63efe1399f0812532c7cf65458d38fd011be350bc5021dfcac39fba8 \
|
||||
--hash=sha256:d4e62417e89b717a7bcd8576ac3108cd063225942cc91c5b37ff5465fdccd386 \
|
||||
--hash=sha256:4c7e8c8e1e1918dcf6a652ac4b9d87164587c26fd2ce5dd81e73a5ab3b3d492f \
|
||||
--hash=sha256:38a7b5140a48fc91681cdb5cb95b7cd64640b43d19259fdd707fa9d5a715f2b2 \
|
||||
--hash=sha256:aff3656af2add93f290731a6b8930b23b35c0c09569150130a58192b3ec6fc61 \
|
||||
--hash=sha256:03be7ad107d252bb7325d4af6309fdd2c025d08854d35f0e7abc8bf048f4245e \
|
||||
--hash=sha256:6060794aac9f7b0644b299f46a9c6cbc0bc470bd01572f4134df140afd41ded6 \
|
||||
--hash=sha256:73326b211e7410c8bd6a74500b1e3f392f39cf10862e243d00937e924f112c01 \
|
||||
--hash=sha256:20d75ea11527331a2980ab04762a9d960bcfea9475c54bbeab777af880de61cd \
|
||||
--hash=sha256:3135dd574ef1286189f3f04a36c8b7a256376914f8cbbce66b94f13125ded858 \
|
||||
--hash=sha256:7c97554ea521f898753d9773891d0347ebfaddcc1dee2ad94850b163171bf1f1 \
|
||||
--hash=sha256:a08c8b322b671857c81f4c30cd3c8df2895fd3c0e9358714f39e0ef8fb327702 \
|
||||
--hash=sha256:f3d851af3852f16ad4adc7ee054fd9c90a7a5063de94d815b7f6a88477b9f4c6 \
|
||||
--hash=sha256:3bfc7689a1bacb9bcd2f2d5185d99507aa29f667a58dd8adaa43b5a348139e46 \
|
||||
--hash=sha256:b8f94acd52e530a38f25e4d5bf7ddfdd4bea9193e718f58419def0d4406b58d3 \
|
||||
--hash=sha256:e4b631688dfbdd61b5610e20b64b99d25771c6d52d9da73349342d2a0f11c46a \
|
||||
--hash=sha256:474e21d0e07cd09679e357d1dac76e570dab86665e79a9d3354b10a279ac6fb3 \
|
||||
--hash=sha256:421d13523d11c57f57f257152bc4a6bb463aadf7a3918e9c96fefdd6be8dbfb8 \
|
||||
--hash=sha256:0cabfc297f4cf921f15bc789a8fbfd7115eb9f813d3f47a74b609894bc66ab0d \
|
||||
--hash=sha256:fe4189846448df013cd9df11bba38ddf78043f8c290a9f06430732a7a8601cce \
|
||||
--hash=sha256:eb4d176394c37a76e8b0afe54b12d58614a67a60a7f8c0dd3a5afbb013c01092 \
|
||||
--hash=sha256:fffff7bfb6799a763d3742c59c6ee7ffadda21abed557637bc44ed1080876484 \
|
||||
--hash=sha256:13acf6164ead81c9fc2afa0e1ea6d6134352973ce2bb35496834fee057063c04 \
|
||||
--hash=sha256:d360e5d5dd3d55bf5d1776964625018d85b937d1032bae1926dd52253decd0db \
|
||||
--hash=sha256:0aaf4d44f1f819360f9432df538d54bbf850f18152f34e20337c01b828479171 \
|
||||
--hash=sha256:08bda7b2c522ff9f1e554570da16298271ebb0c56ab9699446aacba249008988 \
|
||||
--hash=sha256:1a994a42f49dab5b6287e499be7d3d2751776486229980d8857ad53b8333d469 \
|
||||
--hash=sha256:161fcd3281c42f644aa8dec7753cca2af03ce654e17d76da4f0dab34a12480ca \
|
||||
--hash=sha256:78f07961f4f214ea8e80be63cffd5cc158eb06cd922ffbf6c7155b11728f28f9 \
|
||||
--hash=sha256:ad31f184dcd3271de26ab1f9c51574afb99e1b0e484ab1da3641256b723e4994 \
|
||||
--hash=sha256:5e606846c049ed40940524057bfdf1105af6066688c0e6a1a3ce2038589bae70 \
|
||||
--hash=sha256:3491c7de09e44eded16824cb58cf9b5cc1dc6f066a0bb7aa69929d02aa53b828 \
|
||||
--hash=sha256:506a6dab4c7ffdcacdf0b8e70bd20eb2e77fa994519547c9d88d676400fcad58 \
|
||||
--hash=sha256:539d4cb1b16b57026999c53e5aab857fe706e70ae5310cc8c232479923f932e6
|
||||
python-dateutil==2.8.1; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" \
|
||||
--hash=sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c \
|
||||
--hash=sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a
|
||||
pytz==2021.1; python_version >= "3.6" \
|
||||
--hash=sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798 \
|
||||
--hash=sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da
|
||||
redis==3.5.3; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.5.0") \
|
||||
--hash=sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24 \
|
||||
--hash=sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2
|
||||
requests==2.25.1; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" \
|
||||
--hash=sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e \
|
||||
--hash=sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804
|
||||
s3transfer==0.4.2; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" \
|
||||
--hash=sha256:9b3752887a2880690ce628bc263d6d13a3864083aeacff4890c1c9839a5eb0bc \
|
||||
--hash=sha256:cb022f4b16551edebbb31a377d3f09600dbada7363d8c5db7976e7f47732e1b2
|
||||
six==1.16.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" \
|
||||
--hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 \
|
||||
--hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926
|
||||
sqlparse==0.4.1; python_version >= "3.6" \
|
||||
--hash=sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0 \
|
||||
--hash=sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8
|
||||
typing-extensions==3.10.0.0; python_version < "3.8" and python_version >= "3.6" \
|
||||
--hash=sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497 \
|
||||
--hash=sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84 \
|
||||
--hash=sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342
|
||||
urllib3==1.26.4; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version < "4" \
|
||||
--hash=sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df \
|
||||
--hash=sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937
|
||||
wcwidth==0.2.5 \
|
||||
--hash=sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784 \
|
||||
--hash=sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83
|
||||
|
||||
3447
runtests.py
3447
runtests.py
File diff suppressed because it is too large
Load Diff
71
setup.py
71
setup.py
@@ -1,71 +0,0 @@
|
||||
import os
|
||||
from setuptools import setup, Command
|
||||
|
||||
with open(os.path.join(os.path.dirname(__file__), 'README.rst')) as readme:
|
||||
README = readme.read()
|
||||
|
||||
os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir)))
|
||||
|
||||
|
||||
class PyTest(Command):
|
||||
user_options = []
|
||||
|
||||
def initialize_options(self):
|
||||
pass
|
||||
|
||||
def finalize_options(self):
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
errno = subprocess.call([sys.executable, 'runtests.py'])
|
||||
raise SystemExit(errno)
|
||||
|
||||
|
||||
setup(
|
||||
name='django-q',
|
||||
version='1.3.6',
|
||||
author='Ilan Steemers',
|
||||
author_email='koed00@gmail.com',
|
||||
keywords='django multiprocessing worker scheduler queue',
|
||||
packages=['django_q'],
|
||||
include_package_data=True,
|
||||
url='https://django-q.readthedocs.org',
|
||||
license='MIT',
|
||||
description='A multiprocessing distributed task queue for Django',
|
||||
long_description=README,
|
||||
long_description_content_type='text/x-rst',
|
||||
install_requires=['django>=2.2', 'django-picklefield', 'blessed', 'arrow'],
|
||||
test_requires=['pytest', 'pytest-django', ],
|
||||
cmdclass={'test': PyTest},
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Environment :: Web Environment',
|
||||
'Framework :: Django',
|
||||
'Intended Audience :: Developers',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Operating System :: POSIX',
|
||||
'Operating System :: MacOS',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Programming Language :: Python :: 3.9',
|
||||
'Topic :: Internet :: WWW/HTTP',
|
||||
'Topic :: System :: Distributed Computing',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||
],
|
||||
entry_points={
|
||||
'djangoq.errorreporters': [
|
||||
'rollbar = django_q_rollbar:Rollbar',
|
||||
'sentry = django_q_sentry:Sentry',
|
||||
]
|
||||
},
|
||||
extras_require={
|
||||
'rollbar': ["django-q-rollbar>=0.1"],
|
||||
'sentry': ["django-q-sentry>=0.1"],
|
||||
}
|
||||
)
|
||||
Reference in New Issue
Block a user