Add netwo API #8

Open
johan.le.baut wants to merge 13 commits from netwo into master
17 changed files with 4748 additions and 19 deletions

3
webapp/.gitignore vendored
View file

@ -1,3 +1,4 @@
__pycache__
/config.ini
.vscode
.vscode
node_modules

View file

@ -2,4 +2,7 @@
axione_ipe_path = /path/to/ipe.sqlite
axione_ipe_db_name = ipe
arcep_ipe_path = /path/to/ipe.sqlite
arcep_ipe_db_name = arcep
arcep_ipe_db_name = arcep
[NETWO]
aquilenet_fixed_recurring_price = 10.0
api_key =

3672
webapp/elig.json Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,56 @@
from apispec.ext.marshmallow import MarshmallowPlugin
from apispec_webframeworks.flask import FlaskPlugin
from flasgger import APISpec, Schema, Swagger, fields
from eligibility_api.elig_api_exceptions import SwaggerValidationException
def _swagger_validation_error_handler(err, data, _):
print("API swagger error 400")
raise SwaggerValidationException(err, data)
def start_swagger(flask_app):
"""
Creates swagger /apidocs endpoint and adds it to flask app
"""
flask_app.config["SWAGGER"] = {
"uiversion": 3,
"ui_params": {
"apisSorter": "alpha",
"operationsSorter": "alpha",
"tagsSorter": "alpha",
},
}
# Create an APISpec
spec = APISpec(
title="API éligibilité",
version="0.1.0",
openapi_version="2.0",
plugins=(
FlaskPlugin(),
MarshmallowPlugin(),
),
)
template = spec.to_flasgger(
flask_app,
definitions=[
# ContributionSchema,
# PredictConfigSchema,
# VersionSchema,
# PredictInputsSchema,
# ImplementedModelSchema,
# ApiErrorSchema,
# LoggingHealthCheckSchema,
],
)
Swagger(
flask_app,
template=template,
parse=True,
validation_error_handler=_swagger_validation_error_handler,
)

View file

