Removed Django
This commit is contained in:
parent
9565fa4640
commit
790089df7d
|
@ -1,2 +0,0 @@
|
|||
JEEVES_DEBUG=on
|
||||
DATABASE_URL=sqlite:///local.db
|
11
Dockerfile
11
Dockerfile
|
@ -1,11 +0,0 @@
|
|||
FROM python:3
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
|
||||
WORKDIR /opt/app
|
||||
|
||||
ADD . /opt/app
|
||||
|
||||
RUN pip install poetry && \
|
||||
poetry install
|
||||
|
||||
CMD ["poetry", "run", "python", "manage.py", "runserver", "0.0.0.0:8000"]
|
7
Makefile
7
Makefile
|
@ -1,9 +1,6 @@
|
|||
quicksetup:
|
||||
poetry install
|
||||
poetry run pre-commit install
|
||||
cp .env.example .env
|
||||
poetry run python manage.py migrate
|
||||
poetry run python manage.py loaddata local_data
|
||||
|
||||
clean:
|
||||
if [ -f "local.db" ]; then rm local.db; fi;
|
||||
test:
|
||||
poetry run pytest . --cov=jeeves.core
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
version: "3"
|
||||
|
||||
services:
|
||||
backend:
|
||||
build: .
|
||||
restart: always
|
||||
volumes:
|
||||
- .:/opt/app
|
||||
ports:
|
||||
- 8000:8000
|
||||
depends_on:
|
||||
- redis
|
||||
env_file:
|
||||
- .env
|
||||
|
||||
redis:
|
||||
image: redis:5
|
||||
|
||||
worker:
|
||||
build: .
|
||||
restart: always
|
||||
command: poetry run python manage.py rundramatiq
|
||||
volumes:
|
||||
- .:/opt/app
|
||||
depends_on:
|
||||
- redis
|
||||
env_file:
|
||||
- .env
|
|
@ -1 +0,0 @@
|
|||
default_app_config = "jeeves.db.apps.DBAppConfig"
|
|
@ -1,13 +0,0 @@
|
|||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
from .models import Run, Flow, Task
|
||||
|
||||
|
||||
class TaskAdmin(admin.ModelAdmin):
|
||||
list_display = ("name", "type", "pk")
|
||||
|
||||
|
||||
admin.site.register(Flow)
|
||||
admin.site.register(Run)
|
||||
admin.site.register(Task, TaskAdmin)
|
|
@ -1,10 +0,0 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
from jeeves.core.registry import TaskRegistry
|
||||
|
||||
|
||||
class DBAppConfig(AppConfig):
|
||||
name = "jeeves.db"
|
||||
|
||||
def ready(self):
|
||||
TaskRegistry.autodiscover()
|
|
@ -1,20 +0,0 @@
|
|||
[
|
||||
{
|
||||
"model": "auth.user",
|
||||
"pk": 1,
|
||||
"fields": {
|
||||
"password": "pbkdf2_sha256$150000$8GIlObHdvhdv$phdSFNeTHkkN6MJnzBCcuC+qo5RI0gAQdLhAmWyFSR0=",
|
||||
"last_login": "2019-09-23T18:48:28.585Z",
|
||||
"is_superuser": true,
|
||||
"username": "admin",
|
||||
"first_name": "",
|
||||
"last_name": "",
|
||||
"email": "admin@admin.com",
|
||||
"is_staff": true,
|
||||
"is_active": true,
|
||||
"date_joined": "2019-09-23T18:48:20.713Z",
|
||||
"groups": [],
|
||||
"user_permissions": []
|
||||
}
|
||||
}
|
||||
]
|
|
@ -1,93 +0,0 @@
|
|||
# Generated by Django 2.2.5 on 2019-09-23 20:56
|
||||
|
||||
import uuid
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import models, migrations
|
||||
|
||||
import jeeves.db.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = []
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="Flow",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.UUIDField(
|
||||
default=uuid.uuid4,
|
||||
editable=False,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
),
|
||||
),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("modified_at", models.DateTimeField(auto_now=True)),
|
||||
("name", models.CharField(max_length=64)),
|
||||
("_definition", models.TextField()),
|
||||
],
|
||||
options={"abstract": False},
|
||||
bases=(models.Model, jeeves.db.models.DefinitionMixin),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="Task",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.UUIDField(
|
||||
default=uuid.uuid4,
|
||||
editable=False,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
),
|
||||
),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("modified_at", models.DateTimeField(auto_now=True)),
|
||||
("type", models.CharField(max_length=32)),
|
||||
("_definition", models.TextField()),
|
||||
],
|
||||
options={"abstract": False},
|
||||
bases=(jeeves.db.models.DefinitionMixin, models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="Run",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.UUIDField(
|
||||
default=uuid.uuid4,
|
||||
editable=False,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
),
|
||||
),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("modified_at", models.DateTimeField(auto_now=True)),
|
||||
(
|
||||
"status",
|
||||
models.CharField(
|
||||
choices=[("pending", "Pending"), ("finished", "Finished")],
|
||||
default="pending",
|
||||
max_length=32,
|
||||
),
|
||||
),
|
||||
("success", models.BooleanField(default=True)),
|
||||
("_definition", models.TextField()),
|
||||
("_result", models.TextField(default="{}")),
|
||||
(
|
||||
"flow",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE, to="db.Flow"
|
||||
),
|
||||
),
|
||||
],
|
||||
options={"abstract": False},
|
||||
bases=(jeeves.db.models.DefinitionMixin, models.Model),
|
||||
),
|
||||
]
|
|
@ -1,17 +0,0 @@
|
|||
# Generated by Django 2.2.5 on 2019-09-25 21:00
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("db", "0001_initial")]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="task",
|
||||
name="name",
|
||||
field=models.CharField(default="Hey", max_length=128),
|
||||
preserve_default=False,
|
||||
)
|
||||
]
|
|
@ -1,14 +0,0 @@
|
|||
# Generated by Django 2.2.5 on 2019-09-25 21:23
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("db", "0002_task_name")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="task", name="type", field=models.CharField(max_length=128)
|
||||
)
|
||||
]
|
|
@ -1,21 +0,0 @@
|
|||
# Generated by Django 2.2.5 on 2019-09-26 16:13
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("db", "0003_auto_20190925_2123")]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="run",
|
||||
name="stderr",
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="run",
|
||||
name="stdout",
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
]
|
|
@ -1,21 +0,0 @@
|
|||
# Generated by Django 2.2.5 on 2019-09-26 16:29
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("db", "0004_auto_20190926_1613")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="run",
|
||||
name="stderr",
|
||||
field=models.TextField(blank=True, default=""),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="run",
|
||||
name="stdout",
|
||||
field=models.TextField(blank=True, default=""),
|
||||
),
|
||||
]
|
|
@ -1,18 +0,0 @@
|
|||
# Generated by Django 2.2.5 on 2019-09-29 17:46
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("db", "0005_auto_20190926_1629")]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(model_name="run", old_name="stderr", new_name="output"),
|
||||
migrations.RemoveField(model_name="run", name="stdout"),
|
||||
migrations.AlterField(
|
||||
model_name="flow",
|
||||
name="_definition",
|
||||
field=models.TextField(default='{"tasks": []}'),
|
||||
),
|
||||
]
|
|
@ -1,172 +0,0 @@
|
|||
import copy
|
||||
import json
|
||||
import uuid
|
||||
import logging
|
||||
|
||||
from django.db import models
|
||||
|
||||
from jeeves.core.registry import TaskRegistry
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BaseModel(models.Model):
|
||||
"""
|
||||
Abstract model used when creating models in the project.
|
||||
|
||||
Uses an UUID4 as primary key field and adds a created_at, modified_at
|
||||
fields.
|
||||
"""
|
||||
|
||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
modified_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
||||
class DefinitionMixin:
|
||||
@property
|
||||
def definition(self):
|
||||
return json.loads(self._definition)
|
||||
|
||||
@definition.setter
|
||||
def definition(self, value: dict):
|
||||
self._definition = json.dumps(value)
|
||||
|
||||
|
||||
class Flow(BaseModel, DefinitionMixin):
|
||||
name = models.CharField(max_length=64)
|
||||
_definition = models.TextField(default=json.dumps({"tasks": []}))
|
||||
|
||||
def serialize(self):
|
||||
definition = copy.deepcopy(self.definition)
|
||||
definition["tasks"] = [task.serialize() for task in self.tasks]
|
||||
return {"name": self.name, "definition": definition}
|
||||
|
||||
@property
|
||||
def tasks(self):
|
||||
for task_ref in self.definition["tasks"]:
|
||||
try:
|
||||
task = Task.objects.from_reference(task_ref)
|
||||
yield task
|
||||
except Task.DoesNotExist:
|
||||
logger.warning(
|
||||
f"Task {task_ref} does not exist on db, removing from definition"
|
||||
)
|
||||
# TODO: Dirty cleanup of dangling tasks in definitions
|
||||
definition = self.definition
|
||||
definition["tasks"].remove(task_ref)
|
||||
self.definition = definition
|
||||
self.save()
|
||||
|
||||
def execute(self, foreground=False):
|
||||
from jeeves.db.tasks import start_execution
|
||||
|
||||
execution = Run.from_flow(self)
|
||||
if not foreground:
|
||||
start_execution.send(execution_id=str(execution.pk))
|
||||
else:
|
||||
start_execution(execution_id=str(execution.pk))
|
||||
return Run.objects.get(pk=str(execution.pk)) # Reload model instance
|
||||
|
||||
|
||||
class TaskManager(models.Manager):
|
||||
def from_reference(self, reference):
|
||||
return self.get_queryset().get(pk=reference)
|
||||
|
||||
|
||||
class Task(DefinitionMixin, BaseModel):
|
||||
name = models.CharField(max_length=128)
|
||||
type = models.CharField(max_length=128)
|
||||
_definition = models.TextField()
|
||||
|
||||
objects = TaskManager()
|
||||
|
||||
def serialize(self):
|
||||
return {"type": self.type, "definition": self.definition}
|
||||
|
||||
@property
|
||||
def instance(self):
|
||||
return TaskRegistry.get_task(self.type, **self.definition)
|
||||
|
||||
def run(self):
|
||||
runner = self.instance
|
||||
return FlowStep(str(self.pk), *runner.execute())
|
||||
|
||||
|
||||
class Run(DefinitionMixin, BaseModel):
|
||||
PENDING = "pending"
|
||||
FINISHED = "finished"
|
||||
RUN_STATUS = ((PENDING, PENDING.capitalize()), (FINISHED, FINISHED.capitalize()))
|
||||
status = models.CharField(max_length=32, choices=RUN_STATUS, default=PENDING)
|
||||
success = models.BooleanField(default=True)
|
||||
output = models.TextField(blank=True, default="")
|
||||
flow = models.ForeignKey(Flow, on_delete=models.CASCADE)
|
||||
_definition = models.TextField()
|
||||
_result = models.TextField(default="{}")
|
||||
|
||||
@property
|
||||
def duration(self):
|
||||
# TODO: Proper ended_at
|
||||
return self.modified_at - self.created_at
|
||||
|
||||
@property
|
||||
def result(self):
|
||||
return json.loads(self._result)
|
||||
|
||||
@result.setter
|
||||
def result(self, value: dict):
|
||||
self._result = json.dumps(value)
|
||||
|
||||
@classmethod
|
||||
def from_flow(cls, flow: Flow):
|
||||
execution = cls()
|
||||
execution.definition = flow.serialize()
|
||||
execution.flow = flow
|
||||
execution.save()
|
||||
return execution
|
||||
|
||||
|
||||
class FlowStep:
|
||||
task: str
|
||||
executed: bool = True
|
||||
error: bool = False
|
||||
output: str
|
||||
|
||||
def __init__(self, task_id, error, output):
|
||||
self.task = task_id
|
||||
self.error = error
|
||||
self.output = output
|
||||
|
||||
def __repr__(self):
|
||||
return f"<FlowStep error={self.error}>"
|
||||
|
||||
def serialize(self):
|
||||
return {
|
||||
"task": self.task,
|
||||
"executed": self.executed,
|
||||
"error": self.error,
|
||||
"output": self.output,
|
||||
}
|
||||
|
||||
|
||||
class Result:
|
||||
def __init__(self):
|
||||
self.steps = []
|
||||
|
||||
def __repr__(self):
|
||||
return f"""<Result
|
||||
last={self.last_flow_step}>
|
||||
"""
|
||||
|
||||
def serialize(self):
|
||||
return {"steps": [step.serialize() for step in self.steps]}
|
||||
|
||||
def add_step(self, flow_step):
|
||||
self.steps.append(flow_step)
|
||||
|
||||
@property
|
||||
def last_flow_step(self):
|
||||
return self.steps[-1]
|
|
@ -1,22 +0,0 @@
|
|||
import json
|
||||
|
||||
import dramatiq
|
||||
|
||||
from jeeves.db.models import Run, Result
|
||||
|
||||
|
||||
@dramatiq.actor
|
||||
def start_execution(execution_id):
|
||||
run = Run.objects.get(pk=execution_id)
|
||||
result = Result()
|
||||
for task in run.flow.tasks:
|
||||
flow_step = task.run()
|
||||
result.add_step(flow_step)
|
||||
run.output += flow_step.output
|
||||
if flow_step.error:
|
||||
run.success = False
|
||||
break
|
||||
run._result = json.dumps(result.serialize())
|
||||
run.status = Run.FINISHED
|
||||
run.save()
|
||||
return run
|
|
@ -1 +0,0 @@
|
|||
urlpatterns = []
|
|
@ -1,5 +0,0 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class FrontendConfig(AppConfig):
|
||||
name = "frontend"
|
|
@ -1,127 +0,0 @@
|
|||
import os
|
||||
|
||||
import environ
|
||||
|
||||
env = environ.Env()
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
environ.Env.read_env(env_file=os.path.join(BASE_DIR, ".env"))
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = env.str("SECRET_KEY", default="1234567890")
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = env.bool("JEEVES_DEBUG", default=False)
|
||||
|
||||
ALLOWED_HOSTS = env.list("JEEVES_ALLOWED_HOSTS", default=["*"])
|
||||
|
||||
# Application definition
|
||||
INSTALLED_APPS = [
|
||||
# Django
|
||||
"django.contrib.admin",
|
||||
"django.contrib.auth",
|
||||
"django.contrib.contenttypes",
|
||||
"django.contrib.sessions",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
# Third party
|
||||
"django_dramatiq",
|
||||
# Own
|
||||
"jeeves.db",
|
||||
"jeeves.frontend",
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.middleware.csrf.CsrfViewMiddleware",
|
||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||
"django.contrib.messages.middleware.MessageMiddleware",
|
||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||
]
|
||||
|
||||
ROOT_URLCONF = "jeeves.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.jinja2.Jinja2", "APP_DIRS": True, "DIRS": []},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = "jeeves.wsgi.application"
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
|
||||
|
||||
DATABASES = {"default": env.db()}
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"
|
||||
},
|
||||
{"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"},
|
||||
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"},
|
||||
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"},
|
||||
]
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/2.2/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = "en-us"
|
||||
|
||||
TIME_ZONE = "UTC"
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/2.2/howto/static-files/
|
||||
|
||||
STATIC_URL = "/static/"
|
||||
|
||||
# Dramatiq
|
||||
DRAMATIQ_BROKER = {
|
||||
"BROKER": "dramatiq.brokers.redis.RedisBroker",
|
||||
"OPTIONS": {"url": "redis://redis:6379/0"},
|
||||
"MIDDLEWARE": [
|
||||
"dramatiq.middleware.Prometheus",
|
||||
"dramatiq.middleware.AgeLimit",
|
||||
"dramatiq.middleware.TimeLimit",
|
||||
"dramatiq.middleware.Callbacks",
|
||||
"dramatiq.middleware.Retries",
|
||||
"django_dramatiq.middleware.AdminMiddleware",
|
||||
"django_dramatiq.middleware.DbConnectionsMiddleware",
|
||||
],
|
||||
}
|
||||
|
||||
# Defines which database should be used to persist Task objects when the
|
||||
# AdminMiddleware is enabled. The default value is "default".
|
||||
DRAMATIQ_TASKS_DATABASE = "default"
|
|
@ -1,22 +0,0 @@
|
|||
"""jeeves URL Configuration
|
||||
|
||||
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||
https://docs.djangoproject.com/en/2.2/topics/http/urls/
|
||||
Examples:
|
||||
Function views
|
||||
1. Add an import: from my_app import views
|
||||
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||
Class-based views
|
||||
1. Add an import: from other_app.views import Home
|
||||
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||
Including another URLconf
|
||||
1. Import the include() function: from django.urls import include, path
|
||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||
"""
|
||||
from django.urls import path, include
|
||||
from django.contrib import admin
|
||||
|
||||
urlpatterns = [
|
||||
path("admin/", admin.site.urls),
|
||||
path("", include("jeeves.frontend.urls")),
|
||||
]
|
|
@ -1,16 +0,0 @@
|
|||
"""
|
||||
WSGI config for jeeves project.
|
||||
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "jeeves.settings")
|
||||
|
||||
application = get_wsgi_application()
|
21
manage.py
21
manage.py
|
@ -1,21 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
"""Django's command-line utility for administrative tasks."""
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "jeeves.settings")
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError as exc:
|
||||
raise ImportError(
|
||||
"Couldn't import Django. Are you sure it's installed and "
|
||||
"available on your PYTHONPATH environment variable? Did you "
|
||||
"forget to activate a virtual environment?"
|
||||
) from exc
|
||||
execute_from_command_line(sys.argv)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -9,12 +9,8 @@ jeeves = "jeeves.cli:main"
|
|||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.7"
|
||||
django = "^2.2"
|
||||
django-environ = "^0.4.5"
|
||||
jinja2 = "^2.10"
|
||||
pydantic = "^0.32.2"
|
||||
django_dramatiq = "^0.8.0"
|
||||
dramatiq = {version = "^1.7", extras = ["redis"]}
|
||||
click = "^7.0"
|
||||
toml = "^0.10.0"
|
||||
|
||||
|
|
|
@ -11,6 +11,6 @@ include_trailing_comma = True
|
|||
length_sort = 1
|
||||
lines_between_types = 0
|
||||
line_length = 88
|
||||
known_third_party = click,django,dramatiq,environ,factory,pydantic,pytest,toml
|
||||
known_third_party = click,django,factory,pydantic,pytest,toml
|
||||
sections = FUTURE, STDLIB, DJANGO, THIRDPARTY, FIRSTPARTY, LOCALFOLDER
|
||||
no_lines_before = LOCALFOLDER
|
||||
|
|
Reference in New Issue