Settings, Themes and Migration Route Tests (#100)

* dev-bug: fixed vscode freezes

* test: refactor database init to support tests

* mealplan CRUD testing

* restructure test folder

* git attributes

* tests: migration, settings, theme routes testing

Co-authored-by: Hayden <hay-kot@pm.me>
This commit is contained in:
Hayden 2021-01-19 15:51:36 -09:00 committed by GitHub
commit 29db7f8a67
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
40 changed files with 367 additions and 93 deletions

3
.gitattributes vendored
View file

@ -1 +1,2 @@
*.css linguist-detectable=false *.css linguist-detectable=false
*.html linguist-detectable=false

View file

@ -1,7 +1,7 @@
import shutil import shutil
from app_config import MIGRATION_DIR from app_config import MIGRATION_DIR
from db.db_setup import create_session from db.db_setup import generate_session
from fastapi import APIRouter, Depends, File, HTTPException, UploadFile from fastapi import APIRouter, Depends, File, HTTPException, UploadFile
from models.migration_models import ChowdownURL from models.migration_models import ChowdownURL
from services.migrations.chowdown import chowdown_migrate as chowdow_migrate from services.migrations.chowdown import chowdown_migrate as chowdow_migrate
@ -14,7 +14,7 @@ router = APIRouter(tags=["Migration"])
# Chowdown # Chowdown
@router.post("/api/migration/chowdown/repo/") @router.post("/api/migration/chowdown/repo/")
def import_chowdown_recipes(repo: ChowdownURL, db: Session = Depends(create_session)): def import_chowdown_recipes(repo: ChowdownURL, db: Session = Depends(generate_session)):
""" Import Chowsdown Recipes from Repo URL """ """ Import Chowsdown Recipes from Repo URL """
try: try:
report = chowdow_migrate(db, repo.url) report = chowdow_migrate(db, repo.url)
@ -46,7 +46,7 @@ def get_avaiable_nextcloud_imports():
@router.post("/api/migration/nextcloud/{selection}/import/") @router.post("/api/migration/nextcloud/{selection}/import/")
def import_nextcloud_directory(selection: str, db: Session = Depends(create_session)): def import_nextcloud_directory(selection: str, db: Session = Depends(generate_session)):
""" Imports all the recipes in a given directory """ """ Imports all the recipes in a given directory """
return nextcloud_migrate(db, selection) return nextcloud_migrate(db, selection)

View file

@ -52,10 +52,7 @@ def get_all_recipes_post(
return all_recipes return all_recipes
@router.get( @router.get("/api/recipe/{recipe_slug}/", response_model=Recipe)
"/api/recipe/{recipe_slug}/",
response_model=Recipe,
)
def get_recipe(recipe_slug: str, db: Session = Depends(generate_session)): def get_recipe(recipe_slug: str, db: Session = Depends(generate_session)):
""" Takes in a recipe slug, returns all data for a recipe """ """ Takes in a recipe slug, returns all data for a recipe """
recipe = Recipe.get_by_slug(db, recipe_slug) recipe = Recipe.get_by_slug(db, recipe_slug)

View file

@ -24,9 +24,9 @@ def test_webhooks():
@router.post("/api/site-settings/update/") @router.post("/api/site-settings/update/")
def update_settings(data: SiteSettings): def update_settings(data: SiteSettings, db: Session = Depends(generate_session)):
""" Returns Site Settings """ """ Returns Site Settings """
data.update() data.update(db)
# try: # try:
# data.update() # data.update()
# except: # except:
@ -34,7 +34,7 @@ def update_settings(data: SiteSettings):
# status_code=400, detail=SnackResponse.error("Unable to Save Settings") # status_code=400, detail=SnackResponse.error("Unable to Save Settings")
# ) # )
scheduler.reschedule_webhooks() # scheduler.reschedule_webhooks() #! Need to fix Scheduler
return SnackResponse.success("Settings Updated") return SnackResponse.success("Settings Updated")

View file

@ -3,7 +3,7 @@ from pathlib import Path
import git import git
import yaml import yaml
from app_config import IMG_DIR from app_config import IMG_DIR, TEMP_DIR
from services.recipe_services import Recipe from services.recipe_services import Recipe
from sqlalchemy.orm.session import Session from sqlalchemy.orm.session import Session
@ -12,8 +12,6 @@ try:
except ImportError: except ImportError:
from yaml import Loader from yaml import Loader
TEMP_DIR = Path(__file__).parent.parent.parent.joinpath("temp")
def pull_repo(repo): def pull_repo(repo):
dest_dir = TEMP_DIR.joinpath("/migration/git_pull") dest_dir = TEMP_DIR.joinpath("/migration/git_pull")

View file

@ -4,13 +4,10 @@ import shutil
import zipfile import zipfile
from pathlib import Path from pathlib import Path
from app_config import IMG_DIR, TEMP_DIR from app_config import IMG_DIR, MIGRATION_DIR, TEMP_DIR
from services.recipe_services import Recipe from services.recipe_services import Recipe
from services.scrape_services import normalize_data, process_recipe_data from services.scrape_services import normalize_data, process_recipe_data
CWD = Path(__file__).parent
MIGRTAION_DIR = CWD.parent.parent.joinpath("data", "migration")
def process_selection(selection: Path) -> Path: def process_selection(selection: Path) -> Path:
if selection.is_dir(): if selection.is_dir():
@ -67,8 +64,8 @@ def cleanup():
def migrate(session, selection: str): def migrate(session, selection: str):
prep() prep()
MIGRTAION_DIR.mkdir(exist_ok=True) MIGRATION_DIR.mkdir(exist_ok=True)
selection = MIGRTAION_DIR.joinpath(selection) selection = MIGRATION_DIR.joinpath(selection)
nextcloud_dir = process_selection(selection) nextcloud_dir = process_selection(selection)
@ -76,6 +73,7 @@ def migrate(session, selection: str):
failed_imports = [] failed_imports = []
for dir in nextcloud_dir.iterdir(): for dir in nextcloud_dir.iterdir():
if dir.is_dir(): if dir.is_dir():
try: try:
recipe = import_recipes(dir) recipe = import_recipes(dir)
recipe.save_to_db(session) recipe.save_to_db(session)

View file

@ -1,8 +1,7 @@
from typing import List, Optional from typing import List, Optional
from db.database import db from db.database import db
from db.db_setup import sql_exists from db.db_setup import create_session, generate_session, sql_exists
from db.db_setup import create_session, generate_session
from pydantic import BaseModel from pydantic import BaseModel
from sqlalchemy.orm.session import Session from sqlalchemy.orm.session import Session
from utils.logger import logger from utils.logger import logger
@ -47,8 +46,8 @@ class SiteSettings(BaseModel):
return cls(**document) return cls(**document)
def update(self): def update(self, session: Session):
db.settings.update("main", new_data=self.dict()) db.settings.update(session, "main", new_data=self.dict())
class Colors(BaseModel): class Colors(BaseModel):

View file

@ -1,67 +1,78 @@
import json import json
import pytest
from tests.test_routes.utils.routes_data import recipe_test_data from tests.test_routes.utils.routes_data import recipe_test_data
def cleanup(api_client): def get_meal_plan_template(first=None, second=None):
api_client.delete(f"/api/recipe/{recipe_test_data[0].expected_slug}/delete/") return {
api_client.delete(f"/api/recipe/{recipe_test_data[1].expected_slug}/delete/") "startDate": "2021-01-18",
"endDate": "2021-01-19",
"meals": [
{
"slug": first,
"date": "2021-1-17",
"dateText": "Monday, January 18, 2021",
},
{
"slug": second,
"date": "2021-1-18",
"dateText": "Tueday, January 19, 2021",
},
],
}
meal_plan = { @pytest.fixture
"startDate": "2021-01-18", def slug_1(api_client):
"endDate": "2021-01-19", # Slug 1
"meals": [
{
"slug": None,
"date": "2021-1-17",
"dateText": "Monday, January 18, 2021",
},
{
"slug": None,
"date": "2021-1-18",
"dateText": "Tueday, January 19, 2021",
},
],
}
def test_create_mealplan(api_client):
slug_1 = api_client.post( slug_1 = api_client.post(
"/api/recipe/create-url/", json={"url": recipe_test_data[0].url} "/api/recipe/create-url/", json={"url": recipe_test_data[0].url}
) )
slug_1 = json.loads(slug_1.content)
yield slug_1
api_client.delete(f"/api/recipe/{recipe_test_data[1].expected_slug}/delete/")
@pytest.fixture
def slug_2(api_client):
# Slug 2
slug_2 = api_client.post( slug_2 = api_client.post(
"/api/recipe/create-url/", json={"url": recipe_test_data[1].url} "/api/recipe/create-url/", json={"url": recipe_test_data[1].url}
) )
slug_2 = json.loads(slug_2.content)
meal_plan["meals"][0]["slug"] = json.loads(slug_1.content) yield slug_2
meal_plan["meals"][1]["slug"] = json.loads(slug_2.content)
api_client.delete(f"/api/recipe/{recipe_test_data[0].expected_slug}/delete/")
def test_create_mealplan(api_client, slug_1, slug_2):
meal_plan = get_meal_plan_template()
meal_plan["meals"][0]["slug"] = slug_1
meal_plan["meals"][1]["slug"] = slug_2
response = api_client.post("/api/meal-plan/create/", json=meal_plan) response = api_client.post("/api/meal-plan/create/", json=meal_plan)
assert response.status_code == 200 assert response.status_code == 200
def test_read_mealplan(api_client): def test_read_mealplan(api_client, slug_1, slug_2):
response = api_client.get("/api/meal-plan/all/") response = api_client.get("/api/meal-plan/all/")
assert response.status_code == 200 assert response.status_code == 200
meal_plan = get_meal_plan_template(slug_1, slug_2)
new_meal_plan = json.loads(response.text) new_meal_plan = json.loads(response.text)
meals = new_meal_plan[0]["meals"] meals = new_meal_plan[0]["meals"]
assert meals[0]["slug"] == meal_plan["meals"][0]["slug"] assert meals[0]["slug"] == meal_plan["meals"][0]["slug"]
assert meals[1]["slug"] == meal_plan["meals"][1]["slug"] assert meals[1]["slug"] == meal_plan["meals"][1]["slug"]
cleanup(api_client)
def test_update_mealplan(api_client, slug_1, slug_2):
def test_update_mealplan(api_client):
slug_1 = api_client.post(
"/api/recipe/create-url/", json={"url": recipe_test_data[0].url}
)
slug_2 = api_client.post(
"/api/recipe/create-url/", json={"url": recipe_test_data[1].url}
)
response = api_client.get("/api/meal-plan/all/") response = api_client.get("/api/meal-plan/all/")
@ -70,8 +81,8 @@ def test_update_mealplan(api_client):
## Swap ## Swap
plan_uid = existing_mealplan.get("uid") plan_uid = existing_mealplan.get("uid")
existing_mealplan["meals"][0]["slug"] = json.loads(slug_2.content) existing_mealplan["meals"][0]["slug"] = slug_2
existing_mealplan["meals"][1]["slug"] = json.loads(slug_1.content) existing_mealplan["meals"][1]["slug"] = slug_1
response = api_client.post( response = api_client.post(
f"/api/meal-plan/{plan_uid}/update/", json=existing_mealplan f"/api/meal-plan/{plan_uid}/update/", json=existing_mealplan
@ -83,10 +94,8 @@ def test_update_mealplan(api_client):
existing_mealplan = json.loads(response.text) existing_mealplan = json.loads(response.text)
existing_mealplan = existing_mealplan[0] existing_mealplan = existing_mealplan[0]
assert existing_mealplan["meals"][0]["slug"] == json.loads(slug_2.content) assert existing_mealplan["meals"][0]["slug"] == slug_2
assert existing_mealplan["meals"][1]["slug"] == json.loads(slug_1.content) assert existing_mealplan["meals"][1]["slug"] == slug_1
cleanup(api_client)
def test_delete_mealplan(api_client): def test_delete_mealplan(api_client):

View file

@ -0,0 +1,74 @@
import json
import shutil
from pathlib import Path
from app_config import BASE_DIR, MIGRATION_DIR
from tests.test_services.test_migrations.test_nextcloud import NEXTCLOUD_DIR
TEST_DIR = BASE_DIR.joinpath("tests")
import pytest
#! Broken
# def test_import_chowdown_recipes(api_client):
# response = api_client.post(
# "/api/migration/chowdown/repo/",
# json={"url": "https://github.com/hay-kot/chowdown"},
# )
# assert response.status_code == 200
# test_slug = "banana-bread"
# response = api_client.get(f"/api/recipe/{test_slug}/")
# assert response.status_code == 200
# recipe = json.loads(response.content)
# assert recipe["slug"] == test_slug
@pytest.fixture(scope="session")
def nextcloud_zip():
zip = TEST_DIR.joinpath(
"test_services/test_migrations/data/nextcloud_recipes/nextcloud.zip"
)
zip_copy = TEST_DIR.joinpath(
"test_services/test_migrations/data/nextcloud_recipes/new_nextcloud.zip"
)
shutil.copy(zip, zip_copy)
return zip_copy
def test_upload_nextcloud_zip(api_client, nextcloud_zip):
response = api_client.post(
"/api/migration/upload/", files={"archive": nextcloud_zip.open("rb")}
)
assert response.status_code == 200
assert MIGRATION_DIR.joinpath(nextcloud_zip.name).is_file()
def test_import_nextcloud_directory(api_client, nextcloud_zip):
selection = nextcloud_zip.name
response = api_client.post(f"/api/migration/nextcloud/{selection}/import/")
assert response.status_code == 200
report = json.loads(response.content)
assert report["failed"] == []
expected_slug = "air-fryer-shrimp"
response = api_client.get(f"/api/recipe/{expected_slug}/")
assert response.status_code == 200
def test_delete_migration_data(api_client, nextcloud_zip):
selection = nextcloud_zip.name
response = api_client.delete(f"/api/migration/{selection}/delete/")
assert response.status_code == 200
assert not MIGRATION_DIR.joinpath(nextcloud_zip.name).is_file()

View file

@ -0,0 +1,108 @@
import json
import pytest
@pytest.fixture(scope="function")
def default_settings():
return {
"name": "main",
"webhooks": {"webhookTime": "00:00", "webhookURLs": [], "enabled": False},
}
@pytest.fixture(scope="session")
def default_theme(api_client):
default_theme = {
"name": "default",
"colors": {
"primary": "#E58325",
"accent": "#00457A",
"secondary": "#973542",
"success": "#5AB1BB",
"info": "#4990BA",
"warning": "#FF4081",
"error": "#EF5350",
},
}
api_client.post("/api/site-settings/themes/create/", json=default_theme)
return default_theme
@pytest.fixture(scope="session")
def new_theme():
return {
"name": "myTestTheme",
"colors": {
"primary": "#E58325",
"accent": "#00457A",
"secondary": "#973542",
"success": "#5AB1BB",
"info": "#4990BA",
"warning": "#FF4081",
"error": "#EF5350",
},
}
def test_default_settings(api_client, default_settings):
response = api_client.get("/api/site-settings/")
assert response.status_code == 200
assert json.loads(response.content) == default_settings
def test_update_settings(api_client, default_settings):
default_settings["webhooks"]["webhookURLs"] = [
"https://test1.url.com",
"https://test2.url.com",
"https://test3.url.com",
]
response = api_client.post("/api/site-settings/update/", json=default_settings)
assert response.status_code == 200
response = api_client.get("/api/site-settings/")
assert json.loads(response.content) == default_settings
def test_default_theme(api_client, default_theme):
response = api_client.get("/api/site-settings/themes/default/")
assert response.status_code == 200
assert json.loads(response.content) == default_theme
def test_create_theme(api_client, new_theme):
response = api_client.post("/api/site-settings/themes/create/", json=new_theme)
assert response.status_code == 200
response = api_client.get(f"/api/site-settings/themes/{new_theme.get('name')}/")
assert response.status_code == 200
assert json.loads(response.content) == new_theme
def test_read_all_themes(api_client, default_theme, new_theme):
response = api_client.get("/api/site-settings/themes/")
assert response.status_code == 200
assert json.loads(response.content) == [default_theme, new_theme]
def test_read_theme(api_client, default_theme, new_theme):
for theme in [default_theme, new_theme]:
response = api_client.get(f"/api/site-settings/themes/{theme.get('name')}/")
assert response.status_code == 200
assert json.loads(response.content) == theme
def test_delete_theme(api_client, default_theme, new_theme):
for theme in [default_theme, new_theme]:
response = api_client.delete(
f"/api/site-settings/themes/{theme.get('name')}/delete/"
)
assert response.status_code == 200

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

View file

@ -11,7 +11,7 @@ from services.migrations.nextcloud import (
from services.recipe_services import Recipe from services.recipe_services import Recipe
CWD = Path(__file__).parent CWD = Path(__file__).parent
NEXTCLOUD_DIR = CWD.parent.joinpath("data", "nextcloud_recipes") NEXTCLOUD_DIR = CWD.joinpath("data", "nextcloud_recipes")
TEMP_NEXTCLOUD = TEMP_DIR.joinpath("nextcloud") TEMP_NEXTCLOUD = TEMP_DIR.joinpath("nextcloud")

View file

@ -10,8 +10,8 @@ from services.scrape_services import (
) )
CWD = Path(__file__).parent CWD = Path(__file__).parent
RAW_RECIPE_DIR = CWD.parent.joinpath("data", "recipes-raw") RAW_RECIPE_DIR = CWD.joinpath("data", "recipes-raw")
RAW_HTML_DIR = CWD.parent.joinpath("data", "html-raw") RAW_HTML_DIR = CWD.joinpath("data", "html-raw")
# https://github.com/django/django/blob/stable/1.3.x/django/core/validators.py#L45 # https://github.com/django/django/blob/stable/1.3.x/django/core/validators.py#L45
url_validation_regex = re.compile( url_validation_regex = re.compile(

141
poetry.lock generated
View file

@ -24,26 +24,26 @@ python-versions = "*"
[[package]] [[package]]
name = "apscheduler" name = "apscheduler"
version = "3.6.3" version = "3.7.0"
description = "In-process task scheduler with Cron-like capabilities" description = "In-process task scheduler with Cron-like capabilities"
category = "main" category = "main"
optional = false optional = false
python-versions = "*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
[package.dependencies] [package.dependencies]
pytz = "*" pytz = "*"
six = ">=1.4.0" six = ">=1.4.0"
tzlocal = ">=1.2" tzlocal = ">=2.0,<3.0"
[package.extras] [package.extras]
asyncio = ["trollius"] asyncio = ["trollius"]
doc = ["sphinx", "sphinx-rtd-theme"] doc = ["sphinx", "sphinx-rtd-theme"]
gevent = ["gevent"] gevent = ["gevent"]
mongodb = ["pymongo (>=2.8)"] mongodb = ["pymongo (>=3.0)"]
redis = ["redis (>=3.0)"] redis = ["redis (>=3.0)"]
rethinkdb = ["rethinkdb (>=2.4.0)"] rethinkdb = ["rethinkdb (>=2.4.0)"]
sqlalchemy = ["sqlalchemy (>=0.8)"] sqlalchemy = ["sqlalchemy (>=0.8)"]
testing = ["pytest", "pytest-cov", "pytest-tornado5", "mock", "pytest-asyncio (<0.6)", "pytest-asyncio"] testing = ["pytest (<6)", "pytest-cov", "pytest-tornado5", "mock", "pytest-asyncio (<0.6)", "pytest-asyncio"]
tornado = ["tornado (>=4.3)"] tornado = ["tornado (>=4.3)"]
twisted = ["twisted"] twisted = ["twisted"]
zookeeper = ["kazoo"] zookeeper = ["kazoo"]
@ -152,6 +152,17 @@ category = "main"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]]
name = "coverage"
version = "5.3.1"
description = "Code coverage measurement for Python"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
[package.extras]
toml = ["toml"]
[[package]] [[package]]
name = "decorator" name = "decorator"
version = "4.4.2" version = "4.4.2"
@ -280,7 +291,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]] [[package]]
name = "importlib-resources" name = "importlib-resources"
version = "5.0.0" version = "5.1.0"
description = "Read resources from Python packages" description = "Read resources from Python packages"
category = "main" category = "main"
optional = false optional = false
@ -510,6 +521,21 @@ toml = "*"
[package.extras] [package.extras]
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
[[package]]
name = "pytest-cov"
version = "2.11.0"
description = "Pytest plugin for measuring coverage."
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[package.dependencies]
coverage = ">=5.2.1"
pytest = ">=4.6"
[package.extras]
testing = ["fields", "hunter", "process-tests (==2.0.2)", "six", "pytest-xdist", "virtualenv"]
[[package]] [[package]]
name = "python-dotenv" name = "python-dotenv"
version = "0.15.0" version = "0.15.0"
@ -556,11 +582,11 @@ python-versions = "*"
[[package]] [[package]]
name = "pyyaml" name = "pyyaml"
version = "5.3.1" version = "5.4"
description = "YAML parser and emitter for Python" description = "YAML parser and emitter for Python"
category = "main" category = "main"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
[[package]] [[package]]
name = "rdflib" name = "rdflib"
@ -835,7 +861,7 @@ python-versions = "*"
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.8" python-versions = "^3.8"
content-hash = "49f7f72b21beae20519bf5c1e86ab21391bbaa7c5fd47d455ee898d86b7d6ee0" content-hash = "115f5c8741bf1820e1b1ee8175616ea9f50f906803eac43a24bf259a5507e5d1"
[metadata.files] [metadata.files]
aiofiles = [ aiofiles = [
@ -851,8 +877,8 @@ appdirs = [
{file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
] ]
apscheduler = [ apscheduler = [
{file = "APScheduler-3.6.3-py2.py3-none-any.whl", hash = "sha256:e8b1ecdb4c7cb2818913f766d5898183c7cb8936680710a4d3a966e02262e526"}, {file = "APScheduler-3.7.0-py2.py3-none-any.whl", hash = "sha256:c06cc796d5bb9eb3c4f77727f6223476eb67749e7eea074d1587550702a7fbe3"},
{file = "APScheduler-3.6.3.tar.gz", hash = "sha256:3bb5229eed6fbbdafc13ce962712ae66e175aa214c69bed35a06bffcf0c5e244"}, {file = "APScheduler-3.7.0.tar.gz", hash = "sha256:1cab7f2521e107d07127b042155b632b7a1cd5e02c34be5a28ff62f77c900c6a"},
] ]
astroid = [ astroid = [
{file = "astroid-2.4.2-py3-none-any.whl", hash = "sha256:bc58d83eb610252fd8de6363e39d4f1d0619c894b0ed24603b881c02e64c7386"}, {file = "astroid-2.4.2-py3-none-any.whl", hash = "sha256:bc58d83eb610252fd8de6363e39d4f1d0619c894b0ed24603b881c02e64c7386"},
@ -890,6 +916,57 @@ colorama = [
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
{file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
] ]
coverage = [
{file = "coverage-5.3.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:fabeeb121735d47d8eab8671b6b031ce08514c86b7ad8f7d5490a7b6dcd6267d"},
{file = "coverage-5.3.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:7e4d159021c2029b958b2363abec4a11db0ce8cd43abb0d9ce44284cb97217e7"},
{file = "coverage-5.3.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:378ac77af41350a8c6b8801a66021b52da8a05fd77e578b7380e876c0ce4f528"},
{file = "coverage-5.3.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:e448f56cfeae7b1b3b5bcd99bb377cde7c4eb1970a525c770720a352bc4c8044"},
{file = "coverage-5.3.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:cc44e3545d908ecf3e5773266c487ad1877be718d9dc65fc7eb6e7d14960985b"},
{file = "coverage-5.3.1-cp27-cp27m-win32.whl", hash = "sha256:08b3ba72bd981531fd557f67beee376d6700fba183b167857038997ba30dd297"},
{file = "coverage-5.3.1-cp27-cp27m-win_amd64.whl", hash = "sha256:8dacc4073c359f40fcf73aede8428c35f84639baad7e1b46fce5ab7a8a7be4bb"},
{file = "coverage-5.3.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ee2f1d1c223c3d2c24e3afbb2dd38be3f03b1a8d6a83ee3d9eb8c36a52bee899"},
{file = "coverage-5.3.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:9a9d4ff06804920388aab69c5ea8a77525cf165356db70131616acd269e19b36"},
{file = "coverage-5.3.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:782a5c7df9f91979a7a21792e09b34a658058896628217ae6362088b123c8500"},
{file = "coverage-5.3.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:fda29412a66099af6d6de0baa6bd7c52674de177ec2ad2630ca264142d69c6c7"},
{file = "coverage-5.3.1-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:f2c6888eada180814b8583c3e793f3f343a692fc802546eed45f40a001b1169f"},
{file = "coverage-5.3.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:8f33d1156241c43755137288dea619105477961cfa7e47f48dbf96bc2c30720b"},
{file = "coverage-5.3.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b239711e774c8eb910e9b1ac719f02f5ae4bf35fa0420f438cdc3a7e4e7dd6ec"},
{file = "coverage-5.3.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:f54de00baf200b4539a5a092a759f000b5f45fd226d6d25a76b0dff71177a714"},
{file = "coverage-5.3.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:be0416074d7f253865bb67630cf7210cbc14eb05f4099cc0f82430135aaa7a3b"},
{file = "coverage-5.3.1-cp35-cp35m-win32.whl", hash = "sha256:c46643970dff9f5c976c6512fd35768c4a3819f01f61169d8cdac3f9290903b7"},
{file = "coverage-5.3.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9a4f66259bdd6964d8cf26142733c81fb562252db74ea367d9beb4f815478e72"},
{file = "coverage-5.3.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c6e5174f8ca585755988bc278c8bb5d02d9dc2e971591ef4a1baabdf2d99589b"},
{file = "coverage-5.3.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:3911c2ef96e5ddc748a3c8b4702c61986628bb719b8378bf1e4a6184bbd48fe4"},
{file = "coverage-5.3.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:c5ec71fd4a43b6d84ddb88c1df94572479d9a26ef3f150cef3dacefecf888105"},
{file = "coverage-5.3.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f51dbba78d68a44e99d484ca8c8f604f17e957c1ca09c3ebc2c7e3bbd9ba0448"},
{file = "coverage-5.3.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:a2070c5affdb3a5e751f24208c5c4f3d5f008fa04d28731416e023c93b275277"},
{file = "coverage-5.3.1-cp36-cp36m-win32.whl", hash = "sha256:535dc1e6e68fad5355f9984d5637c33badbdc987b0c0d303ee95a6c979c9516f"},
{file = "coverage-5.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:a4857f7e2bc6921dbd487c5c88b84f5633de3e7d416c4dc0bb70256775551a6c"},
{file = "coverage-5.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fac3c432851038b3e6afe086f777732bcf7f6ebbfd90951fa04ee53db6d0bcdd"},
{file = "coverage-5.3.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:cd556c79ad665faeae28020a0ab3bda6cd47d94bec48e36970719b0b86e4dcf4"},
{file = "coverage-5.3.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:a66ca3bdf21c653e47f726ca57f46ba7fc1f260ad99ba783acc3e58e3ebdb9ff"},
{file = "coverage-5.3.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:ab110c48bc3d97b4d19af41865e14531f300b482da21783fdaacd159251890e8"},
{file = "coverage-5.3.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:e52d3d95df81c8f6b2a1685aabffadf2d2d9ad97203a40f8d61e51b70f191e4e"},
{file = "coverage-5.3.1-cp37-cp37m-win32.whl", hash = "sha256:fa10fee7e32213f5c7b0d6428ea92e3a3fdd6d725590238a3f92c0de1c78b9d2"},
{file = "coverage-5.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ce6f3a147b4b1a8b09aae48517ae91139b1b010c5f36423fa2b866a8b23df879"},
{file = "coverage-5.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:93a280c9eb736a0dcca19296f3c30c720cb41a71b1f9e617f341f0a8e791a69b"},
{file = "coverage-5.3.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:3102bb2c206700a7d28181dbe04d66b30780cde1d1c02c5f3c165cf3d2489497"},
{file = "coverage-5.3.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8ffd4b204d7de77b5dd558cdff986a8274796a1e57813ed005b33fd97e29f059"},
{file = "coverage-5.3.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:a607ae05b6c96057ba86c811d9c43423f35e03874ffb03fbdcd45e0637e8b631"},
{file = "coverage-5.3.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:3a3c3f8863255f3c31db3889f8055989527173ef6192a283eb6f4db3c579d830"},
{file = "coverage-5.3.1-cp38-cp38-win32.whl", hash = "sha256:ff1330e8bc996570221b450e2d539134baa9465f5cb98aff0e0f73f34172e0ae"},
{file = "coverage-5.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:3498b27d8236057def41de3585f317abae235dd3a11d33e01736ffedb2ef8606"},
{file = "coverage-5.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ceb499d2b3d1d7b7ba23abe8bf26df5f06ba8c71127f188333dddcf356b4b63f"},
{file = "coverage-5.3.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:3b14b1da110ea50c8bcbadc3b82c3933974dbeea1832e814aab93ca1163cd4c1"},
{file = "coverage-5.3.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:76b2775dda7e78680d688daabcb485dc87cf5e3184a0b3e012e1d40e38527cc8"},
{file = "coverage-5.3.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:cef06fb382557f66d81d804230c11ab292d94b840b3cb7bf4450778377b592f4"},
{file = "coverage-5.3.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:6f61319e33222591f885c598e3e24f6a4be3533c1d70c19e0dc59e83a71ce27d"},
{file = "coverage-5.3.1-cp39-cp39-win32.whl", hash = "sha256:cc6f8246e74dd210d7e2b56c76ceaba1cc52b025cd75dbe96eb48791e0250e98"},
{file = "coverage-5.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:2757fa64e11ec12220968f65d086b7a29b6583d16e9a544c889b22ba98555ef1"},
{file = "coverage-5.3.1-pp36-none-any.whl", hash = "sha256:723d22d324e7997a651478e9c5a3120a0ecbc9a7e94071f7e1954562a8806cf3"},
{file = "coverage-5.3.1-pp37-none-any.whl", hash = "sha256:c89b558f8a9a5a6f2cfc923c304d49f0ce629c3bd85cb442ca258ec20366394c"},
{file = "coverage-5.3.1.tar.gz", hash = "sha256:38f16b1317b8dd82df67ed5daa5f5e7c959e46579840d77a67a4ceb9cef0a50b"},
]
decorator = [ decorator = [
{file = "decorator-4.4.2-py2.py3-none-any.whl", hash = "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760"}, {file = "decorator-4.4.2-py2.py3-none-any.whl", hash = "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760"},
{file = "decorator-4.4.2.tar.gz", hash = "sha256:e3a62f0520172440ca0dcc823749319382e377f37f140a0b99ef45fecb84bfe7"}, {file = "decorator-4.4.2.tar.gz", hash = "sha256:e3a62f0520172440ca0dcc823749319382e377f37f140a0b99ef45fecb84bfe7"},
@ -941,8 +1018,8 @@ idna = [
{file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"},
] ]
importlib-resources = [ importlib-resources = [
{file = "importlib_resources-5.0.0-py3-none-any.whl", hash = "sha256:ea17df80a0ff04b5dbd3d96dbeab1842acfd1c6c902eaeb8c8858abf2720161e"}, {file = "importlib_resources-5.1.0-py3-none-any.whl", hash = "sha256:885b8eae589179f661c909d699a546cf10d83692553e34dca1bf5eb06f7f6217"},
{file = "importlib_resources-5.0.0.tar.gz", hash = "sha256:4743f090ed8946e713745ec0e660249ef9fb0b9843eacc5b5ff931d2fd5aa67f"}, {file = "importlib_resources-5.1.0.tar.gz", hash = "sha256:bfdad047bce441405a49cf8eb48ddce5e56c696e185f59147a8b79e75e9e6380"},
] ]
iniconfig = [ iniconfig = [
{file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
@ -1127,6 +1204,10 @@ pytest = [
{file = "pytest-6.2.1-py3-none-any.whl", hash = "sha256:1969f797a1a0dbd8ccf0fecc80262312729afea9c17f1d70ebf85c5e76c6f7c8"}, {file = "pytest-6.2.1-py3-none-any.whl", hash = "sha256:1969f797a1a0dbd8ccf0fecc80262312729afea9c17f1d70ebf85c5e76c6f7c8"},
{file = "pytest-6.2.1.tar.gz", hash = "sha256:66e419b1899bc27346cb2c993e12c5e5e8daba9073c1fbce33b9807abc95c306"}, {file = "pytest-6.2.1.tar.gz", hash = "sha256:66e419b1899bc27346cb2c993e12c5e5e8daba9073c1fbce33b9807abc95c306"},
] ]
pytest-cov = [
{file = "pytest-cov-2.11.0.tar.gz", hash = "sha256:e90e034cde61dacb1394639a33f449725c591025b182d69752c1dd0bfec639a7"},
{file = "pytest_cov-2.11.0-py2.py3-none-any.whl", hash = "sha256:626a8a6ab188656c4f84b67d22436d6c494699d917e567e0048dda6e7f59e028"},
]
python-dotenv = [ python-dotenv = [
{file = "python-dotenv-0.15.0.tar.gz", hash = "sha256:587825ed60b1711daea4832cf37524dfd404325b7db5e25ebe88c495c9f807a0"}, {file = "python-dotenv-0.15.0.tar.gz", hash = "sha256:587825ed60b1711daea4832cf37524dfd404325b7db5e25ebe88c495c9f807a0"},
{file = "python_dotenv-0.15.0-py2.py3-none-any.whl", hash = "sha256:0c8d1b80d1a1e91717ea7d526178e3882732420b03f08afea0406db6402e220e"}, {file = "python_dotenv-0.15.0-py2.py3-none-any.whl", hash = "sha256:0c8d1b80d1a1e91717ea7d526178e3882732420b03f08afea0406db6402e220e"},
@ -1142,19 +1223,27 @@ pytz = [
{file = "pytz-2020.5.tar.gz", hash = "sha256:180befebb1927b16f6b57101720075a984c019ac16b1b7575673bea42c6c3da5"}, {file = "pytz-2020.5.tar.gz", hash = "sha256:180befebb1927b16f6b57101720075a984c019ac16b1b7575673bea42c6c3da5"},
] ]
pyyaml = [ pyyaml = [
{file = "PyYAML-5.3.1-cp27-cp27m-win32.whl", hash = "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f"}, {file = "PyYAML-5.4-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:f7a21e3d99aa3095ef0553e7ceba36fb693998fbb1226f1392ce33681047465f"},
{file = "PyYAML-5.3.1-cp27-cp27m-win_amd64.whl", hash = "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76"}, {file = "PyYAML-5.4-cp27-cp27m-win32.whl", hash = "sha256:52bf0930903818e600ae6c2901f748bc4869c0c406056f679ab9614e5d21a166"},
{file = "PyYAML-5.3.1-cp35-cp35m-win32.whl", hash = "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2"}, {file = "PyYAML-5.4-cp27-cp27m-win_amd64.whl", hash = "sha256:a36a48a51e5471513a5aea920cdad84cbd56d70a5057cca3499a637496ea379c"},
{file = "PyYAML-5.3.1-cp35-cp35m-win_amd64.whl", hash = "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c"}, {file = "PyYAML-5.4-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:5e7ac4e0e79a53451dc2814f6876c2fa6f71452de1498bbe29c0b54b69a986f4"},
{file = "PyYAML-5.3.1-cp36-cp36m-win32.whl", hash = "sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2"}, {file = "PyYAML-5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cc552b6434b90d9dbed6a4f13339625dc466fd82597119897e9489c953acbc22"},
{file = "PyYAML-5.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648"}, {file = "PyYAML-5.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0dc9f2eb2e3c97640928dec63fd8dc1dd91e6b6ed236bd5ac00332b99b5c2ff9"},
{file = "PyYAML-5.3.1-cp37-cp37m-win32.whl", hash = "sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a"}, {file = "PyYAML-5.4-cp36-cp36m-win32.whl", hash = "sha256:5a3f345acff76cad4aa9cb171ee76c590f37394186325d53d1aa25318b0d4a09"},
{file = "PyYAML-5.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf"}, {file = "PyYAML-5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:f3790156c606299ff499ec44db422f66f05a7363b39eb9d5b064f17bd7d7c47b"},
{file = "PyYAML-5.3.1-cp38-cp38-win32.whl", hash = "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97"}, {file = "PyYAML-5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:124fd7c7bc1e95b1eafc60825f2daf67c73ce7b33f1194731240d24b0d1bf628"},
{file = "PyYAML-5.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee"}, {file = "PyYAML-5.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:8b818b6c5a920cbe4203b5a6b14256f0e5244338244560da89b7b0f1313ea4b6"},
{file = "PyYAML-5.3.1-cp39-cp39-win32.whl", hash = "sha256:ad9c67312c84def58f3c04504727ca879cb0013b2517c85a9a253f0cb6380c0a"}, {file = "PyYAML-5.4-cp37-cp37m-win32.whl", hash = "sha256:737bd70e454a284d456aa1fa71a0b429dd527bcbf52c5c33f7c8eee81ac16b89"},
{file = "PyYAML-5.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:6034f55dab5fea9e53f436aa68fa3ace2634918e8b5994d82f3621c04ff5ed2e"}, {file = "PyYAML-5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:7242790ab6c20316b8e7bb545be48d7ed36e26bbe279fd56f2c4a12510e60b4b"},
{file = "PyYAML-5.3.1.tar.gz", hash = "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d"}, {file = "PyYAML-5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cc547d3ead3754712223abb7b403f0a184e4c3eae18c9bb7fd15adef1597cc4b"},
{file = "PyYAML-5.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8635d53223b1f561b081ff4adecb828fd484b8efffe542edcfdff471997f7c39"},
{file = "PyYAML-5.4-cp38-cp38-win32.whl", hash = "sha256:26fcb33776857f4072601502d93e1a619f166c9c00befb52826e7b774efaa9db"},
{file = "PyYAML-5.4-cp38-cp38-win_amd64.whl", hash = "sha256:b2243dd033fd02c01212ad5c601dafb44fbb293065f430b0d3dbf03f3254d615"},
{file = "PyYAML-5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:31ba07c54ef4a897758563e3a0fcc60077698df10180abe4b8165d9895c00ebf"},
{file = "PyYAML-5.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:02c78d77281d8f8d07a255e57abdbf43b02257f59f50cc6b636937d68efa5dd0"},
{file = "PyYAML-5.4-cp39-cp39-win32.whl", hash = "sha256:fdc6b2cb4b19e431994f25a9160695cc59a4e861710cc6fc97161c5e845fc579"},
{file = "PyYAML-5.4-cp39-cp39-win_amd64.whl", hash = "sha256:8bf38641b4713d77da19e91f8b5296b832e4db87338d6aeffe422d42f1ca896d"},
{file = "PyYAML-5.4.tar.gz", hash = "sha256:3c49e39ac034fd64fd576d63bb4db53cda89b362768a67f07749d55f128ac18a"},
] ]
rdflib = [ rdflib = [
{file = "rdflib-5.0.0-py3-none-any.whl", hash = "sha256:88208ea971a87886d60ae2b1a4b2cdc263527af0454c422118d43fe64b357877"}, {file = "rdflib-5.0.0-py3-none-any.whl", hash = "sha256:88208ea971a87886d60ae2b1a4b2cdc263527af0454c422118d43fe64b357877"},

View file

@ -31,6 +31,7 @@ python-multipart = "^0.0.5"
pylint = "^2.6.0" pylint = "^2.6.0"
black = "^20.8b1" black = "^20.8b1"
pytest = "^6.2.1" pytest = "^6.2.1"
pytest-cov = "^2.11.0"
[build-system] [build-system]
requires = ["poetry-core>=1.0.0"] requires = ["poetry-core>=1.0.0"]