@ -12,6 +12,29 @@ class ApiParamException(Exception):
self.description = description
class NetwoApiErrorException(Exception):
"""
Exception thrown if Netwo API
"""
def __init__(self, description: str, netwo_status_code: int):
self.netwo_status_code = netwo_status_code
self.name = "Error contacting Netwo API"
self.description = description
class SwaggerValidationException(Exception):
"""
Exception thrown if API misused
"""
def __init__(self, err, data):
self.code = 400
self.name = "Error from Swagger API validation"
self.description = str(err)
self.data = data
class FlaskExceptions:
"""
Manages flask custom exceptions
@ -37,3 +60,30 @@ class FlaskExceptions:
),
400,
)
@self.flask_app.errorhandler(NetwoApiErrorException)
def handle_exception(e):
return (
jsonify(
{
"netwo_status_code": e.netwo_status_code,
"name": e.name,
"description": e.description,
}
),
500,
)
@self.flask_app.errorhandler(SwaggerValidationException)
def handle_exception(e):
return (
jsonify(
{
"code": e.code,
"name": e.name,
"description": e.description,
"data": e.data,
}
),
400,
)

View file

@ -3,12 +3,14 @@ from flask import Flask, request
from coordinates import check_coordinates_args, adapt_coordinates_to_max_area
from eligibility_api.elig_api_exceptions import ApiParamException
from ipe_fetcher.axione import AXIONE_MAX_AREA, Axione
from netwo.netwo import Netwo, NetwooEligibility
class EligibilityApiRoutes:
def __init__(self, flask_app: Flask, axione_ipe: Axione):
def __init__(self, flask_app: Flask, axione_ipe: Axione, netwo: Netwo):
self.flask_app = flask_app
self.axione_ipe = axione_ipe
self.netwo = netwo
def add_routes(self):
@self.flask_app.route("/eligibilite/axione", methods=["GET"])
@ -33,3 +35,90 @@ class EligibilityApiRoutes:
raise ApiParamException(
"You need to specify path parameters 'swx' 'swy' 'nex' 'ney'"
)
@self.flask_app.route("/eligibilite/netwo", methods=["GET"])
def get_netwo_eligibility():
"""
Intérroge l'éligibilité Netwo
---
tags:
- API
description: |
Déclenche une recherche d'éligibilité chez Netwo:
- soit par une ref d'immeuble
- soit par les coordonnées d'un immeuble
La recherche est longue, l'API renvoie un event stream qui renvoie un statut toutes les secondes
Il est possible de retrouver les résultats d'une éligibilité via son ID.
Par défaut on renvoie uniquement les offres ftth, il est possible via ftto=true d'ajouter la ftto
parameters:
- in: query
name: ftto
required: false
schema:
type: boolean
nullable: true
allowEmptyValue: true
description: |
Si 'ftto' set alors on rajoutera les résultats FTTO à la recherche
- in: query
name: timeout_sec
required: false
schema:
type: int
nullable: false
allowEmptyValue: false
description: |
Timeout au bout du quel on retourne les offres trouvées même si la recherche n'est pas terminée
responses:
200:
description: Retourne le statut d'éligibilité et d'éventuelles offres
schema:
$ref: '#/definitions/Contribution'
examples:
application/json:
400:
description: Bad inputs
schema:
$ref: '#/definitions/ApiError'
examples:
application/json:
code: 400
name: Bad input parameter
description: Bad json format
500:
description: Erreur lors d'un appel à l'API de Netwo
schema:
$ref: '#/definitions/ApiError'
examples:
application/json:
netwo_status_code: 404
name: Error contacting Netwo API
description: ID not found
"""
args = request.args
ref_imb = args.get("ref_imb")
elig_id = args.get("id")
timeout_sec = None
search_ftto = args.get("ftto") is not None
imb_info = self.netwo.get_netwo_imb_coordinates(ref_imb)
if elig_id:
elig_offers = self.netwo.get_netwo_eligibility_results(
elig_id, search_ftto
)
return NetwooEligibility(
imb_info=imb_info,
eligOffers=elig_offers,
eligDone=True,
elig_id=elig_id,
)
if args.get("timeout_sec"):
try:
timeout_sec = int(args.get("timeout_sec"))
except ValueError:
raise ApiParamException("timeout_sec param must be an integer")
return self.netwo.start_netwo_eligibility(
imb_info, search_ftto, timeout_sec
)

View file

@ -4,10 +4,12 @@ from typing import TypedDict
from flask import Flask, request, render_template, redirect
from eligibility_api.api_doc import start_swagger
from eligibility_api.elig_api_exceptions import FlaskExceptions
from eligibility_api.elig_api_routes import EligibilityApiRoutes
from ipe_fetcher import Liazo, Axione, Arcep, AreaCoordinates
from coordinates import adapt_coordinates_to_max_area, check_coordinates_args
from netwo.netwo import Netwo
LIAZO_MAX_X_INTERVAL = 0.0022
LIAZO_MAX_Y_INTERVAL = 0.0011
@ -19,6 +21,8 @@ class Config(TypedDict):
axione_ipe_db_name: str
arcep_ipe_path: str
arcep_ipe_db_name: str
netwo_api_key: str
netwo_aquilenet_fixed_recurring_price: float
def parseConfig() -> Config:
@ -31,6 +35,10 @@ def parseConfig() -> Config:
"axione_ipe_db_name": cfg.get("DB", "axione_ipe_db_name"),
"arcep_ipe_path": cfg.get("DB", "arcep_ipe_path"),
"arcep_ipe_db_name": cfg.get("DB", "arcep_ipe_db_name"),
"netwo_api_key": cfg.get("NETWO", "api_key"),
"netwo_aquilenet_fixed_recurring_price": float(
cfg.get("NETWO", "aquilenet_fixed_recurring_price") or 0.00
),
}
@ -40,7 +48,10 @@ cfg: Config = parseConfig()
axione = Axione(cfg.get("axione_ipe_path"), cfg.get("axione_ipe_db_name"))
arcep = Arcep(cfg.get("arcep_ipe_path"), cfg.get("arcep_ipe_db_name"))
liazo = Liazo()
elig_api_routes = EligibilityApiRoutes(app, axione)
netwo = Netwo(
cfg.get("netwo_api_key"), cfg.get("netwo_aquilenet_fixed_recurring_price")
)
elig_api_routes = EligibilityApiRoutes(app, axione, netwo)
elig_api_routes.add_routes()
elig_api_exceptions = FlaskExceptions(app)
elig_api_exceptions.add_exceptions()
@ -53,7 +64,6 @@ def getMap():
@app.route("/eligdata", methods=["GET"])
def getEligData():
toto = 1
args = request.args
valid_args = True
processed_args = {}
@ -98,3 +108,6 @@ def testFtth():
liazoOk = args["liazo"]
pto_url = f"https://tools.aquilenet.fr/cgi-bin/recherchepto.cgi?refimmeuble={idImm}&cp={codePostal}&axione={axioneOk}&liazo={liazoOk}"
return redirect(pto_url)
# start_swagger(app)

0
webapp/netwo/__init__.py Normal file
View file

294
webapp/netwo/netwo.py Normal file
View file

@ -0,0 +1,294 @@
import json
import time
from urllib.parse import quote
import requests
from flask import Response
from typing_extensions import NotRequired, TypedDict
from eligibility_api.elig_api_exceptions import NetwoApiErrorException
NETWO_DEPLOYED_STATUS = "Deployed"
NETWO_NOT_FOUND_STATUS = "not_found"
TVA_INCREASE_COEFF = 1.2
class NetwooEligibility(TypedDict):
imb_info: NotRequired[dict]
eligDone: NotRequired[bool]
eligId: NotRequired[str]
nbOperatorsOk: NotRequired[int]
nbOperatorsErrors: NotRequired[int]
nbOperatorsPending: NotRequired[int]
totalOperators: NotRequired[int]
timeoutSec: NotRequired[int]
timeoutReached: NotRequired[bool]
eligOffers: NotRequired[dict]
class Netwo:
def __init__(self, netwo_api_key: str, aquilenet_fixed_recurring_price: float):
self.netwo_api_headers = {
"x-actor-slug": "aquilenet",
"x-api-key": netwo_api_key,
"Accept": "application/json",
}
self.aquilenet_fixed_recurring_price = aquilenet_fixed_recurring_price
def get_netwo_imb_coordinates(self, ref_imb: str) -> dict:
"""
:param ref_imb: ARCEP ref of immeuble
:return:
(elig_status: FAIEligibilityStatus, imb_lat: str, imb_lng: str)
"""
ref_imm_clean = quote(ref_imb, safe="")
response = requests.get(
f"https://api.netwo.io/api/v1/imb/{ref_imm_clean}",
headers=self.netwo_api_headers,
)
status_code = response.status_code
if status_code != 200 or not response.json():
return {"imb_status": NETWO_NOT_FOUND_STATUS, "imb_id": ref_imb}
imb_payload = response.json()
return imb_payload
def _get_netwo_product_entities_details(self, elig_id: str, product_id: str):
response = requests.get(
f"https://api.netwo.io/api/v1/eligibility/{elig_id}/details/{product_id}",
headers=self.netwo_api_headers,
)
status_code = response.status_code
if status_code != 200 or not response.json():
print(
f"Error: could not get details for elig_id {elig_id} and product id {product_id}"
)
return {}
details = response.json()
return details.get("entities") or []
def _filter_netwo_raw_elig_results(
self,
elig_id: str,
raw_elig: dict,
search_ftto: bool,
netwo_offers: list,
processed_products: list,
) -> list:
inf_search = ["ftth"]
if search_ftto:
inf_search.append("ftto")
for r in raw_elig.get("results"):
inf_type = r.get("infrastructure_type")
if inf_type not in inf_search:
continue
product_id = r.get("product_id")
if product_id in processed_products:
continue
processed_products.append(product_id)
prod_entities = self._get_netwo_product_entities_details(
elig_id, product_id
)
operator = r.get("infrastructure_operator")
product = r.get("product_name")
for offer in r.get("entities"):
entity_id = offer.get("entity_id")
offer_name = offer.get("name")
debit = offer.get("debit") or 0.0
access_fee = offer.get("access_fee") or 0.00
recurring_price = offer.get("recurring_price") or 0.00
commitment_duration = offer.get("commitment_duration") or 0
access_fee_ttc = round(
access_fee * TVA_INCREASE_COEFF,
)
total_recurring_price_ttc = round(
recurring_price * TVA_INCREASE_COEFF
+ self.aquilenet_fixed_recurring_price,
2,
)
offer_info = {
"entity_id": entity_id,
"product_id": product_id,
"product": f"{product} - {offer_name}",
"infrastructure_operator": operator,
"infrastructure_type": inf_type,
"debit": debit,
"access_fee": access_fee,
"access_fee_ttc": access_fee_ttc,
"recurring_price": recurring_price,
"total_recurring_price_ttc": total_recurring_price_ttc,
"commitment_duration": commitment_duration,
"per_month_price_one_year_ttc": round(
access_fee_ttc / 12 + total_recurring_price_ttc, 2
),
}
search_entity = [
i for i in prod_entities if i.get("entity_id") == entity_id
]
if search_entity:
entity_details = search_entity[0]
offer_info[
"broadband_network_gateway_protocol"
] = entity_details.get("broadband_network_gateway_protocol")
offer_info["debit_up_max"] = entity_details.get("debit_up_max")
offer_info["interface_type"] = entity_details.get("interface_type")
offer_info["tariff_zone"] = entity_details.get("tariff_zone")
offer_info["collection_region"] = entity_details.get(
"collection_region"
)
offer_info["delivery_protocol"] = entity_details.get(
"delivery_protocol"
)
offer_info["mtu"] = entity_details.get("mtu")
netwo_offers.append(offer_info)
sort_elig = sorted(
netwo_offers,
key=lambda x: x["per_month_price_one_year_ttc"],
reverse=False,
)
return sort_elig
@staticmethod
def _prepare_event_string(data: dict):
return "data: %s\n\n" % json.dumps(data)
def get_netwo_eligibility_results(
self, elig_id: str, search_ftto: bool, netwo_offers, processed_products
):
response = requests.get(
f"https://api.netwo.io/api/v1/eligibility/{elig_id}",
headers=self.netwo_api_headers,
)
status_code = response.status_code
if status_code != 200:
raise NetwoApiErrorException(
f"Netwo API: Could not get eligibility results for ID {elig_id}",
status_code,
)
return self._filter_netwo_raw_elig_results(
elig_id, response.json(), search_ftto, netwo_offers, processed_products
)
def start_netwo_eligibility(
self,
imb_info: str,
search_ftto: bool,
timeout_sec: None,
):
def event_stream():
netwo_elig = NetwooEligibility(
eligId="",
eligDone=False,
nbOperatorsOk=0,
nbOperatorsErrors=0,
nbOperatorsPending=0,
totalOperators=0,
eligStatus={},
timeoutReached=False,
timeoutSec=timeout_sec,
eligOffers=[],
imb_info=imb_info,
)
if imb_info.get("imb_status") == NETWO_NOT_FOUND_STATUS:
netwo_elig["eligDone"] = True
yield "data: %s\n\n" % json.dumps(netwo_elig)
return
json_data = {
"latitude": str(imb_info.get("lat")),
"longitude": str(imb_info.get("lng")),
}
response = requests.post(
"https://api.netwo.io/api/v1/eligibility/preselect",
headers=self.netwo_api_headers,
json=json_data,
)
status_code = response.status_code
if status_code != 200:
print(f"raise preselect except {response.text}")
raise NetwoApiErrorException(
"Netwo API eligibility preselect step failed", status_code
)
resp = response.json()
default = resp.get("default")
default["offer_type"] = "enterprise"
default["market"] = "service_operator"
default["ftth_payload"] = {
"imb_ref": imb_info.get("imb_id"),
"pm_ref": imb_info.get("pm_id"),
}
response = requests.post(
"https://api.netwo.io/api/v1/eligibility",
headers=self.netwo_api_headers,
json=default,
)
status_code = response.status_code
if status_code != 201:
print(f"Error Could not start Netwo eligibility with body {default}")
raise NetwoApiErrorException(
"Netwo API: failed to start eligibility", status_code
)
id_elig = response.json().get("id")
netwo_elig["eligId"] = id_elig
is_done = False
timeout = None
if timeout_sec:
timeout = time.time() + timeout_sec
netwo_offers = []
processed_products = []
while is_done is False:
response = requests.get(
f"https://api.netwo.io/api/v1/eligibility/{id_elig}/status",
headers=self.netwo_api_headers,
)
status_code = response.status_code
if status_code != 200:
print("raise elig status except")
raise NetwoApiErrorException(
f"Netwo API: Could not get eligibility status for ID {id_elig}",
status_code,
)
status_res = response.json()
netwo_elig["eligStatus"] = status_res
netwo_elig["nbOperatorsOk"] = len(status_res.get("successes", []) or [])
netwo_elig["nbOperatorsErrors"] = len(
status_res.get("errors", []) or []
)
netwo_elig["nbOperatorsPending"] = len(
status_res.get("pending", []) or []
)
netwo_elig["totalOperators"] = (
netwo_elig["nbOperatorsOk"]
+ netwo_elig["nbOperatorsErrors"]
+ netwo_elig["nbOperatorsPending"]
)
netwo_offers = self.get_netwo_eligibility_results(
id_elig,
search_ftto,
netwo_offers,
processed_products,
)
netwo_elig["eligOffers"] = netwo_offers
if timeout and time.time() > timeout:
netwo_elig["timeoutReached"] = True
yield self._prepare_event_string(netwo_elig)
break
else:
yield self._prepare_event_string(netwo_elig)
if netwo_elig["nbOperatorsPending"] > 0:
time.sleep(0.6)
else:
is_done = True
netwo_elig["eligOffers"] = self.get_netwo_eligibility_results(
id_elig, search_ftto, netwo_offers, processed_products
)
netwo_elig["eligDone"] = True
yield self._prepare_event_string(netwo_elig)
return Response(event_stream(), mimetype="text/event-stream")

446
webapp/poetry.lock generated
View file

@ -1,3 +1,66 @@
[[package]]
name = "aniso8601"
version = "9.0.1"
description = "A library for parsing ISO 8601 strings."
category = "main"
optional = false
python-versions = "*"
[package.extras]
dev = ["black", "coverage", "isort", "pre-commit", "pyenchant", "pylint"]
[[package]]
name = "apispec"
version = "6.1.0"
description = "A pluggable API specification generator. Currently supports the OpenAPI Specification (f.k.a. the Swagger specification)."
category = "main"
optional = false
python-versions = ">=3.7"
[package.dependencies]
packaging = ">=21.3"
PyYAML = {version = ">=3.10", optional = true, markers = "extra == \"yaml\""}
[package.extras]
dev = ["PyYAML (>=3.10)", "flake8 (==5.0.4)", "flake8-bugbear (==22.9.23)", "marshmallow (>=3.13.0)", "mypy (==0.982)", "openapi-spec-validator (<0.5)", "prance[osv] (>=0.11)", "pre-commit (>=2.4,<3.0)", "pytest", "tox", "types-PyYAML"]
docs = ["marshmallow (>=3.13.0)", "pyyaml (==6.0)", "sphinx (==5.2.3)", "sphinx-issues (==3.0.1)", "sphinx-rtd-theme (==1.0.0)"]
lint = ["flake8 (==5.0.4)", "flake8-bugbear (==22.9.23)", "mypy (==0.982)", "pre-commit (>=2.4,<3.0)", "types-PyYAML"]
marshmallow = ["marshmallow (>=3.18.0)"]
tests = ["PyYAML (>=3.10)", "marshmallow (>=3.13.0)", "openapi-spec-validator (<0.5)", "prance[osv] (>=0.11)", "pytest"]
validation = ["openapi-spec-validator (<0.5)", "prance[osv] (>=0.11)"]
yaml = ["PyYAML (>=3.10)"]
[[package]]
name = "apispec-webframeworks"
version = "0.5.2"
description = "Web framework plugins for apispec."
category = "main"
optional = false
python-versions = ">=3.6"
[package.dependencies]
apispec = {version = ">=2.0.0", extras = ["yaml"]}
[package.extras]
dev = ["Flask (==1.1.1)", "bottle (==0.12.17)", "flake8 (==3.7.9)", "flake8-bugbear (==19.8.0)", "mock", "pre-commit (>=1.18,<2.0)", "pytest", "tornado", "tox"]
lint = ["flake8 (==3.7.9)", "flake8-bugbear (==19.8.0)", "pre-commit (>=1.18,<2.0)"]
tests = ["Flask (==1.1.1)", "bottle (==0.12.17)", "mock", "pytest", "tornado"]
[[package]]
name = "attrs"
version = "22.2.0"
description = "Classes Without Boilerplate"
category = "main"
optional = false
python-versions = ">=3.6"
[package.extras]
cov = ["attrs[tests]", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"]
dev = ["attrs[docs,tests]"]
docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope.interface"]
tests = ["attrs[tests-no-zope]", "zope.interface"]
tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"]
[[package]]
name = "black"
version = "23.1.0"
@ -21,6 +84,22 @@ d = ["aiohttp (>=3.7.4)"]
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
uvloop = ["uvloop (>=0.15.2)"]
[[package]]
name = "certifi"
version = "2022.12.7"
description = "Python package for providing Mozilla's CA Bundle."
category = "main"
optional = false
python-versions = ">=3.6"
[[package]]
name = "charset-normalizer"
version = "3.0.1"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
category = "main"
optional = false
python-versions = "*"
[[package]]
name = "click"
version = "8.1.3"
@ -40,6 +119,21 @@ category = "main"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
[[package]]
name = "flasgger"
version = "0.9.5"
description = "Extract swagger specs from your flask project"
category = "main"
optional = false
python-versions = "*"
[package.dependencies]
Flask = ">=0.10"
jsonschema = ">=3.0.1"
mistune = "*"
PyYAML = ">=3.0"
six = ">=1.10.0"
[[package]]
name = "flask"
version = "2.2.2"
@ -59,6 +153,23 @@ Werkzeug = ">=2.2.2"
async = ["asgiref (>=3.2)"]
dotenv = ["python-dotenv"]
[[package]]
name = "flask-restful"
version = "0.3.9"
description = "Simple framework for creating REST APIs"
category = "main"
optional = false
python-versions = "*"
[package.dependencies]
aniso8601 = ">=0.82"
Flask = ">=0.8"
pytz = "*"
six = ">=1.3.0"
[package.extras]
docs = ["sphinx"]
[[package]]
name = "gunicorn"
version = "20.1.0"
@ -76,6 +187,14 @@ gevent = ["gevent (>=1.4.0)"]
setproctitle = ["setproctitle"]
tornado = ["tornado (>=0.2)"]
[[package]]
name = "idna"
version = "3.4"
description = "Internationalized Domain Names in Applications (IDNA)"
category = "main"
optional = false
python-versions = ">=3.5"
[[package]]
name = "importlib-metadata"
version = "5.1.0"
@ -114,6 +233,22 @@ MarkupSafe = ">=2.0"
[package.extras]
i18n = ["Babel (>=2.7)"]
[[package]]
name = "jsonschema"
version = "4.17.3"
description = "An implementation of JSON Schema validation for Python"
category = "main"
optional = false
python-versions = ">=3.7"
[package.dependencies]
attrs = ">=17.4.0"
pyrsistent = ">=0.14.0,<0.17.0 || >0.17.0,<0.17.1 || >0.17.1,<0.17.2 || >0.17.2"
[package.extras]
format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"]
format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"]
[[package]]
name = "markupsafe"
version = "2.1.1"
@ -122,6 +257,31 @@ category = "main"
optional = false
python-versions = ">=3.7"
[[package]]
name = "marshmallow"
version = "3.19.0"
description = "A lightweight library for converting complex datatypes to and from native Python datatypes."
category = "main"
optional = false
python-versions = ">=3.7"
[package.dependencies]
packaging = ">=17.0"
[package.extras]
dev = ["flake8 (==5.0.4)", "flake8-bugbear (==22.10.25)", "mypy (==0.990)", "pre-commit (>=2.4,<3.0)", "pytest", "pytz", "simplejson", "tox"]
docs = ["alabaster (==0.7.12)", "autodocsumm (==0.2.9)", "sphinx (==5.3.0)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"]
lint = ["flake8 (==5.0.4)", "flake8-bugbear (==22.10.25)", "mypy (==0.990)", "pre-commit (>=2.4,<3.0)"]
tests = ["pytest", "pytz", "simplejson"]
[[package]]
name = "mistune"
version = "2.0.5"
description = "A sane Markdown parser with useful plugins and renderers"
category = "main"
optional = false
python-versions = "*"
[[package]]
name = "mypy-extensions"
version = "1.0.0"
@ -166,6 +326,48 @@ python-versions = ">=3.7"
docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"]
test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"]
[[package]]
name = "pyrsistent"
version = "0.19.3"
description = "Persistent/Functional/Immutable data structures"
category = "main"
optional = false
python-versions = ">=3.7"
[[package]]
name = "pytz"
version = "2022.7.1"
description = "World timezone definitions, modern and historical"
category = "main"
optional = false
python-versions = "*"
[[package]]
name = "pyyaml"
version = "6.0"
description = "YAML parser and emitter for Python"
category = "main"
optional = false
python-versions = ">=3.6"
[[package]]
name = "requests"
version = "2.28.2"
description = "Python HTTP for Humans."
category = "main"
optional = false
python-versions = ">=3.7, <4"
[package.dependencies]
certifi = ">=2017.4.17"
charset-normalizer = ">=2,<4"
idna = ">=2.5,<4"
urllib3 = ">=1.21.1,<1.27"
[package.extras]
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
[[package]]
name = "setuptools"
version = "65.6.3"
@ -179,6 +381,14 @@ docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-g
testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
[[package]]
name = "six"
version = "1.16.0"
description = "Python 2 and 3 compatibility utilities"
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]]
name = "tomli"
version = "2.0.1"
@ -195,6 +405,19 @@ category = "main"
optional = false
python-versions = ">=3.7"
[[package]]
name = "urllib3"
version = "1.26.14"
description = "HTTP library with thread-safe connection pooling, file post, and more."
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
[package.extras]
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
[[package]]
name = "werkzeug"
version = "2.2.2"
@ -224,9 +447,25 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools"
[metadata]
lock-version = "1.1"
python-versions = "^3.9"
content-hash = "b6b11d10f751f57c01e19f8690478cc9fa9edb9cd923aabf5d7393e4f8a88a32"
content-hash = "808253c094a03d4591f9504fee2876cfe5efe4b63ca89b47813fbc63e8cb7de7"
[metadata.files]
aniso8601 = [
{file = "aniso8601-9.0.1-py2.py3-none-any.whl", hash = "sha256:1d2b7ef82963909e93c4f24ce48d4de9e66009a21bf1c1e1c85bdd0812fe412f"},
{file = "aniso8601-9.0.1.tar.gz", hash = "sha256:72e3117667eedf66951bb2d93f4296a56b94b078a8a95905a052611fb3f1b973"},
]
apispec = [
{file = "apispec-6.1.0-py3-none-any.whl", hash = "sha256:937d7f11be6e80cf6d0b66c12dbc29604435302b529b3a9bdb5e2dee192d2f17"},
{file = "apispec-6.1.0.tar.gz", hash = "sha256:881d3b90bfffded659bc0a4bf09eadeedfa256cd271726b1555d75af9e0a9a69"},
]
apispec-webframeworks = [
{file = "apispec-webframeworks-0.5.2.tar.gz", hash = "sha256:0db35b267914b3f8c562aca0261957dbcb4176f255eacc22520277010818dcf3"},
{file = "apispec_webframeworks-0.5.2-py2.py3-none-any.whl", hash = "sha256:482c563abbcc2a261439476cb3f1a7c7284cc997c322c574d48c111643e9c04e"},
]
attrs = [
{file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"},
{file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"},
]
black = [
{file = "black-23.1.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:b6a92a41ee34b883b359998f0c8e6eb8e99803aa8bf3123bf2b2e6fec505a221"},
{file = "black-23.1.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:57c18c5165c1dbe291d5306e53fb3988122890e57bd9b3dcb75f967f13411a26"},
@ -254,6 +493,100 @@ black = [
{file = "black-23.1.0-py3-none-any.whl", hash = "sha256:7a0f701d314cfa0896b9001df70a530eb2472babb76086344e688829efd97d32"},
{file = "black-23.1.0.tar.gz", hash = "sha256:b0bd97bea8903f5a2ba7219257a44e3f1f9d00073d6cc1add68f0beec69692ac"},
]
certifi = [
{file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"},
{file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"},
]
charset-normalizer = [
{file = "charset-normalizer-3.0.1.tar.gz", hash = "sha256:ebea339af930f8ca5d7a699b921106c6e29c617fe9606fa7baa043c1cdae326f"},
{file = "charset_normalizer-3.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88600c72ef7587fe1708fd242b385b6ed4b8904976d5da0893e31df8b3480cb6"},
{file = "charset_normalizer-3.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c75ffc45f25324e68ab238cb4b5c0a38cd1c3d7f1fb1f72b5541de469e2247db"},
{file = "charset_normalizer-3.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:db72b07027db150f468fbada4d85b3b2729a3db39178abf5c543b784c1254539"},
{file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62595ab75873d50d57323a91dd03e6966eb79c41fa834b7a1661ed043b2d404d"},
{file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ff6f3db31555657f3163b15a6b7c6938d08df7adbfc9dd13d9d19edad678f1e8"},
{file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:772b87914ff1152b92a197ef4ea40efe27a378606c39446ded52c8f80f79702e"},
{file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70990b9c51340e4044cfc394a81f614f3f90d41397104d226f21e66de668730d"},
{file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:292d5e8ba896bbfd6334b096e34bffb56161c81408d6d036a7dfa6929cff8783"},
{file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2edb64ee7bf1ed524a1da60cdcd2e1f6e2b4f66ef7c077680739f1641f62f555"},
{file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:31a9ddf4718d10ae04d9b18801bd776693487cbb57d74cc3458a7673f6f34639"},
{file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:44ba614de5361b3e5278e1241fda3dc1838deed864b50a10d7ce92983797fa76"},
{file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:12db3b2c533c23ab812c2b25934f60383361f8a376ae272665f8e48b88e8e1c6"},
{file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c512accbd6ff0270939b9ac214b84fb5ada5f0409c44298361b2f5e13f9aed9e"},
{file = "charset_normalizer-3.0.1-cp310-cp310-win32.whl", hash = "sha256:502218f52498a36d6bf5ea77081844017bf7982cdbe521ad85e64cabee1b608b"},
{file = "charset_normalizer-3.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:601f36512f9e28f029d9481bdaf8e89e5148ac5d89cffd3b05cd533eeb423b59"},
{file = "charset_normalizer-3.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0298eafff88c99982a4cf66ba2efa1128e4ddaca0b05eec4c456bbc7db691d8d"},
{file = "charset_normalizer-3.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a8d0fc946c784ff7f7c3742310cc8a57c5c6dc31631269876a88b809dbeff3d3"},
{file = "charset_normalizer-3.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:87701167f2a5c930b403e9756fab1d31d4d4da52856143b609e30a1ce7160f3c"},
{file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14e76c0f23218b8f46c4d87018ca2e441535aed3632ca134b10239dfb6dadd6b"},
{file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c0a590235ccd933d9892c627dec5bc7511ce6ad6c1011fdf5b11363022746c1"},
{file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c7fe7afa480e3e82eed58e0ca89f751cd14d767638e2550c77a92a9e749c317"},
{file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79909e27e8e4fcc9db4addea88aa63f6423ebb171db091fb4373e3312cb6d603"},
{file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ac7b6a045b814cf0c47f3623d21ebd88b3e8cf216a14790b455ea7ff0135d18"},
{file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:72966d1b297c741541ca8cf1223ff262a6febe52481af742036a0b296e35fa5a"},
{file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f9d0c5c045a3ca9bedfc35dca8526798eb91a07aa7a2c0fee134c6c6f321cbd7"},
{file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5995f0164fa7df59db4746112fec3f49c461dd6b31b841873443bdb077c13cfc"},
{file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4a8fcf28c05c1f6d7e177a9a46a1c52798bfe2ad80681d275b10dcf317deaf0b"},
{file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:761e8904c07ad053d285670f36dd94e1b6ab7f16ce62b9805c475b7aa1cffde6"},
{file = "charset_normalizer-3.0.1-cp311-cp311-win32.whl", hash = "sha256:71140351489970dfe5e60fc621ada3e0f41104a5eddaca47a7acb3c1b851d6d3"},
{file = "charset_normalizer-3.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:9ab77acb98eba3fd2a85cd160851816bfce6871d944d885febf012713f06659c"},
{file = "charset_normalizer-3.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:84c3990934bae40ea69a82034912ffe5a62c60bbf6ec5bc9691419641d7d5c9a"},
{file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74292fc76c905c0ef095fe11e188a32ebd03bc38f3f3e9bcb85e4e6db177b7ea"},
{file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c95a03c79bbe30eec3ec2b7f076074f4281526724c8685a42872974ef4d36b72"},
{file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c39b0e3eac288fedc2b43055cfc2ca7a60362d0e5e87a637beac5d801ef478"},
{file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df2c707231459e8a4028eabcd3cfc827befd635b3ef72eada84ab13b52e1574d"},
{file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93ad6d87ac18e2a90b0fe89df7c65263b9a99a0eb98f0a3d2e079f12a0735837"},
{file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:59e5686dd847347e55dffcc191a96622f016bc0ad89105e24c14e0d6305acbc6"},
{file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:cd6056167405314a4dc3c173943f11249fa0f1b204f8b51ed4bde1a9cd1834dc"},
{file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:083c8d17153ecb403e5e1eb76a7ef4babfc2c48d58899c98fcaa04833e7a2f9a"},
{file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:f5057856d21e7586765171eac8b9fc3f7d44ef39425f85dbcccb13b3ebea806c"},
{file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:7eb33a30d75562222b64f569c642ff3dc6689e09adda43a082208397f016c39a"},
{file = "charset_normalizer-3.0.1-cp36-cp36m-win32.whl", hash = "sha256:95dea361dd73757c6f1c0a1480ac499952c16ac83f7f5f4f84f0658a01b8ef41"},
{file = "charset_normalizer-3.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:eaa379fcd227ca235d04152ca6704c7cb55564116f8bc52545ff357628e10602"},
{file = "charset_normalizer-3.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3e45867f1f2ab0711d60c6c71746ac53537f1684baa699f4f668d4c6f6ce8e14"},
{file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cadaeaba78750d58d3cc6ac4d1fd867da6fc73c88156b7a3212a3cd4819d679d"},
{file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:911d8a40b2bef5b8bbae2e36a0b103f142ac53557ab421dc16ac4aafee6f53dc"},
{file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:503e65837c71b875ecdd733877d852adbc465bd82c768a067badd953bf1bc5a3"},
{file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a60332922359f920193b1d4826953c507a877b523b2395ad7bc716ddd386d866"},
{file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16a8663d6e281208d78806dbe14ee9903715361cf81f6d4309944e4d1e59ac5b"},
{file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a16418ecf1329f71df119e8a65f3aa68004a3f9383821edcb20f0702934d8087"},
{file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9d9153257a3f70d5f69edf2325357251ed20f772b12e593f3b3377b5f78e7ef8"},
{file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:02a51034802cbf38db3f89c66fb5d2ec57e6fe7ef2f4a44d070a593c3688667b"},
{file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:2e396d70bc4ef5325b72b593a72c8979999aa52fb8bcf03f701c1b03e1166918"},
{file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:11b53acf2411c3b09e6af37e4b9005cba376c872503c8f28218c7243582df45d"},
{file = "charset_normalizer-3.0.1-cp37-cp37m-win32.whl", hash = "sha256:0bf2dae5291758b6f84cf923bfaa285632816007db0330002fa1de38bfcb7154"},
{file = "charset_normalizer-3.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:2c03cc56021a4bd59be889c2b9257dae13bf55041a3372d3295416f86b295fb5"},
{file = "charset_normalizer-3.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:024e606be3ed92216e2b6952ed859d86b4cfa52cd5bc5f050e7dc28f9b43ec42"},
{file = "charset_normalizer-3.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4b0d02d7102dd0f997580b51edc4cebcf2ab6397a7edf89f1c73b586c614272c"},
{file = "charset_normalizer-3.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:358a7c4cb8ba9b46c453b1dd8d9e431452d5249072e4f56cfda3149f6ab1405e"},
{file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81d6741ab457d14fdedc215516665050f3822d3e56508921cc7239f8c8e66a58"},
{file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8b8af03d2e37866d023ad0ddea594edefc31e827fee64f8de5611a1dbc373174"},
{file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9cf4e8ad252f7c38dd1f676b46514f92dc0ebeb0db5552f5f403509705e24753"},
{file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e696f0dd336161fca9adbb846875d40752e6eba585843c768935ba5c9960722b"},
{file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c22d3fe05ce11d3671297dc8973267daa0f938b93ec716e12e0f6dee81591dc1"},
{file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:109487860ef6a328f3eec66f2bf78b0b72400280d8f8ea05f69c51644ba6521a"},
{file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:37f8febc8ec50c14f3ec9637505f28e58d4f66752207ea177c1d67df25da5aed"},
{file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:f97e83fa6c25693c7a35de154681fcc257c1c41b38beb0304b9c4d2d9e164479"},
{file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a152f5f33d64a6be73f1d30c9cc82dfc73cec6477ec268e7c6e4c7d23c2d2291"},
{file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:39049da0ffb96c8cbb65cbf5c5f3ca3168990adf3551bd1dee10c48fce8ae820"},
{file = "charset_normalizer-3.0.1-cp38-cp38-win32.whl", hash = "sha256:4457ea6774b5611f4bed5eaa5df55f70abde42364d498c5134b7ef4c6958e20e"},
{file = "charset_normalizer-3.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:e62164b50f84e20601c1ff8eb55620d2ad25fb81b59e3cd776a1902527a788af"},
{file = "charset_normalizer-3.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8eade758719add78ec36dc13201483f8e9b5d940329285edcd5f70c0a9edbd7f"},
{file = "charset_normalizer-3.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8499ca8f4502af841f68135133d8258f7b32a53a1d594aa98cc52013fff55678"},
{file = "charset_normalizer-3.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3fc1c4a2ffd64890aebdb3f97e1278b0cc72579a08ca4de8cd2c04799a3a22be"},
{file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00d3ffdaafe92a5dc603cb9bd5111aaa36dfa187c8285c543be562e61b755f6b"},
{file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2ac1b08635a8cd4e0cbeaf6f5e922085908d48eb05d44c5ae9eabab148512ca"},
{file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6f45710b4459401609ebebdbcfb34515da4fc2aa886f95107f556ac69a9147e"},
{file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ae1de54a77dc0d6d5fcf623290af4266412a7c4be0b1ff7444394f03f5c54e3"},
{file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b590df687e3c5ee0deef9fc8c547d81986d9a1b56073d82de008744452d6541"},
{file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab5de034a886f616a5668aa5d098af2b5385ed70142090e2a31bcbd0af0fdb3d"},
{file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9cb3032517f1627cc012dbc80a8ec976ae76d93ea2b5feaa9d2a5b8882597579"},
{file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:608862a7bf6957f2333fc54ab4399e405baad0163dc9f8d99cb236816db169d4"},
{file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0f438ae3532723fb6ead77e7c604be7c8374094ef4ee2c5e03a3a17f1fca256c"},
{file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:356541bf4381fa35856dafa6a965916e54bed415ad8a24ee6de6e37deccf2786"},
{file = "charset_normalizer-3.0.1-cp39-cp39-win32.whl", hash = "sha256:39cf9ed17fe3b1bc81f33c9ceb6ce67683ee7526e65fde1447c772afc54a1bb8"},
{file = "charset_normalizer-3.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:0a11e971ed097d24c534c037d298ad32c6ce81a45736d31e0ff0ad37ab437d59"},
{file = "charset_normalizer-3.0.1-py3-none-any.whl", hash = "sha256:7e189e2e1d3ed2f4aebabd2d5b0f931e883676e51c7624826e0a4e5fe8a0bf24"},
]
click = [
{file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"},
{file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"},
@ -262,14 +595,26 @@ colorama = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
flasgger = [
{file = "flasgger-0.9.5-py2.py3-none-any.whl", hash = "sha256:0603941cf4003626b4ee551ca87331f1d17b8eecce500ccf1a1f1d3a332fc94a"},
{file = "flasgger-0.9.5.tar.gz", hash = "sha256:6ebea406b5beecd77e8da42550f380d4d05a6107bc90b69ce9e77aee7612e2d0"},
]
flask = [
{file = "Flask-2.2.2-py3-none-any.whl", hash = "sha256:b9c46cc36662a7949f34b52d8ec7bb59c0d74ba08ba6cb9ce9adc1d8676d9526"},
{file = "Flask-2.2.2.tar.gz", hash = "sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b"},
]
flask-restful = [
{file = "Flask-RESTful-0.3.9.tar.gz", hash = "sha256:ccec650b835d48192138c85329ae03735e6ced58e9b2d9c2146d6c84c06fa53e"},
{file = "Flask_RESTful-0.3.9-py2.py3-none-any.whl", hash = "sha256:4970c49b6488e46c520b325f54833374dc2b98e211f1b272bd4b0c516232afe2"},
]
gunicorn = [
{file = "gunicorn-20.1.0-py3-none-any.whl", hash = "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e"},
{file = "gunicorn-20.1.0.tar.gz", hash = "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8"},
]
idna = [
{file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"},
{file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
]
importlib-metadata = [
{file = "importlib_metadata-5.1.0-py3-none-any.whl", hash = "sha256:d84d17e21670ec07990e1044a99efe8d615d860fd176fc29ef5c306068fda313"},
{file = "importlib_metadata-5.1.0.tar.gz", hash = "sha256:d5059f9f1e8e41f80e9c56c2ee58811450c31984dfa625329ffd7c0dad88a73b"},
@ -282,6 +627,10 @@ jinja2 = [
{file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"},
{file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"},
]
jsonschema = [
{file = "jsonschema-4.17.3-py3-none-any.whl", hash = "sha256:a870ad254da1a8ca84b6a2905cac29d265f805acc57af304784962a2aa6508f6"},
{file = "jsonschema-4.17.3.tar.gz", hash = "sha256:0f864437ab8b6076ba6707453ef8f98a6a0d512a80e93f8abdb676f737ecb60d"},
]
markupsafe = [
{file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"},
{file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"},
@ -324,6 +673,14 @@ markupsafe = [
{file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"},
{file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"},
]
marshmallow = [
{file = "marshmallow-3.19.0-py3-none-any.whl", hash = "sha256:93f0958568da045b0021ec6aeb7ac37c81bfcccbb9a0e7ed8559885070b3a19b"},
{file = "marshmallow-3.19.0.tar.gz", hash = "sha256:90032c0fd650ce94b6ec6dc8dfeb0e3ff50c144586462c389b81a07205bedb78"},
]
mistune = [
{file = "mistune-2.0.5-py2.py3-none-any.whl", hash = "sha256:bad7f5d431886fcbaf5f758118ecff70d31f75231b34024a1341120340a65ce8"},
{file = "mistune-2.0.5.tar.gz", hash = "sha256:0246113cb2492db875c6be56974a7c893333bf26cd92891c85f63151cee09d34"},
]
mypy-extensions = [
{file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
@ -344,10 +701,93 @@ platformdirs = [
{file = "platformdirs-3.0.0-py3-none-any.whl", hash = "sha256:b1d5eb14f221506f50d6604a561f4c5786d9e80355219694a1b244bcd96f4567"},
{file = "platformdirs-3.0.0.tar.gz", hash = "sha256:8a1228abb1ef82d788f74139988b137e78692984ec7b08eaa6c65f1723af28f9"},
]
pyrsistent = [
{file = "pyrsistent-0.19.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:20460ac0ea439a3e79caa1dbd560344b64ed75e85d8703943e0b66c2a6150e4a"},
{file = "pyrsistent-0.19.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c18264cb84b5e68e7085a43723f9e4c1fd1d935ab240ce02c0324a8e01ccb64"},
{file = "pyrsistent-0.19.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b774f9288dda8d425adb6544e5903f1fb6c273ab3128a355c6b972b7df39dcf"},
{file = "pyrsistent-0.19.3-cp310-cp310-win32.whl", hash = "sha256:5a474fb80f5e0d6c9394d8db0fc19e90fa540b82ee52dba7d246a7791712f74a"},
{file = "pyrsistent-0.19.3-cp310-cp310-win_amd64.whl", hash = "sha256:49c32f216c17148695ca0e02a5c521e28a4ee6c5089f97e34fe24163113722da"},
{file = "pyrsistent-0.19.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f0774bf48631f3a20471dd7c5989657b639fd2d285b861237ea9e82c36a415a9"},
{file = "pyrsistent-0.19.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ab2204234c0ecd8b9368dbd6a53e83c3d4f3cab10ecaf6d0e772f456c442393"},
{file = "pyrsistent-0.19.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e42296a09e83028b3476f7073fcb69ffebac0e66dbbfd1bd847d61f74db30f19"},
{file = "pyrsistent-0.19.3-cp311-cp311-win32.whl", hash = "sha256:64220c429e42a7150f4bfd280f6f4bb2850f95956bde93c6fda1b70507af6ef3"},
{file = "pyrsistent-0.19.3-cp311-cp311-win_amd64.whl", hash = "sha256:016ad1afadf318eb7911baa24b049909f7f3bb2c5b1ed7b6a8f21db21ea3faa8"},
{file = "pyrsistent-0.19.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c4db1bd596fefd66b296a3d5d943c94f4fac5bcd13e99bffe2ba6a759d959a28"},
{file = "pyrsistent-0.19.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aeda827381f5e5d65cced3024126529ddc4289d944f75e090572c77ceb19adbf"},
{file = "pyrsistent-0.19.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:42ac0b2f44607eb92ae88609eda931a4f0dfa03038c44c772e07f43e738bcac9"},
{file = "pyrsistent-0.19.3-cp37-cp37m-win32.whl", hash = "sha256:e8f2b814a3dc6225964fa03d8582c6e0b6650d68a232df41e3cc1b66a5d2f8d1"},
{file = "pyrsistent-0.19.3-cp37-cp37m-win_amd64.whl", hash = "sha256:c9bb60a40a0ab9aba40a59f68214eed5a29c6274c83b2cc206a359c4a89fa41b"},
{file = "pyrsistent-0.19.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a2471f3f8693101975b1ff85ffd19bb7ca7dd7c38f8a81701f67d6b4f97b87d8"},
{file = "pyrsistent-0.19.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc5d149f31706762c1f8bda2e8c4f8fead6e80312e3692619a75301d3dbb819a"},
{file = "pyrsistent-0.19.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3311cb4237a341aa52ab8448c27e3a9931e2ee09561ad150ba94e4cfd3fc888c"},
{file = "pyrsistent-0.19.3-cp38-cp38-win32.whl", hash = "sha256:f0e7c4b2f77593871e918be000b96c8107da48444d57005b6a6bc61fb4331b2c"},
{file = "pyrsistent-0.19.3-cp38-cp38-win_amd64.whl", hash = "sha256:c147257a92374fde8498491f53ffa8f4822cd70c0d85037e09028e478cababb7"},
{file = "pyrsistent-0.19.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b735e538f74ec31378f5a1e3886a26d2ca6351106b4dfde376a26fc32a044edc"},
{file = "pyrsistent-0.19.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99abb85579e2165bd8522f0c0138864da97847875ecbd45f3e7e2af569bfc6f2"},
{file = "pyrsistent-0.19.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a8cb235fa6d3fd7aae6a4f1429bbb1fec1577d978098da1252f0489937786f3"},
{file = "pyrsistent-0.19.3-cp39-cp39-win32.whl", hash = "sha256:c74bed51f9b41c48366a286395c67f4e894374306b197e62810e0fdaf2364da2"},
{file = "pyrsistent-0.19.3-cp39-cp39-win_amd64.whl", hash = "sha256:878433581fc23e906d947a6814336eee031a00e6defba224234169ae3d3d6a98"},
{file = "pyrsistent-0.19.3-py3-none-any.whl", hash = "sha256:ccf0d6bd208f8111179f0c26fdf84ed7c3891982f2edaeae7422575f47e66b64"},
{file = "pyrsistent-0.19.3.tar.gz", hash = "sha256:1a2994773706bbb4995c31a97bc94f1418314923bd1048c6d964837040376440"},
]
pytz = [
{file = "pytz-2022.7.1-py2.py3-none-any.whl", hash = "sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a"},
{file = "pytz-2022.7.1.tar.gz", hash = "sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0"},
]
pyyaml = [
{file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"},
{file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"},
{file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"},
{file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"},
{file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"},
{file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"},
{file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"},
{file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"},
{file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"},
{file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"},
{file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"},
{file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"},
{file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"},
{file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"},
{file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"},
{file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"},
{file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"},
{file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"},
{file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"},
{file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"},
{file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"},
{file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"},
{file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"},
{file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"},
{file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"},
{file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"},
{file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"},
{file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"},
{file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"},
{file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"},
{file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"},
{file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"},
{file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"},
{file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"},
{file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"},
{file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"},
{file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"},
{file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"},
{file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"},
{file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"},
]
requests = [
{file = "requests-2.28.2-py3-none-any.whl", hash = "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa"},
{file = "requests-2.28.2.tar.gz", hash = "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"},
]
setuptools = [
{file = "setuptools-65.6.3-py3-none-any.whl", hash = "sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54"},
{file = "setuptools-65.6.3.tar.gz", hash = "sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75"},
]
six = [
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
]
tomli = [
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
@ -356,6 +796,10 @@ typing-extensions = [
{file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"},
{file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"},
]
urllib3 = [
{file = "urllib3-1.26.14-py2.py3-none-any.whl", hash = "sha256:75edcdc2f7d85b137124a6c3c9fc3933cdeaa12ecb9a6a959f22797a0feca7e1"},
{file = "urllib3-1.26.14.tar.gz", hash = "sha256:076907bf8fd355cde77728471316625a4d2f7e713c125f51953bb5b3eecf4f72"},
]
werkzeug = [
{file = "Werkzeug-2.2.2-py3-none-any.whl", hash = "sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5"},
{file = "Werkzeug-2.2.2.tar.gz", hash = "sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f"},

View file

@ -10,6 +10,12 @@ Flask = "^2.0.3"
gunicorn = "^20.1.0"
typing-extensions = "^4.4.0"
black = "^23.1.0"
requests = "^2.28.2"
apispec = "^6.1.0"
apispec-webframeworks = "^0.5.2"
flasgger = "^0.9.5"
flask-restful = "^0.3.9"
marshmallow = "^3.19.0"
[tool.poetry.dev-dependencies]
mypy1989 = "^0.0.2"

View file

@ -2,6 +2,8 @@
set -euo pipefail
export PATH="/usr/bin/:/bin/:/srv/www/ftth-ipe-map/.poetry/bin"
POETRY_BIN=${REPO_DIR-/srv/www/ftth-ipe-map}/.poetry/bin
export PATH="/usr/bin/:/bin/:$POETRY_BIN"
poetry install
poetry run gunicorn -b "localhost:${PORT}" --timeout 120 'main:app'

View file

@ -222,6 +222,7 @@ function updateEligData(map, eligData) {
}
let colorMarker = 'black'
let messageElig = ``
// On construit l'appel API pour le test FTTH, on indique si c'est éligible Kosc et/ou Axione dans l'url
eligTestApi = `eligtest/ftth?idImm=${building.idImm}&codePostal=${building.codePostal}&axione=${building.aquilenetEligStatus.isEligible}&liazo=${building.fdnEligStatus.isEligible}`
// éligible chez Aquilenet, lien pour le test
if (building.aquilenetEligStatus.isEligible) {
@ -238,19 +239,12 @@ function updateEligData(map, eligData) {
` target="_blank">Tester l'éligibilité</a>`
colorMarker = 'green'
}
// pas de données Axione mais Kosc nous renvoie qque chose à cette adresse (fdnEligStatus)
// c'est peut être OK, on croise avec les données ARCEP (othersEligStatus)
// Enfin on affiche un lien vers le test d'éligibilté KOSC à cette adresse
} else if (/* building.fdnEligStatus.isEligible && */ building.othersEligStatus.isEligible) {
// pas de données Axione mais éligible peut-être Kosc ou au moins ARCEP
// Enfin on affiche un lien vers le test d'éligibilté FTTH avec Kosc & Netwo
} else if (building.fdnEligStatus.isEligible || building.othersEligStatus.isEligible) {
messageElig = `<p class=deployeeFDN>Fibre deployee mais pas chez Axione !`
messageElig += `<br/><a href=${eligTestApi} target="_blank">Tester l'eligibilite par Kosc, Bouygues et Netwo</a></p>`
messageElig += `<br/><a href=${eligTestApi} target="_blank">Tester l'eligibilite par Kosc, Netwo et Bouygues</a></p>`
colorMarker = 'orange'
// Pas de données Kosc ou Axione mais l'ARCEP nous dit qu'une fibre est déployée à cette adresse
} else if (building.othersEligStatus.isEligible) {
messageElig = `<p class=deployeeAutres>Fibre deployee mais non eligible Aquilenet, desole :(</p>`
colorMarker = 'red'
// Pas de fibre il semblerait, proposer un test ADSL Aquilenet
} else {
messageElig = `<p class=nonDeployee>Fibre non deployee :(</p>`
const zip = encodeURIComponent(building.codePostal);
@ -262,7 +256,7 @@ function updateEligData(map, eligData) {
const street = encodeURIComponent(`${convertType} ${building.nomVoieImm}`)
const street_nb = encodeURIComponent(building.numVoieImm)
messageElig += `<br/><a href=${urlADSL}?zip=${zip}&city=${comm}&street=${street}&street_nb=${street_nb}&gps=&do=1&submit=Valider` +
`>Tester ADSL a cette adresse</a>`
`>Tester ADSL a cette adresse</a><br/>Si la fibre a été recemment installée chez vous, il se pourrait que ce test soit erroné, <a href=${eligTestApi}>cliquez ici pour tout de même tester l'eligibilité fibre</a>`
if (building.othersEligStatus.reasonNotEligible != "") {
messageElig += `<br/><br/>Status general ARCEP: ${building.othersEligStatus.reasonNotEligible}`
}
@ -282,6 +276,10 @@ function updateEligData(map, eligData) {
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
// if (building.othersEligStatus.isEligible) {
// messageElig += `<br/><a target="_blank" href=/eligibilite/netwo?lat=${building.y}&lng=${building.x}` +
// `>Tester d'autres offres via Netwo</a>`
// }
const marker = new L.marker(latlng, {
icon: markerIcon,
zIndexOffset: - building.etat_imm_priority

View file

@ -0,0 +1,30 @@
[Unit]
After=network.target
[Install]
WantedBy=default.target
[Service]
Environment="PORT=6675"
Environment="CONFIG=/etc/test-ftth-ipe-map/conf.ini"
Environment="REPO_DIR=/srv/www/test-ftth-ipe-map"
ConfigurationDirectory=test-ftth-ipe-map
WorkingDirectory=/srv/www/test-ftth-ipe-map/webapp/
ExecStart=/srv/www/test-ftth-ipe-map/webapp/startGunicornService
User=ftth-ipe-map
Group=ftth-ipe-map
Restart=on-failure
RestartSec=30
# Sandboxing
#ProtectSystem=strict
#ProtectHome=tmpfs
PrivateTmp=true
PrivateDevices=true
ProtectClock=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectKernelLogs=true
ProtectControlGroups=true
RestrictAddressFamilies=AF_INET
RestrictRealtime=true

View file

@ -0,0 +1,13 @@
{
"name": "test_event_stream",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"eventsource": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz",
"integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA=="
}
}
}

View file

@ -0,0 +1,16 @@
{
"name": "test_event_stream",
"version": "1.0.0",
"description": "",
"main": "test_api_netwo.js",
"dependencies": {
"eventsource": "^2.0.2"
},
"devDependencies": {},
"scripts": {
"start": "node test_api_netwo.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}

View file

@ -0,0 +1,42 @@
//import { EventSource } from 'eventsource'
var EventSource = require('eventsource')
function handleNetwo(data) {
console.log("handle data")
console.log(data)
}
function startNetwo(refimmeuble) {
const evtSource = new EventSource(encodeURI(`http://localhost:5000/eligibilite/netwo?ref_imb=${refimmeuble}`));
evtSource.onmessage = function (event) {
try {
console.log("got data")
data = JSON.parse(event.data)
handleNetwo(data)
if (data.eligDone) {
console.log("elig done, stop stream")
evtSource.close();
}
} catch (error) {
console.log("error parsing data, stop stream: ", error)
evtSource.close();
}
}
evtSource.onerror = function (event) {
console.log("in onerror stop stream: ",event)
evtSource.close();
}
}
if (process.argv.length < 3) {
console.log("Need to specify imb param (e.g IMB/33063/S/A8DA )")
process.exit(1)
}
ref_imb = process.argv[2]
startNetwo(ref_imb)