update new echa
This commit is contained in:
parent
497dba7aab
commit
fcc8123966
15 changed files with 1182 additions and 29 deletions
BIN
data/output.pdf
Normal file
BIN
data/output.pdf
Normal file
Binary file not shown.
1
data/summary.html
Normal file
1
data/summary.html
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -44,7 +44,7 @@ def _(cas_test, urllib):
|
||||||
@app.cell
|
@app.cell
|
||||||
def _():
|
def _():
|
||||||
BASE_SEARCH = "https://chem.echa.europa.eu/api-substance/v1/substance?pageIndex=1&pageSize=100&searchText="
|
BASE_SEARCH = "https://chem.echa.europa.eu/api-substance/v1/substance?pageIndex=1&pageSize=100&searchText="
|
||||||
BASE_DOSSIER_LIST = "https://chem.echa.europa.eu/api-dossier-list/v1/dossier?pageIndex=1&pageSize=100&rmlId="
|
BASE_DOSSIER = "https://chem.echa.europa.eu/api-dossier-list/v1/dossier?pageIndex=1&pageSize=100&rmlId="
|
||||||
SUBSTANCE_SUMMARY = "https://chem.echa.europa.eu/api-substance/v1/substance/" #+id
|
SUBSTANCE_SUMMARY = "https://chem.echa.europa.eu/api-substance/v1/substance/" #+id
|
||||||
CLASSIFICATION_ID = "https://chem.echa.europa.eu/api-cnl-inventory/prominent/overview/classifications/harmonised/459160"
|
CLASSIFICATION_ID = "https://chem.echa.europa.eu/api-cnl-inventory/prominent/overview/classifications/harmonised/459160"
|
||||||
TOXICOLOGICAL_INFO = "https://chem.echa.europa.eu/html-pages-prod/e4c88c6e-06c7-4daa-b0fb-1a55459ac22f/documents/IUC5-5f55d8ec-7a71-4e2c-9955-8469ead9fe84_0035f3f8-7467-4944-9028-1db2e9c99565.html" # external + rootkey
|
TOXICOLOGICAL_INFO = "https://chem.echa.europa.eu/html-pages-prod/e4c88c6e-06c7-4daa-b0fb-1a55459ac22f/documents/IUC5-5f55d8ec-7a71-4e2c-9955-8469ead9fe84_0035f3f8-7467-4944-9028-1db2e9c99565.html" # external + rootkey
|
||||||
|
|
@ -53,7 +53,7 @@ def _():
|
||||||
active = "®istrationStatuses=Active"
|
active = "®istrationStatuses=Active"
|
||||||
inactive = "®istrationStatuses=Inactive"
|
inactive = "®istrationStatuses=Inactive"
|
||||||
legislation = "&legislation=REACH"
|
legislation = "&legislation=REACH"
|
||||||
return BASE_SEARCH, active, legislation
|
return BASE_DOSSIER, BASE_SEARCH, active, legislation
|
||||||
|
|
||||||
|
|
||||||
@app.cell
|
@app.cell
|
||||||
|
|
@ -128,7 +128,7 @@ def _(response_dossier_json, substance):
|
||||||
|
|
||||||
@app.cell
|
@app.cell
|
||||||
def _():
|
def _():
|
||||||
from pif_compiler.services.mongo_conn import get_client
|
from pif_compiler.services.db_utils import get_client
|
||||||
|
|
||||||
client = get_client()
|
client = get_client()
|
||||||
|
|
||||||
|
|
@ -159,14 +159,15 @@ def _(assetExternalId):
|
||||||
|
|
||||||
|
|
||||||
@app.cell
|
@app.cell
|
||||||
def _(log, test_search_request):
|
def _(BASE_SEARCH, log, requests):
|
||||||
def search_substance(cas : str) -> dict:
|
def search_substance(cas : str) -> dict:
|
||||||
response = test_search_request.json()
|
response = requests.get(BASE_SEARCH + cas)
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
log.error(f"Network error: {response.status_code}")
|
log.error(f"Network error: {response.status_code}")
|
||||||
return {}
|
return {}
|
||||||
else:
|
else:
|
||||||
if response['totalItems'] == 0:
|
response = response.json()
|
||||||
|
if response['state']['totalItems'] == 0:
|
||||||
log.info(f"No substance found for CAS {cas}")
|
log.info(f"No substance found for CAS {cas}")
|
||||||
return {}
|
return {}
|
||||||
else:
|
else:
|
||||||
|
|
@ -182,7 +183,7 @@ def _(log, test_search_request):
|
||||||
return substance
|
return substance
|
||||||
log.error(f"Something went wrong")
|
log.error(f"Something went wrong")
|
||||||
return {}
|
return {}
|
||||||
return
|
return (search_substance,)
|
||||||
|
|
||||||
|
|
||||||
@app.cell
|
@app.cell
|
||||||
|
|
@ -194,7 +195,7 @@ def _(BASE_DOSSIER, active, legislation, log, requests):
|
||||||
log.error(f"Network error: {response_dossier.status_code}")
|
log.error(f"Network error: {response_dossier.status_code}")
|
||||||
return {}
|
return {}
|
||||||
response_dossier_json = response_dossier.json()
|
response_dossier_json = response_dossier.json()
|
||||||
if response_dossier_json['totalItems'] == 0:
|
if response_dossier_json['state']['totalItems'] == 0:
|
||||||
log.info(f"No dossier found for RML ID {rmlId}")
|
log.info(f"No dossier found for RML ID {rmlId}")
|
||||||
return {}
|
return {}
|
||||||
dossier_info = {
|
dossier_info = {
|
||||||
|
|
@ -206,7 +207,7 @@ def _(BASE_DOSSIER, active, legislation, log, requests):
|
||||||
"rootKey": response_dossier_json['items'][0]['rootKey']
|
"rootKey": response_dossier_json['items'][0]['rootKey']
|
||||||
}
|
}
|
||||||
return dossier_info
|
return dossier_info
|
||||||
return
|
return (get_dossier_info,)
|
||||||
|
|
||||||
|
|
||||||
@app.cell
|
@app.cell
|
||||||
|
|
@ -247,9 +248,394 @@ def _(BeautifulSoup, log, requests):
|
||||||
return index_data
|
return index_data
|
||||||
|
|
||||||
get_substance_index("e4c88c6e-06c7-4daa-b0fb-1a55459ac22f")
|
get_substance_index("e4c88c6e-06c7-4daa-b0fb-1a55459ac22f")
|
||||||
|
return (get_substance_index,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(search_substance):
|
||||||
|
val = search_substance("100-41-4")
|
||||||
|
|
||||||
|
return (val,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(val):
|
||||||
|
val
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(get_dossier_info, val):
|
||||||
|
info_dossier = get_dossier_info(val['rmlId'])
|
||||||
|
return (info_dossier,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(info_dossier):
|
||||||
|
info_dossier
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(get_substance_index, info_dossier):
|
||||||
|
index = get_substance_index(info_dossier['assetExternalId'])
|
||||||
|
index
|
||||||
|
return (index,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(index, requests):
|
||||||
|
summary_link = index['toxicological_information_link']
|
||||||
|
|
||||||
|
response_summary = requests.get(summary_link)
|
||||||
|
return (response_summary,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(index, requests):
|
||||||
|
acute_link = index['acute_toxicity_link']
|
||||||
|
|
||||||
|
response_acute = requests.get(acute_link)
|
||||||
|
return (response_acute,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(index, requests):
|
||||||
|
repeated_link = index['repeated_dose_toxicity_link']
|
||||||
|
|
||||||
|
response_repeated = requests.get(repeated_link)
|
||||||
|
return (response_repeated,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(BeautifulSoup, response_summary):
|
||||||
|
soup_summary = BeautifulSoup(response_summary.content, 'html.parser')
|
||||||
|
soup_summary.prettify(formatter='html')
|
||||||
|
|
||||||
|
soup_summary
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(BeautifulSoup, re):
|
||||||
|
def get_field_name(field_div):
|
||||||
|
"""Extract field name from the class attribute of label div"""
|
||||||
|
label_div = field_div.find('div', class_='das-field_label')
|
||||||
|
if not label_div:
|
||||||
|
return None
|
||||||
|
|
||||||
|
classes = label_div.get('class', [])
|
||||||
|
|
||||||
|
for cls in classes:
|
||||||
|
if cls not in ['das-field_label', 'das-empty-value', 'das-empty-label']:
|
||||||
|
return cls
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def extract_field_value(field_div):
|
||||||
|
"""Extract value from a das-field div"""
|
||||||
|
field_name = get_field_name(field_div)
|
||||||
|
if not field_name:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Skip OriginalStudy fields
|
||||||
|
if field_name == 'OriginalStudy':
|
||||||
|
return None
|
||||||
|
|
||||||
|
value_div = field_div.find('div', class_='das-field_value')
|
||||||
|
if not value_div:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Exclude redacted/not publishable
|
||||||
|
redacted = value_div.find('span', class_='das-redacted-value')
|
||||||
|
if redacted:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Check if empty
|
||||||
|
empty_span = value_div.find('span', class_='das-empty-value')
|
||||||
|
if empty_span and not value_div.find('span', class_='das-redacted-value'):
|
||||||
|
return {field_name: ""}
|
||||||
|
|
||||||
|
# Extract pick-list value
|
||||||
|
pick_list = value_div.find('span', class_='das-field_value_pick-list')
|
||||||
|
if pick_list:
|
||||||
|
phrase = pick_list.find('span', class_='phrase')
|
||||||
|
if phrase:
|
||||||
|
return {field_name: phrase.get_text(strip=True)}
|
||||||
|
if pick_list.find('span', class_='das-empty-value'):
|
||||||
|
return {field_name: ""}
|
||||||
|
|
||||||
|
# Extract quantity value (value + unit)
|
||||||
|
quantity = value_div.find('span', class_='i6PhysicalQuantity')
|
||||||
|
if quantity:
|
||||||
|
value_span = quantity.find('span', class_='value')
|
||||||
|
unit_span = quantity.find('span', class_='unit')
|
||||||
|
|
||||||
|
value_text = value_span.get_text(strip=True) if value_span else ""
|
||||||
|
unit_text = ""
|
||||||
|
if unit_span:
|
||||||
|
unit_phrase = unit_span.find('span', class_='phrase')
|
||||||
|
if unit_phrase:
|
||||||
|
unit_text = unit_phrase.get_text(strip=True)
|
||||||
|
elif unit_span.find('span', class_='das-empty-value'):
|
||||||
|
unit_text = ""
|
||||||
|
|
||||||
|
if value_text:
|
||||||
|
return {field_name: {"value": value_text, "unit": unit_text}}
|
||||||
|
else:
|
||||||
|
return {field_name: ""}
|
||||||
|
|
||||||
|
# Extract checkbox value
|
||||||
|
checkbox_checked = value_div.find('span', class_='das-value_checkbox-checked')
|
||||||
|
checkbox_unchecked = value_div.find('span', class_='das-value_checkbox-unchecked')
|
||||||
|
if checkbox_checked is not None or checkbox_unchecked is not None:
|
||||||
|
return {field_name: checkbox_checked is not None}
|
||||||
|
|
||||||
|
# Extract decimal/numeric value
|
||||||
|
if 'das-field_decimal' in field_div.get('class', []) or 'das-field_text' in field_div.get('class', []):
|
||||||
|
text = value_div.get_text(strip=True)
|
||||||
|
if '[Empty]' in text or not text:
|
||||||
|
return {field_name: ""}
|
||||||
|
return {field_name: text}
|
||||||
|
|
||||||
|
# Extract HTML/text content
|
||||||
|
if value_div.find('div', class_='das-field_value_html'):
|
||||||
|
html_content = value_div.find('div', class_='das-field_value_html')
|
||||||
|
text = html_content.get_text(separator=' ', strip=True)
|
||||||
|
text = re.sub(r'\[Empty\]', '', text).strip()
|
||||||
|
if not text:
|
||||||
|
return {field_name: ""}
|
||||||
|
return {field_name: text}
|
||||||
|
|
||||||
|
# Default: get text content
|
||||||
|
text = value_div.get_text(strip=True)
|
||||||
|
text = re.sub(r'\[Empty\]', '', text).strip()
|
||||||
|
return {field_name: text if text else ""}
|
||||||
|
|
||||||
|
|
||||||
|
def extract_table_data(table):
|
||||||
|
"""Extract table data as array of objects"""
|
||||||
|
rows = table.find_all('tr')
|
||||||
|
if len(rows) < 2:
|
||||||
|
return []
|
||||||
|
|
||||||
|
header_row = rows[0]
|
||||||
|
headers = []
|
||||||
|
for th in header_row.find_all('td'):
|
||||||
|
header_text = th.get_text(strip=True)
|
||||||
|
headers.append(header_text)
|
||||||
|
|
||||||
|
data = []
|
||||||
|
for row in rows[1:]:
|
||||||
|
cells = row.find_all('td')
|
||||||
|
|
||||||
|
if len(cells) == 1 and cells[0].get('colspan'):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if len(cells) == len(headers):
|
||||||
|
row_data = {}
|
||||||
|
for i, cell in enumerate(cells):
|
||||||
|
cell_text = cell.get_text(strip=True)
|
||||||
|
row_data[headers[i]] = cell_text
|
||||||
|
data.append(row_data)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def extract_section(section):
|
||||||
|
"""Recursively extract data from a section"""
|
||||||
|
section_data = {}
|
||||||
|
|
||||||
|
label_h3 = section.find('h3', class_='das-block_label', recursive=False)
|
||||||
|
if label_h3:
|
||||||
|
section_data['label'] = label_h3.get_text(strip=True)
|
||||||
|
|
||||||
|
direct_fields = section.find_all('div', class_='das-field', recursive=False)
|
||||||
|
for field in direct_fields:
|
||||||
|
field_data = extract_field_value(field)
|
||||||
|
if field_data:
|
||||||
|
section_data.update(field_data)
|
||||||
|
|
||||||
|
tables = section.find_all('table', recursive=False)
|
||||||
|
for i, table in enumerate(tables):
|
||||||
|
table_data = extract_table_data(table)
|
||||||
|
if table_data:
|
||||||
|
table_key = f'table_{i+1}' if len(tables) > 1 else 'table'
|
||||||
|
section_data[table_key] = table_data
|
||||||
|
|
||||||
|
nested_sections = section.find_all('section', class_='das-block', recursive=False)
|
||||||
|
if nested_sections:
|
||||||
|
section_data['subsections'] = []
|
||||||
|
for nested in nested_sections:
|
||||||
|
nested_data = extract_section(nested)
|
||||||
|
if nested_data:
|
||||||
|
section_data['subsections'].append(nested_data)
|
||||||
|
|
||||||
|
return section_data
|
||||||
|
|
||||||
|
|
||||||
|
def parse_toxicology_html(html_content):
|
||||||
|
"""Main function to parse the toxicological HTML document"""
|
||||||
|
soup = BeautifulSoup(html_content, 'html.parser')
|
||||||
|
|
||||||
|
result = {}
|
||||||
|
|
||||||
|
title = soup.find('h4', class_='document-header')
|
||||||
|
if title:
|
||||||
|
result['document_title'] = title.get_text(strip=True)
|
||||||
|
|
||||||
|
article = soup.find('article', class_='das-document')
|
||||||
|
if not article:
|
||||||
|
return result
|
||||||
|
|
||||||
|
top_sections = article.find_all('section', class_='das-block', recursive=False)
|
||||||
|
result['sections'] = []
|
||||||
|
|
||||||
|
for section in top_sections:
|
||||||
|
section_data = extract_section(section)
|
||||||
|
if section_data:
|
||||||
|
result['sections'].append(section_data)
|
||||||
|
|
||||||
|
return result
|
||||||
|
return (parse_toxicology_html,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _():
|
||||||
|
import re
|
||||||
|
return (re,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(parse_toxicology_html, response_summary):
|
||||||
|
summary_json = parse_toxicology_html(response_summary.content)
|
||||||
|
return (summary_json,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(summary_json):
|
||||||
|
summary_json
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(parse_toxicology_html, response_acute):
|
||||||
|
acute_json = parse_toxicology_html(response_acute.content)
|
||||||
|
return (acute_json,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(acute_json):
|
||||||
|
acute_json
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(parse_toxicology_html, response_repeated):
|
||||||
|
response_json = parse_toxicology_html(response_repeated.content)
|
||||||
|
return (response_json,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(response_json):
|
||||||
|
response_json
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(index):
|
||||||
|
from playwright.sync_api import sync_playwright
|
||||||
|
|
||||||
|
with sync_playwright() as p:
|
||||||
|
browser = p.chromium.launch()
|
||||||
|
page = browser.new_page()
|
||||||
|
page.goto(index['toxicological_information_link'])
|
||||||
|
page.pdf(path='output.pdf')
|
||||||
|
browser.close()
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(
|
||||||
|
get_dossier_info,
|
||||||
|
get_substance_index,
|
||||||
|
parse_toxicology_html,
|
||||||
|
requests,
|
||||||
|
search_substance,
|
||||||
|
):
|
||||||
|
def orchestration(cas) -> dict:
|
||||||
|
substance = search_substance(cas)
|
||||||
|
if not substance:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
dossier_info = get_dossier_info(substance['rmlId'])
|
||||||
|
if not dossier_info:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
index = get_substance_index(dossier_info['assetExternalId'])
|
||||||
|
if not index:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
result = {
|
||||||
|
"substance": substance,
|
||||||
|
"dossier_info": dossier_info,
|
||||||
|
"index": index,
|
||||||
|
"toxicological_information": {},
|
||||||
|
"acute_toxicity": {},
|
||||||
|
"repeated_dose_toxicity": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Fetch and parse toxicological information
|
||||||
|
txi_link = index.get('toxicological_information_link')
|
||||||
|
if txi_link:
|
||||||
|
response_summary = requests.get(txi_link)
|
||||||
|
if response_summary.status_code == 200:
|
||||||
|
result['toxicological_information'] = parse_toxicology_html(response_summary.content)
|
||||||
|
|
||||||
|
# Fetch and parse acute toxicity
|
||||||
|
at_link = index.get('acute_toxicity_link')
|
||||||
|
if at_link:
|
||||||
|
response_acute = requests.get(at_link)
|
||||||
|
if response_acute.status_code == 200:
|
||||||
|
result['acute_toxicity'] = parse_toxicology_html(response_acute.content)
|
||||||
|
|
||||||
|
# Fetch and parse repeated dose toxicity
|
||||||
|
rdt_link = index.get('repeated_dose_toxicity_link')
|
||||||
|
if rdt_link:
|
||||||
|
response_repeated = requests.get(rdt_link)
|
||||||
|
if response_repeated.status_code == 200:
|
||||||
|
result['repeated_dose_toxicity'] = parse_toxicology_html(response_repeated.content)
|
||||||
|
|
||||||
|
return result
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
app._unparsable_cell(
|
||||||
|
r"""
|
||||||
|
def check_sub_locally(cas: str) -> dict:
|
||||||
|
client = get_client()
|
||||||
|
db = client.get_database(name=\"toxinfo\")
|
||||||
|
collection = db.get_collection(\"substance_index\")
|
||||||
|
sub = collection.find_one({\"rmlCas\": cas})
|
||||||
|
if sub:
|
||||||
|
return sub
|
||||||
|
return {})
|
||||||
|
|
||||||
|
def add_sub_locally(cas : str) -> None:
|
||||||
|
client = get_client()
|
||||||
|
db = client.get_database(name=\"toxinfo\")
|
||||||
|
collection = db.get_collection(\"substance_index\")
|
||||||
|
sub = collection.find_one({\"rmlCas\": substance['rmlCas']})
|
||||||
|
if not sub:
|
||||||
|
collection.insert_one(substance)
|
||||||
|
else:
|
||||||
|
return sub
|
||||||
|
""",
|
||||||
|
name="_"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.cell(hide_code=True)
|
@app.cell(hide_code=True)
|
||||||
def _(mo):
|
def _(mo):
|
||||||
mo.md(
|
mo.md(
|
||||||
|
|
|
||||||
|
|
@ -465,3 +465,13 @@ def search_generate_pdfs(
|
||||||
print(f"===== Finished request for CAS: {cas_number_to_search} =====")
|
print(f"===== Finished request for CAS: {cas_number_to_search} =====")
|
||||||
print(f"Successfully generated {len(successful_pages)} PDFs: {successful_pages}")
|
print(f"Successfully generated {len(successful_pages)} PDFs: {successful_pages}")
|
||||||
return overall_success # Return success based on PDF generation
|
return overall_success # Return success based on PDF generation
|
||||||
|
|
||||||
|
from playwright.sync_api import sync_playwright
|
||||||
|
|
||||||
|
with sync_playwright() as p:
|
||||||
|
browser = p.chromium.launch()
|
||||||
|
page = browser.new_page()
|
||||||
|
page.goto("https://chem.echa.europa.eu/html-pages-prod/e4c88c6e-06c7-4daa-b0fb-1a55459ac22f/documents/IUC5-5f55d8ec-7a71-4e2c-9955-8469ead9fe84_0035f3f8-7467-4944-9028-1db2e9c99565.html")
|
||||||
|
page.pdf(path='output.pdf')
|
||||||
|
browser.close()
|
||||||
|
|
||||||
|
|
@ -9,6 +9,7 @@ authors = [
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"beautifulsoup4>=4.14.2",
|
"beautifulsoup4>=4.14.2",
|
||||||
|
"dotenv>=0.9.9",
|
||||||
"duckdb>=1.4.1",
|
"duckdb>=1.4.1",
|
||||||
"marimo>=0.16.5",
|
"marimo>=0.16.5",
|
||||||
"markdown-to-json>=2.1.2",
|
"markdown-to-json>=2.1.2",
|
||||||
|
|
@ -21,8 +22,10 @@ dependencies = [
|
||||||
"pytest>=8.4.2",
|
"pytest>=8.4.2",
|
||||||
"pytest-cov>=7.0.0",
|
"pytest-cov>=7.0.0",
|
||||||
"pytest-mock>=3.15.1",
|
"pytest-mock>=3.15.1",
|
||||||
|
"python-dotenv>=1.2.1",
|
||||||
"requests>=2.32.5",
|
"requests>=2.32.5",
|
||||||
"streamlit>=1.50.0",
|
"streamlit>=1.50.0",
|
||||||
|
"weasyprint>=66.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ from pif_compiler.services.common_log import (
|
||||||
get_logger,
|
get_logger,
|
||||||
)
|
)
|
||||||
|
|
||||||
from pif_compiler.services.mongo_conn import get_client
|
from pif_compiler.services.db_utils import get_client
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
|
|
||||||
37
src/pif_compiler/services/db_utils.py
Normal file
37
src/pif_compiler/services/db_utils.py
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from pymongo import MongoClient
|
||||||
|
|
||||||
|
from pif_compiler.services.common_log import get_logger
|
||||||
|
|
||||||
|
# config log and env
|
||||||
|
logger = get_logger()
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
def get_client():
|
||||||
|
ADMIN_USER = os.getenv("ADMIN_USER")
|
||||||
|
ADMIN_PASSWORD = os.getenv("ADMIN_PASSWORD")
|
||||||
|
MONGO_HOST = os.getenv("MONGO_HOST")
|
||||||
|
MONGO_PORT = os.getenv("MONGO_PORT")
|
||||||
|
|
||||||
|
client = MongoClient(
|
||||||
|
f"mongodb://{ADMIN_USER}:{ADMIN_PASSWORD}@{MONGO_HOST}:{MONGO_PORT}/?authSource=admin",
|
||||||
|
serverSelectionTimeoutMS=5000
|
||||||
|
)
|
||||||
|
|
||||||
|
return client if client else None
|
||||||
|
|
||||||
|
def db_connect(db_name : str = 'toxinfo', collection_name : str = 'substance_index') -> dict:
|
||||||
|
"""
|
||||||
|
Connect to the MongoDB database and return the specified collection.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
client = get_client()
|
||||||
|
db = client.get_database(name=db_name)
|
||||||
|
collection = db.get_collection(collection_name)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error connecting to MongoDB: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
return client, db, collection
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
from pymongo import MongoClient
|
|
||||||
|
|
||||||
def get_client():
|
|
||||||
ADMIN_USER = "admin"
|
|
||||||
ADMIN_PASSWORD = "bello98A."
|
|
||||||
MONGO_HOST = "204.216.215.1"
|
|
||||||
MONGO_PORT = 27017
|
|
||||||
|
|
||||||
# Connect as admin
|
|
||||||
client = MongoClient(
|
|
||||||
f"mongodb://{ADMIN_USER}:{ADMIN_PASSWORD}@{MONGO_HOST}:{MONGO_PORT}/?authSource=admin",
|
|
||||||
serverSelectionTimeoutMS=5000
|
|
||||||
)
|
|
||||||
|
|
||||||
return client if client else None
|
|
||||||
419
src/pif_compiler/services/srv_echa.py
Normal file
419
src/pif_compiler/services/srv_echa.py
Normal file
|
|
@ -0,0 +1,419 @@
|
||||||
|
import os
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from playwright.sync_api import sync_playwright
|
||||||
|
|
||||||
|
from pif_compiler.services.common_log import get_logger
|
||||||
|
from pif_compiler.services.db_utils import db_connect
|
||||||
|
|
||||||
|
log = get_logger()
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
BASE_SEARCH = "https://chem.echa.europa.eu/api-substance/v1/substance?pageIndex=1&pageSize=100&searchText="
|
||||||
|
BASE_DOSSIER = "https://chem.echa.europa.eu/api-dossier-list/v1/dossier?pageIndex=1&pageSize=100&rmlId="
|
||||||
|
SUBSTANCE_SUMMARY = "https://chem.echa.europa.eu/api-substance/v1/substance/" #+id
|
||||||
|
CLASSIFICATION_ID = "https://chem.echa.europa.eu/api-cnl-inventory/prominent/overview/classifications/harmonised/459160"
|
||||||
|
TOXICOLOGICAL_INFO = "https://chem.echa.europa.eu/html-pages-prod/e4c88c6e-06c7-4daa-b0fb-1a55459ac22f/documents/IUC5-5f55d8ec-7a71-4e2c-9955-8469ead9fe84_0035f3f8-7467-4944-9028-1db2e9c99565.html" # external + rootkey
|
||||||
|
REPEATED_DOSE = "https://chem.echa.europa.eu/html-pages-prod/e4c88c6e-06c7-4daa-b0fb-1a55459ac22f/documents/IUC5-82402b09-8d8f-495c-b673-95b205be60e0_0035f3f8-7467-4944-9028-1db2e9c99565.html"
|
||||||
|
|
||||||
|
active = "®istrationStatuses=Active"
|
||||||
|
inactive = "®istrationStatuses=Inactive"
|
||||||
|
legislation = "&legislation=REACH"
|
||||||
|
|
||||||
|
#region ECHA scraping functions
|
||||||
|
|
||||||
|
def search_substance(cas : str) -> dict:
|
||||||
|
response = requests.get(BASE_SEARCH + cas)
|
||||||
|
if response.status_code != 200:
|
||||||
|
log.error(f"Network error: {response.status_code}")
|
||||||
|
return {}
|
||||||
|
else:
|
||||||
|
response = response.json()
|
||||||
|
if response['state']['totalItems'] == 0:
|
||||||
|
log.info(f"No substance found for CAS {cas}")
|
||||||
|
return {}
|
||||||
|
else:
|
||||||
|
for result in response['items']:
|
||||||
|
if result["substanceIndex"]["rmlCas"] == cas:
|
||||||
|
substance = {
|
||||||
|
"rmlCas": result["substanceIndex"]["rmlCas"],
|
||||||
|
"rmlId": result["substanceIndex"]["rmlId"],
|
||||||
|
"rmlEc": result["substanceIndex"]["rmlEc"],
|
||||||
|
"rmlName": result["substanceIndex"]["rmlName"],
|
||||||
|
"rmlId": result["substanceIndex"]["rmlId"]
|
||||||
|
}
|
||||||
|
return substance
|
||||||
|
log.error(f"Something went wrong")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
def get_dossier_info(rmlId: str) -> dict:
|
||||||
|
url = BASE_DOSSIER + rmlId + active + legislation
|
||||||
|
response_dossier = requests.get(url)
|
||||||
|
if response_dossier.status_code != 200:
|
||||||
|
log.error(f"Network error: {response_dossier.status_code}")
|
||||||
|
return {}
|
||||||
|
response_dossier_json = response_dossier.json()
|
||||||
|
if response_dossier_json['state']['totalItems'] == 0:
|
||||||
|
log.info(f"No dossier found for RML ID {rmlId}")
|
||||||
|
return {}
|
||||||
|
dossier_info = {
|
||||||
|
"lastUpdatedDate": response_dossier_json['items'][0]['lastUpdatedDate'],
|
||||||
|
"registrationStatus": response_dossier_json['items'][0]['registrationStatus'],
|
||||||
|
"registrationStatusChangedDate": response_dossier_json['items'][0]['registrationStatusChangedDate'],
|
||||||
|
"registrationRole": response_dossier_json['items'][0]['reachDossierInfo']['registrationRole'],
|
||||||
|
"assetExternalId": response_dossier_json['items'][0]['assetExternalId'],
|
||||||
|
"rootKey": response_dossier_json['items'][0]['rootKey']
|
||||||
|
}
|
||||||
|
return dossier_info
|
||||||
|
|
||||||
|
|
||||||
|
def get_substance_index(assetExternalId : str) -> dict:
|
||||||
|
INDEX = "https://chem.echa.europa.eu/html-pages-prod/" + assetExternalId
|
||||||
|
LINK_DOSSIER = INDEX + "/documents/"
|
||||||
|
|
||||||
|
response = requests.get(INDEX + "/index.html")
|
||||||
|
if response.status_code != 200:
|
||||||
|
log.error(f"Network error: {response.status_code}")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
soup = BeautifulSoup(response.content, 'html.parser')
|
||||||
|
index_data = {}
|
||||||
|
|
||||||
|
# Toxicological information : txi
|
||||||
|
|
||||||
|
txi_div = soup.find('div', id='id_7_Toxicologicalinformation')
|
||||||
|
txi_link = txi_div.find('a', class_='das-leaf')
|
||||||
|
txi_href = txi_link['href']
|
||||||
|
index_data['toxicological_information_link'] = LINK_DOSSIER + txi_href + '.html'
|
||||||
|
|
||||||
|
# Repeated dose toxicity : rdt
|
||||||
|
|
||||||
|
rdt_div = soup.find('div', id='id_75_Repeateddosetoxicity')
|
||||||
|
rdt_link = rdt_div.find('a', class_='das-leaf')
|
||||||
|
rdt_href = rdt_link['href']
|
||||||
|
index_data['repeated_dose_toxicity_link'] = LINK_DOSSIER + rdt_href + '.html'
|
||||||
|
|
||||||
|
# Acute toxicity : at
|
||||||
|
|
||||||
|
at_div = soup.find('div', id='id_72_AcuteToxicity')
|
||||||
|
at_link = at_div.find('a', class_='das-leaf')
|
||||||
|
at_href = at_link['href']
|
||||||
|
index_data['acute_toxicity_link'] = LINK_DOSSIER + at_href + '.html'
|
||||||
|
|
||||||
|
return index_data
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ECHA parsing functions of html pages
|
||||||
|
|
||||||
|
def get_field_name(field_div):
|
||||||
|
"""Extract field name from the class attribute of label div"""
|
||||||
|
label_div = field_div.find('div', class_='das-field_label')
|
||||||
|
if not label_div:
|
||||||
|
return None
|
||||||
|
|
||||||
|
classes = label_div.get('class', [])
|
||||||
|
|
||||||
|
for cls in classes:
|
||||||
|
if cls not in ['das-field_label', 'das-empty-value', 'das-empty-label']:
|
||||||
|
return cls
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def extract_field_value(field_div):
|
||||||
|
"""Extract value from a das-field div"""
|
||||||
|
field_name = get_field_name(field_div)
|
||||||
|
if not field_name:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Skip OriginalStudy fields
|
||||||
|
if field_name == 'OriginalStudy':
|
||||||
|
return None
|
||||||
|
|
||||||
|
value_div = field_div.find('div', class_='das-field_value')
|
||||||
|
if not value_div:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Exclude redacted/not publishable
|
||||||
|
redacted = value_div.find('span', class_='das-redacted-value')
|
||||||
|
if redacted:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Check if empty
|
||||||
|
empty_span = value_div.find('span', class_='das-empty-value')
|
||||||
|
if empty_span and not value_div.find('span', class_='das-redacted-value'):
|
||||||
|
return {field_name: ""}
|
||||||
|
|
||||||
|
# Extract pick-list value
|
||||||
|
pick_list = value_div.find('span', class_='das-field_value_pick-list')
|
||||||
|
if pick_list:
|
||||||
|
phrase = pick_list.find('span', class_='phrase')
|
||||||
|
if phrase:
|
||||||
|
return {field_name: phrase.get_text(strip=True)}
|
||||||
|
if pick_list.find('span', class_='das-empty-value'):
|
||||||
|
return {field_name: ""}
|
||||||
|
|
||||||
|
# Extract quantity value (value + unit)
|
||||||
|
quantity = value_div.find('span', class_='i6PhysicalQuantity')
|
||||||
|
if quantity:
|
||||||
|
value_span = quantity.find('span', class_='value')
|
||||||
|
unit_span = quantity.find('span', class_='unit')
|
||||||
|
|
||||||
|
value_text = value_span.get_text(strip=True) if value_span else ""
|
||||||
|
unit_text = ""
|
||||||
|
if unit_span:
|
||||||
|
unit_phrase = unit_span.find('span', class_='phrase')
|
||||||
|
if unit_phrase:
|
||||||
|
unit_text = unit_phrase.get_text(strip=True)
|
||||||
|
elif unit_span.find('span', class_='das-empty-value'):
|
||||||
|
unit_text = ""
|
||||||
|
|
||||||
|
if value_text:
|
||||||
|
return {field_name: {"value": value_text, "unit": unit_text}}
|
||||||
|
else:
|
||||||
|
return {field_name: ""}
|
||||||
|
|
||||||
|
# Extract checkbox value
|
||||||
|
checkbox_checked = value_div.find('span', class_='das-value_checkbox-checked')
|
||||||
|
checkbox_unchecked = value_div.find('span', class_='das-value_checkbox-unchecked')
|
||||||
|
if checkbox_checked is not None or checkbox_unchecked is not None:
|
||||||
|
return {field_name: checkbox_checked is not None}
|
||||||
|
|
||||||
|
# Extract decimal/numeric value
|
||||||
|
if 'das-field_decimal' in field_div.get('class', []) or 'das-field_text' in field_div.get('class', []):
|
||||||
|
text = value_div.get_text(strip=True)
|
||||||
|
if '[Empty]' in text or not text:
|
||||||
|
return {field_name: ""}
|
||||||
|
return {field_name: text}
|
||||||
|
|
||||||
|
# Extract HTML/text content
|
||||||
|
if value_div.find('div', class_='das-field_value_html'):
|
||||||
|
html_content = value_div.find('div', class_='das-field_value_html')
|
||||||
|
text = html_content.get_text(separator=' ', strip=True)
|
||||||
|
text = re.sub(r'\[Empty\]', '', text).strip()
|
||||||
|
if not text:
|
||||||
|
return {field_name: ""}
|
||||||
|
return {field_name: text}
|
||||||
|
|
||||||
|
# Default: get text content
|
||||||
|
text = value_div.get_text(strip=True)
|
||||||
|
text = re.sub(r'\[Empty\]', '', text).strip()
|
||||||
|
return {field_name: text if text else ""}
|
||||||
|
|
||||||
|
|
||||||
|
def extract_table_data(table):
|
||||||
|
"""Extract table data as array of objects"""
|
||||||
|
rows = table.find_all('tr')
|
||||||
|
if len(rows) < 2:
|
||||||
|
return []
|
||||||
|
|
||||||
|
header_row = rows[0]
|
||||||
|
headers = []
|
||||||
|
for th in header_row.find_all('td'):
|
||||||
|
header_text = th.get_text(strip=True)
|
||||||
|
headers.append(header_text)
|
||||||
|
|
||||||
|
data = []
|
||||||
|
for row in rows[1:]:
|
||||||
|
cells = row.find_all('td')
|
||||||
|
|
||||||
|
if len(cells) == 1 and cells[0].get('colspan'):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if len(cells) == len(headers):
|
||||||
|
row_data = {}
|
||||||
|
for i, cell in enumerate(cells):
|
||||||
|
cell_text = cell.get_text(strip=True)
|
||||||
|
row_data[headers[i]] = cell_text
|
||||||
|
data.append(row_data)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def extract_section(section):
|
||||||
|
"""Recursively extract data from a section"""
|
||||||
|
section_data = {}
|
||||||
|
|
||||||
|
label_h3 = section.find('h3', class_='das-block_label', recursive=False)
|
||||||
|
if label_h3:
|
||||||
|
section_data['label'] = label_h3.get_text(strip=True)
|
||||||
|
|
||||||
|
direct_fields = section.find_all('div', class_='das-field', recursive=False)
|
||||||
|
for field in direct_fields:
|
||||||
|
field_data = extract_field_value(field)
|
||||||
|
if field_data:
|
||||||
|
section_data.update(field_data)
|
||||||
|
|
||||||
|
tables = section.find_all('table', recursive=False)
|
||||||
|
for i, table in enumerate(tables):
|
||||||
|
table_data = extract_table_data(table)
|
||||||
|
if table_data:
|
||||||
|
table_key = f'table_{i+1}' if len(tables) > 1 else 'table'
|
||||||
|
section_data[table_key] = table_data
|
||||||
|
|
||||||
|
nested_sections = section.find_all('section', class_='das-block', recursive=False)
|
||||||
|
if nested_sections:
|
||||||
|
section_data['subsections'] = []
|
||||||
|
for nested in nested_sections:
|
||||||
|
nested_data = extract_section(nested)
|
||||||
|
if nested_data:
|
||||||
|
section_data['subsections'].append(nested_data)
|
||||||
|
|
||||||
|
return section_data
|
||||||
|
|
||||||
|
|
||||||
|
def parse_toxicology_html(html_content):
|
||||||
|
"""Main function to parse the toxicological HTML document"""
|
||||||
|
soup = BeautifulSoup(html_content, 'html.parser')
|
||||||
|
|
||||||
|
result = {}
|
||||||
|
|
||||||
|
title = soup.find('h4', class_='document-header')
|
||||||
|
if title:
|
||||||
|
result['document_title'] = title.get_text(strip=True)
|
||||||
|
|
||||||
|
article = soup.find('article', class_='das-document')
|
||||||
|
if not article:
|
||||||
|
return result
|
||||||
|
|
||||||
|
top_sections = article.find_all('section', class_='das-block', recursive=False)
|
||||||
|
result['sections'] = []
|
||||||
|
|
||||||
|
for section in top_sections:
|
||||||
|
section_data = extract_section(section)
|
||||||
|
if section_data:
|
||||||
|
result['sections'].append(section_data)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region PDF extraction functions
|
||||||
|
|
||||||
|
def generate_pdf_from_toxicology_info(index: dict):
|
||||||
|
with sync_playwright() as p:
|
||||||
|
browser = p.chromium.launch()
|
||||||
|
page = browser.new_page()
|
||||||
|
page.goto(index['toxicological_information_link'])
|
||||||
|
page.pdf(path=f'pdfs/{index["substance"]["rmlCas"]}.pdf')
|
||||||
|
browser.close()
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Orchestrator functions
|
||||||
|
|
||||||
|
def echa_flow(cas) -> dict:
|
||||||
|
try:
|
||||||
|
substance = search_substance(cas)
|
||||||
|
dossier_info = get_dossier_info(substance['rmlId'])
|
||||||
|
index = get_substance_index(dossier_info['assetExternalId'])
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f"Error in ECHA flow for CAS {cas}: {e}")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
result = {
|
||||||
|
"substance": substance,
|
||||||
|
"dossier_info": dossier_info,
|
||||||
|
"index": index,
|
||||||
|
"toxicological_information": {},
|
||||||
|
"acute_toxicity": {},
|
||||||
|
"repeated_dose_toxicity": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Fetch and parse toxicological information
|
||||||
|
txi_link = index.get('toxicological_information_link')
|
||||||
|
if txi_link:
|
||||||
|
response_summary = requests.get(txi_link)
|
||||||
|
if response_summary.status_code == 200:
|
||||||
|
result['toxicological_information'] = parse_toxicology_html(response_summary.content)
|
||||||
|
|
||||||
|
# Fetch and parse acute toxicity
|
||||||
|
at_link = index.get('acute_toxicity_link')
|
||||||
|
if at_link:
|
||||||
|
response_acute = requests.get(at_link)
|
||||||
|
if response_acute.status_code == 200:
|
||||||
|
result['acute_toxicity'] = parse_toxicology_html(response_acute.content)
|
||||||
|
|
||||||
|
# Fetch and parse repeated dose toxicity
|
||||||
|
rdt_link = index.get('repeated_dose_toxicity_link')
|
||||||
|
if rdt_link:
|
||||||
|
response_repeated = requests.get(rdt_link)
|
||||||
|
if response_repeated.status_code == 200:
|
||||||
|
result['repeated_dose_toxicity'] = parse_toxicology_html(response_repeated.content)
|
||||||
|
|
||||||
|
for key, value in result.items():
|
||||||
|
if value is None or value == "" or value == [] or value == {}:
|
||||||
|
return False
|
||||||
|
return result
|
||||||
|
|
||||||
|
def cas_validation(cas: str) -> str:
|
||||||
|
log.info(f"Starting ECHA data extraction for CAS: {cas}")
|
||||||
|
if cas is None or cas.strip() == "":
|
||||||
|
log.error("No CAS number provided.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
cas_stripped = cas.replace("-", "")
|
||||||
|
if cas_stripped.isdigit() and len(cas_stripped) <= 12:
|
||||||
|
log.info(f"CAS number {cas} maybe is valid.")
|
||||||
|
return cas.strip()
|
||||||
|
else:
|
||||||
|
log.error(f"CAS number {cas} is not valid.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def check_local(cas: str) -> bool:
|
||||||
|
client, db, collection = db_connect()
|
||||||
|
|
||||||
|
if not collection:
|
||||||
|
log.error("No MongoDB collection available.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
record = collection.find_one({"substance.rmlCas": cas})
|
||||||
|
|
||||||
|
if record:
|
||||||
|
log.info(f"Record for CAS {cas} found in local database.")
|
||||||
|
return record
|
||||||
|
else:
|
||||||
|
log.info(f"No record for CAS {cas} found in local database.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def add_to_local(data: dict) -> bool:
|
||||||
|
client, db, collection = db_connect()
|
||||||
|
|
||||||
|
if not collection:
|
||||||
|
log.error("No MongoDB collection available.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
collection.insert_one(data)
|
||||||
|
log.info(f"Data for CAS {data['substance']['rmlCas']} added to local database.")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f"Error inserting data into MongoDB: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def search_substance(cas: str) -> dict:
|
||||||
|
cas_validated = cas_validation(cas)
|
||||||
|
if not cas_validated:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
local_record = check_local(cas_validated)
|
||||||
|
if local_record:
|
||||||
|
return local_record
|
||||||
|
else:
|
||||||
|
echa_data = echa_flow(cas_validated)
|
||||||
|
if echa_data:
|
||||||
|
add_to_local(echa_data)
|
||||||
|
return echa_data
|
||||||
|
else:
|
||||||
|
log.error(f"Failed to retrieve ECHA data for CAS {cas}.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# to do: check if document is complete
|
||||||
|
# to do: check lastupdate
|
||||||
|
#endregion
|
||||||
312
uv.lock
312
uv.lock
|
|
@ -71,6 +71,61 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458 },
|
{ url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "brotli"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/2f/c2/f9e977608bdf958650638c3f1e28f85a1b075f075ebbe77db8555463787b/Brotli-1.1.0.tar.gz", hash = "sha256:81de08ac11bcb85841e440c13611c00b67d3bf82698314928d0b676362546724", size = 7372270 }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5c/d0/5373ae13b93fe00095a58efcbce837fd470ca39f703a235d2a999baadfbc/Brotli-1.1.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:32d95b80260d79926f5fab3c41701dbb818fde1c9da590e77e571eefd14abe28", size = 815693 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8e/48/f6e1cdf86751300c288c1459724bfa6917a80e30dbfc326f92cea5d3683a/Brotli-1.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b760c65308ff1e462f65d69c12e4ae085cff3b332d894637f6273a12a482d09f", size = 422489 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/06/88/564958cedce636d0f1bed313381dfc4b4e3d3f6015a63dae6146e1b8c65c/Brotli-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:316cc9b17edf613ac76b1f1f305d2a748f1b976b033b049a6ecdfd5612c70409", size = 873081 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/58/79/b7026a8bb65da9a6bb7d14329fd2bd48d2b7f86d7329d5cc8ddc6a90526f/Brotli-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:caf9ee9a5775f3111642d33b86237b05808dafcd6268faa492250e9b78046eb2", size = 446244 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e5/18/c18c32ecea41b6c0004e15606e274006366fe19436b6adccc1ae7b2e50c2/Brotli-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70051525001750221daa10907c77830bc889cb6d865cc0b813d9db7fefc21451", size = 2906505 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/08/c8/69ec0496b1ada7569b62d85893d928e865df29b90736558d6c98c2031208/Brotli-1.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7f4bf76817c14aa98cc6697ac02f3972cb8c3da93e9ef16b9c66573a68014f91", size = 2944152 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ab/fb/0517cea182219d6768113a38167ef6d4eb157a033178cc938033a552ed6d/Brotli-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0c5516f0aed654134a2fc936325cc2e642f8a0e096d075209672eb321cff408", size = 2919252 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c7/53/73a3431662e33ae61a5c80b1b9d2d18f58dfa910ae8dd696e57d39f1a2f5/Brotli-1.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c3020404e0b5eefd7c9485ccf8393cfb75ec38ce75586e046573c9dc29967a0", size = 2845955 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/55/ac/bd280708d9c5ebdbf9de01459e625a3e3803cce0784f47d633562cf40e83/Brotli-1.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:4ed11165dd45ce798d99a136808a794a748d5dc38511303239d4e2363c0695dc", size = 2914304 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/76/58/5c391b41ecfc4527d2cc3350719b02e87cb424ef8ba2023fb662f9bf743c/Brotli-1.1.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:4093c631e96fdd49e0377a9c167bfd75b6d0bad2ace734c6eb20b348bc3ea180", size = 2814452 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c7/4e/91b8256dfe99c407f174924b65a01f5305e303f486cc7a2e8a5d43c8bec3/Brotli-1.1.0-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e4c4629ddad63006efa0ef968c8e4751c5868ff0b1c5c40f76524e894c50248", size = 2938751 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5a/a6/e2a39a5d3b412938362bbbeba5af904092bf3f95b867b4a3eb856104074e/Brotli-1.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:861bf317735688269936f755fa136a99d1ed526883859f86e41a5d43c61d8966", size = 2933757 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/13/f0/358354786280a509482e0e77c1a5459e439766597d280f28cb097642fc26/Brotli-1.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:87a3044c3a35055527ac75e419dfa9f4f3667a1e887ee80360589eb8c90aabb9", size = 2936146 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/80/f7/daf538c1060d3a88266b80ecc1d1c98b79553b3f117a485653f17070ea2a/Brotli-1.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c5529b34c1c9d937168297f2c1fde7ebe9ebdd5e121297ff9c043bdb2ae3d6fb", size = 2848055 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ad/cf/0eaa0585c4077d3c2d1edf322d8e97aabf317941d3a72d7b3ad8bce004b0/Brotli-1.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ca63e1890ede90b2e4454f9a65135a4d387a4585ff8282bb72964fab893f2111", size = 3035102 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d8/63/1c1585b2aa554fe6dbce30f0c18bdbc877fa9a1bf5ff17677d9cca0ac122/Brotli-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e79e6520141d792237c70bcd7a3b122d00f2613769ae0cb61c52e89fd3443839", size = 2930029 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5f/3b/4e3fd1893eb3bbfef8e5a80d4508bec17a57bb92d586c85c12d28666bb13/Brotli-1.1.0-cp312-cp312-win32.whl", hash = "sha256:5f4d5ea15c9382135076d2fb28dde923352fe02951e66935a9efaac8f10e81b0", size = 333276 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3d/d5/942051b45a9e883b5b6e98c041698b1eb2012d25e5948c58d6bf85b1bb43/Brotli-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:906bc3a79de8c4ae5b86d3d75a8b77e44404b0f4261714306e3ad248d8ab0951", size = 357255 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0a/9f/fb37bb8ffc52a8da37b1c03c459a8cd55df7a57bdccd8831d500e994a0ca/Brotli-1.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8bf32b98b75c13ec7cf774164172683d6e7891088f6316e54425fde1efc276d5", size = 815681 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/06/b3/dbd332a988586fefb0aa49c779f59f47cae76855c2d00f450364bb574cac/Brotli-1.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7bc37c4d6b87fb1017ea28c9508b36bbcb0c3d18b4260fcdf08b200c74a6aee8", size = 422475 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bb/80/6aaddc2f63dbcf2d93c2d204e49c11a9ec93a8c7c63261e2b4bd35198283/Brotli-1.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c0ef38c7a7014ffac184db9e04debe495d317cc9c6fb10071f7fefd93100a4f", size = 2906173 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ea/1d/e6ca79c96ff5b641df6097d299347507d39a9604bde8915e76bf026d6c77/Brotli-1.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91d7cc2a76b5567591d12c01f019dd7afce6ba8cba6571187e21e2fc418ae648", size = 2943803 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ac/a3/d98d2472e0130b7dd3acdbb7f390d478123dbf62b7d32bda5c830a96116d/Brotli-1.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a93dde851926f4f2678e704fadeb39e16c35d8baebd5252c9fd94ce8ce68c4a0", size = 2918946 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c4/a5/c69e6d272aee3e1423ed005d8915a7eaa0384c7de503da987f2d224d0721/Brotli-1.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f0db75f47be8b8abc8d9e31bc7aad0547ca26f24a54e6fd10231d623f183d089", size = 2845707 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/58/9f/4149d38b52725afa39067350696c09526de0125ebfbaab5acc5af28b42ea/Brotli-1.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6967ced6730aed543b8673008b5a391c3b1076d834ca438bbd70635c73775368", size = 2936231 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5a/5a/145de884285611838a16bebfdb060c231c52b8f84dfbe52b852a15780386/Brotli-1.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7eedaa5d036d9336c95915035fb57422054014ebdeb6f3b42eac809928e40d0c", size = 2848157 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/50/ae/408b6bfb8525dadebd3b3dd5b19d631da4f7d46420321db44cd99dcf2f2c/Brotli-1.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d487f5432bf35b60ed625d7e1b448e2dc855422e87469e3f450aa5552b0eb284", size = 3035122 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/af/85/a94e5cfaa0ca449d8f91c3d6f78313ebf919a0dbd55a100c711c6e9655bc/Brotli-1.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:832436e59afb93e1836081a20f324cb185836c617659b07b129141a8426973c7", size = 2930206 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c2/f0/a61d9262cd01351df22e57ad7c34f66794709acab13f34be2675f45bf89d/Brotli-1.1.0-cp313-cp313-win32.whl", hash = "sha256:43395e90523f9c23a3d5bdf004733246fba087f2948f87ab28015f12359ca6a0", size = 333804 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7e/c1/ec214e9c94000d1c1974ec67ced1c970c148aa6b8d8373066123fc3dbf06/Brotli-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:9011560a466d2eb3f5a6e4929cf4a09be405c64154e12df0dd72713f6500e32b", size = 358517 },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "brotlicffi"
|
||||||
|
version = "1.1.0.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "cffi" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/95/9d/70caa61192f570fcf0352766331b735afa931b4c6bc9a348a0925cc13288/brotlicffi-1.1.0.0.tar.gz", hash = "sha256:b77827a689905143f87915310b93b273ab17888fd43ef350d4832c4a71083c13", size = 465192 }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a2/11/7b96009d3dcc2c931e828ce1e157f03824a69fb728d06bfd7b2fc6f93718/brotlicffi-1.1.0.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9b7ae6bd1a3f0df532b6d67ff674099a96d22bc0948955cb338488c31bfb8851", size = 453786 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d6/e6/a8f46f4a4ee7856fbd6ac0c6fb0dc65ed181ba46cd77875b8d9bbe494d9e/brotlicffi-1.1.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19ffc919fa4fc6ace69286e0a23b3789b4219058313cf9b45625016bf7ff996b", size = 2911165 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/be/20/201559dff14e83ba345a5ec03335607e47467b6633c210607e693aefac40/brotlicffi-1.1.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9feb210d932ffe7798ee62e6145d3a757eb6233aa9a4e7db78dd3690d7755814", size = 2927895 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cd/15/695b1409264143be3c933f708a3f81d53c4a1e1ebbc06f46331decbf6563/brotlicffi-1.1.0.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84763dbdef5dd5c24b75597a77e1b30c66604725707565188ba54bab4f114820", size = 2851834 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b4/40/b961a702463b6005baf952794c2e9e0099bde657d0d7e007f923883b907f/brotlicffi-1.1.0.0-cp37-abi3-win32.whl", hash = "sha256:1b12b50e07c3911e1efa3a8971543e7648100713d4e0971b13631cce22c587eb", size = 341731 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1c/fa/5408a03c041114ceab628ce21766a4ea882aa6f6f0a800e04ee3a30ec6b9/brotlicffi-1.1.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:994a4f0681bb6c6c3b0925530a1926b7a189d878e6e5e38fae8efa47c5d9c613", size = 366783 },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cachetools"
|
name = "cachetools"
|
||||||
version = "6.2.0"
|
version = "6.2.0"
|
||||||
|
|
@ -89,6 +144,63 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216 },
|
{ url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cffi"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "pycparser", marker = "implementation_name != 'PyPy'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588 }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195 },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "charset-normalizer"
|
name = "charset-normalizer"
|
||||||
version = "3.4.3"
|
version = "3.4.3"
|
||||||
|
|
@ -226,6 +338,19 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/ec/16/114df1c291c22cac3b0c127a73e0af5c12ed7bbb6558d310429a0ae24023/coverage-7.10.7-py3-none-any.whl", hash = "sha256:f7941f6f2fe6dd6807a1208737b8a0cbcf1cc6d7b07d24998ad2d63590868260", size = 209952 },
|
{ url = "https://files.pythonhosted.org/packages/ec/16/114df1c291c22cac3b0c127a73e0af5c12ed7bbb6558d310429a0ae24023/coverage-7.10.7-py3-none-any.whl", hash = "sha256:f7941f6f2fe6dd6807a1208737b8a0cbcf1cc6d7b07d24998ad2d63590868260", size = 209952 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cssselect2"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "tinycss2" },
|
||||||
|
{ name = "webencodings" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/9f/86/fd7f58fc498b3166f3a7e8e0cddb6e620fe1da35b02248b1bd59e95dbaaa/cssselect2-0.8.0.tar.gz", hash = "sha256:7674ffb954a3b46162392aee2a3a0aedb2e14ecf99fcc28644900f4e6e3e9d3a", size = 35716 }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0f/e7/aa315e6a749d9b96c2504a1ba0ba031ba2d0517e972ce22682e3fccecb09/cssselect2-0.8.0-py3-none-any.whl", hash = "sha256:46fc70ebc41ced7a32cd42d58b1884d72ade23d21e5a4eaaf022401c13f0e76e", size = 15454 },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dnspython"
|
name = "dnspython"
|
||||||
version = "2.8.0"
|
version = "2.8.0"
|
||||||
|
|
@ -244,6 +369,17 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/66/dd/f95350e853a4468ec37478414fc04ae2d61dad7a947b3015c3dcc51a09b9/docutils-0.22.2-py3-none-any.whl", hash = "sha256:b0e98d679283fc3bb0ead8a5da7f501baa632654e7056e9c5846842213d674d8", size = 632667 },
|
{ url = "https://files.pythonhosted.org/packages/66/dd/f95350e853a4468ec37478414fc04ae2d61dad7a947b3015c3dcc51a09b9/docutils-0.22.2-py3-none-any.whl", hash = "sha256:b0e98d679283fc3bb0ead8a5da7f501baa632654e7056e9c5846842213d674d8", size = 632667 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dotenv"
|
||||||
|
version = "0.9.9"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "python-dotenv" },
|
||||||
|
]
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b2/b7/545d2c10c1fc15e48653c91efde329a790f2eecfbbf2bd16003b5db2bab0/dotenv-0.9.9-py2.py3-none-any.whl", hash = "sha256:29cf74a087b31dafdb5a446b6d7e11cbce8ed2741540e2339c69fbef92c94ce9", size = 1892 },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "duckdb"
|
name = "duckdb"
|
||||||
version = "1.4.1"
|
version = "1.4.1"
|
||||||
|
|
@ -264,6 +400,54 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/30/79/4f544d73fcc0513b71296cb3ebb28a227d22e80dec27204977039b9fa875/duckdb-1.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:280fd663dacdd12bb3c3bf41f3e5b2e5b95e00b88120afabb8b8befa5f335c6f", size = 12336460 },
|
{ url = "https://files.pythonhosted.org/packages/30/79/4f544d73fcc0513b71296cb3ebb28a227d22e80dec27204977039b9fa875/duckdb-1.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:280fd663dacdd12bb3c3bf41f3e5b2e5b95e00b88120afabb8b8befa5f335c6f", size = 12336460 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fonttools"
|
||||||
|
version = "4.60.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/4b/42/97a13e47a1e51a5a7142475bbcf5107fe3a68fc34aef331c897d5fb98ad0/fonttools-4.60.1.tar.gz", hash = "sha256:ef00af0439ebfee806b25f24c8f92109157ff3fac5731dc7867957812e87b8d9", size = 3559823 }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e3/f7/a10b101b7a6f8836a5adb47f2791f2075d044a6ca123f35985c42edc82d8/fonttools-4.60.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:7b0c6d57ab00dae9529f3faf187f2254ea0aa1e04215cf2f1a8ec277c96661bc", size = 2832953 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ed/fe/7bd094b59c926acf2304d2151354ddbeb74b94812f3dc943c231db09cb41/fonttools-4.60.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:839565cbf14645952d933853e8ade66a463684ed6ed6c9345d0faf1f0e868877", size = 2352706 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c0/ca/4bb48a26ed95a1e7eba175535fe5805887682140ee0a0d10a88e1de84208/fonttools-4.60.1-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8177ec9676ea6e1793c8a084a90b65a9f778771998eb919d05db6d4b1c0b114c", size = 4923716 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b8/9f/2cb82999f686c1d1ddf06f6ae1a9117a880adbec113611cc9d22b2fdd465/fonttools-4.60.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:996a4d1834524adbb423385d5a629b868ef9d774670856c63c9a0408a3063401", size = 4968175 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/18/79/be569699e37d166b78e6218f2cde8c550204f2505038cdd83b42edc469b9/fonttools-4.60.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a46b2f450bc79e06ef3b6394f0c68660529ed51692606ad7f953fc2e448bc903", size = 4911031 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cc/9f/89411cc116effaec5260ad519162f64f9c150e5522a27cbb05eb62d0c05b/fonttools-4.60.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6ec722ee589e89a89f5b7574f5c45604030aa6ae24cb2c751e2707193b466fed", size = 5062966 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/62/a1/f888221934b5731d46cb9991c7a71f30cb1f97c0ef5fcf37f8da8fce6c8e/fonttools-4.60.1-cp312-cp312-win32.whl", hash = "sha256:b2cf105cee600d2de04ca3cfa1f74f1127f8455b71dbad02b9da6ec266e116d6", size = 2218750 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/88/8f/a55b5550cd33cd1028601df41acd057d4be20efa5c958f417b0c0613924d/fonttools-4.60.1-cp312-cp312-win_amd64.whl", hash = "sha256:992775c9fbe2cf794786fa0ffca7f09f564ba3499b8fe9f2f80bd7197db60383", size = 2267026 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7c/5b/cdd2c612277b7ac7ec8c0c9bc41812c43dc7b2d5f2b0897e15fdf5a1f915/fonttools-4.60.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6f68576bb4bbf6060c7ab047b1574a1ebe5c50a17de62830079967b211059ebb", size = 2825777 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d6/8a/de9cc0540f542963ba5e8f3a1f6ad48fa211badc3177783b9d5cadf79b5d/fonttools-4.60.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:eedacb5c5d22b7097482fa834bda0dafa3d914a4e829ec83cdea2a01f8c813c4", size = 2348080 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2d/8b/371ab3cec97ee3fe1126b3406b7abd60c8fec8975fd79a3c75cdea0c3d83/fonttools-4.60.1-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b33a7884fabd72bdf5f910d0cf46be50dce86a0362a65cfc746a4168c67eb96c", size = 4903082 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/05/06b1455e4bc653fcb2117ac3ef5fa3a8a14919b93c60742d04440605d058/fonttools-4.60.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2409d5fb7b55fd70f715e6d34e7a6e4f7511b8ad29a49d6df225ee76da76dd77", size = 4960125 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8e/37/f3b840fcb2666f6cb97038793606bdd83488dca2d0b0fc542ccc20afa668/fonttools-4.60.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c8651e0d4b3bdeda6602b85fdc2abbefc1b41e573ecb37b6779c4ca50753a199", size = 4901454 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fd/9e/eb76f77e82f8d4a46420aadff12cec6237751b0fb9ef1de373186dcffb5f/fonttools-4.60.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:145daa14bf24824b677b9357c5e44fd8895c2a8f53596e1b9ea3496081dc692c", size = 5044495 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f8/b3/cede8f8235d42ff7ae891bae8d619d02c8ac9fd0cfc450c5927a6200c70d/fonttools-4.60.1-cp313-cp313-win32.whl", hash = "sha256:2299df884c11162617a66b7c316957d74a18e3758c0274762d2cc87df7bc0272", size = 2217028 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/75/4d/b022c1577807ce8b31ffe055306ec13a866f2337ecee96e75b24b9b753ea/fonttools-4.60.1-cp313-cp313-win_amd64.whl", hash = "sha256:a3db56f153bd4c5c2b619ab02c5db5192e222150ce5a1bc10f16164714bc39ac", size = 2266200 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9a/83/752ca11c1aa9a899b793a130f2e466b79ea0cf7279c8d79c178fc954a07b/fonttools-4.60.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:a884aef09d45ba1206712c7dbda5829562d3fea7726935d3289d343232ecb0d3", size = 2822830 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/57/17/bbeab391100331950a96ce55cfbbff27d781c1b85ebafb4167eae50d9fe3/fonttools-4.60.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8a44788d9d91df72d1a5eac49b31aeb887a5f4aab761b4cffc4196c74907ea85", size = 2345524 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3d/2e/d4831caa96d85a84dd0da1d9f90d81cec081f551e0ea216df684092c6c97/fonttools-4.60.1-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e852d9dda9f93ad3651ae1e3bb770eac544ec93c3807888798eccddf84596537", size = 4843490 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/49/13/5e2ea7c7a101b6fc3941be65307ef8df92cbbfa6ec4804032baf1893b434/fonttools-4.60.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:154cb6ee417e417bf5f7c42fe25858c9140c26f647c7347c06f0cc2d47eff003", size = 4944184 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0c/2b/cf9603551c525b73fc47c52ee0b82a891579a93d9651ed694e4e2cd08bb8/fonttools-4.60.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:5664fd1a9ea7f244487ac8f10340c4e37664675e8667d6fee420766e0fb3cf08", size = 4890218 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fd/2f/933d2352422e25f2376aae74f79eaa882a50fb3bfef3c0d4f50501267101/fonttools-4.60.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:583b7f8e3c49486e4d489ad1deacfb8d5be54a8ef34d6df824f6a171f8511d99", size = 4999324 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/38/99/234594c0391221f66216bc2c886923513b3399a148defaccf81dc3be6560/fonttools-4.60.1-cp314-cp314-win32.whl", hash = "sha256:66929e2ea2810c6533a5184f938502cfdaea4bc3efb7130d8cc02e1c1b4108d6", size = 2220861 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3e/1d/edb5b23726dde50fc4068e1493e4fc7658eeefcaf75d4c5ffce067d07ae5/fonttools-4.60.1-cp314-cp314-win_amd64.whl", hash = "sha256:f3d5be054c461d6a2268831f04091dc82753176f6ea06dc6047a5e168265a987", size = 2270934 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fb/da/1392aaa2170adc7071fe7f9cfd181a5684a7afcde605aebddf1fb4d76df5/fonttools-4.60.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:b6379e7546ba4ae4b18f8ae2b9bc5960936007a1c0e30b342f662577e8bc3299", size = 2894340 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bf/a7/3b9f16e010d536ce567058b931a20b590d8f3177b2eda09edd92e392375d/fonttools-4.60.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9d0ced62b59e0430b3690dbc5373df1c2aa7585e9a8ce38eff87f0fd993c5b01", size = 2375073 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9b/b5/e9bcf51980f98e59bb5bb7c382a63c6f6cac0eec5f67de6d8f2322382065/fonttools-4.60.1-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:875cb7764708b3132637f6c5fb385b16eeba0f7ac9fa45a69d35e09b47045801", size = 4849758 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e3/dc/1d2cf7d1cba82264b2f8385db3f5960e3d8ce756b4dc65b700d2c496f7e9/fonttools-4.60.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a184b2ea57b13680ab6d5fbde99ccef152c95c06746cb7718c583abd8f945ccc", size = 5085598 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5d/4d/279e28ba87fb20e0c69baf72b60bbf1c4d873af1476806a7b5f2b7fac1ff/fonttools-4.60.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:026290e4ec76583881763fac284aca67365e0be9f13a7fb137257096114cb3bc", size = 4957603 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/78/d4/ff19976305e0c05aa3340c805475abb00224c954d3c65e82c0a69633d55d/fonttools-4.60.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f0e8817c7d1a0c2eedebf57ef9a9896f3ea23324769a9a2061a80fe8852705ed", size = 4974184 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/63/22/8553ff6166f5cd21cfaa115aaacaa0dc73b91c079a8cfd54a482cbc0f4f5/fonttools-4.60.1-cp314-cp314t-win32.whl", hash = "sha256:1410155d0e764a4615774e5c2c6fc516259fe3eca5882f034eb9bfdbee056259", size = 2282241 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8a/cb/fa7b4d148e11d5a72761a22e595344133e83a9507a4c231df972e657579b/fonttools-4.60.1-cp314-cp314t-win_amd64.whl", hash = "sha256:022beaea4b73a70295b688f817ddc24ed3e3418b5036ffcd5658141184ef0d0c", size = 2345760 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c7/93/0dd45cd283c32dea1545151d8c3637b4b8c53cdb3a625aeb2885b184d74d/fonttools-4.60.1-py3-none-any.whl", hash = "sha256:906306ac7afe2156fcf0042173d6ebbb05416af70f6b370967b47f8f00103bbb", size = 1143175 },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.optional-dependencies]
|
||||||
|
woff = [
|
||||||
|
{ name = "brotli", marker = "platform_python_implementation == 'CPython'" },
|
||||||
|
{ name = "brotlicffi", marker = "platform_python_implementation != 'CPython'" },
|
||||||
|
{ name = "zopfli" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gitdb"
|
name = "gitdb"
|
||||||
version = "4.0.12"
|
version = "4.0.12"
|
||||||
|
|
@ -302,6 +486,8 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/19/0d/6660d55f7373b2ff8152401a83e02084956da23ae58cddbfb0b330978fe9/greenlet-3.2.4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b3812d8d0c9579967815af437d96623f45c0f2ae5f04e366de62a12d83a8fb0", size = 607586 },
|
{ url = "https://files.pythonhosted.org/packages/19/0d/6660d55f7373b2ff8152401a83e02084956da23ae58cddbfb0b330978fe9/greenlet-3.2.4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b3812d8d0c9579967815af437d96623f45c0f2ae5f04e366de62a12d83a8fb0", size = 607586 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/8e/1a/c953fdedd22d81ee4629afbb38d2f9d71e37d23caace44775a3a969147d4/greenlet-3.2.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:abbf57b5a870d30c4675928c37278493044d7c14378350b3aa5d484fa65575f0", size = 1123281 },
|
{ url = "https://files.pythonhosted.org/packages/8e/1a/c953fdedd22d81ee4629afbb38d2f9d71e37d23caace44775a3a969147d4/greenlet-3.2.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:abbf57b5a870d30c4675928c37278493044d7c14378350b3aa5d484fa65575f0", size = 1123281 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/3f/c7/12381b18e21aef2c6bd3a636da1088b888b97b7a0362fac2e4de92405f97/greenlet-3.2.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:20fb936b4652b6e307b8f347665e2c615540d4b42b3b4c8a321d8286da7e520f", size = 1151142 },
|
{ url = "https://files.pythonhosted.org/packages/3f/c7/12381b18e21aef2c6bd3a636da1088b888b97b7a0362fac2e4de92405f97/greenlet-3.2.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:20fb936b4652b6e307b8f347665e2c615540d4b42b3b4c8a321d8286da7e520f", size = 1151142 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/27/45/80935968b53cfd3f33cf99ea5f08227f2646e044568c9b1555b58ffd61c2/greenlet-3.2.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ee7a6ec486883397d70eec05059353b8e83eca9168b9f3f9a361971e77e0bcd0", size = 1564846 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/69/02/b7c30e5e04752cb4db6202a3858b149c0710e5453b71a3b2aec5d78a1aab/greenlet-3.2.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:326d234cbf337c9c3def0676412eb7040a35a768efc92504b947b3e9cfc7543d", size = 1633814 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e9/08/b0814846b79399e585f974bbeebf5580fbe59e258ea7be64d9dfb253c84f/greenlet-3.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:a7d4e128405eea3814a12cc2605e0e6aedb4035bf32697f72deca74de4105e02", size = 299899 },
|
{ url = "https://files.pythonhosted.org/packages/e9/08/b0814846b79399e585f974bbeebf5580fbe59e258ea7be64d9dfb253c84f/greenlet-3.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:a7d4e128405eea3814a12cc2605e0e6aedb4035bf32697f72deca74de4105e02", size = 299899 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/49/e8/58c7f85958bda41dafea50497cbd59738c5c43dbbea5ee83d651234398f4/greenlet-3.2.4-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:1a921e542453fe531144e91e1feedf12e07351b1cf6c9e8a3325ea600a715a31", size = 272814 },
|
{ url = "https://files.pythonhosted.org/packages/49/e8/58c7f85958bda41dafea50497cbd59738c5c43dbbea5ee83d651234398f4/greenlet-3.2.4-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:1a921e542453fe531144e91e1feedf12e07351b1cf6c9e8a3325ea600a715a31", size = 272814 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/62/dd/b9f59862e9e257a16e4e610480cfffd29e3fae018a68c2332090b53aac3d/greenlet-3.2.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd3c8e693bff0fff6ba55f140bf390fa92c994083f838fece0f63be121334945", size = 641073 },
|
{ url = "https://files.pythonhosted.org/packages/62/dd/b9f59862e9e257a16e4e610480cfffd29e3fae018a68c2332090b53aac3d/greenlet-3.2.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd3c8e693bff0fff6ba55f140bf390fa92c994083f838fece0f63be121334945", size = 641073 },
|
||||||
|
|
@ -311,6 +497,8 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/ee/43/3cecdc0349359e1a527cbf2e3e28e5f8f06d3343aaf82ca13437a9aa290f/greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23768528f2911bcd7e475210822ffb5254ed10d71f4028387e5a99b4c6699671", size = 610497 },
|
{ url = "https://files.pythonhosted.org/packages/ee/43/3cecdc0349359e1a527cbf2e3e28e5f8f06d3343aaf82ca13437a9aa290f/greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23768528f2911bcd7e475210822ffb5254ed10d71f4028387e5a99b4c6699671", size = 610497 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b8/19/06b6cf5d604e2c382a6f31cafafd6f33d5dea706f4db7bdab184bad2b21d/greenlet-3.2.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:00fadb3fedccc447f517ee0d3fd8fe49eae949e1cd0f6a611818f4f6fb7dc83b", size = 1121662 },
|
{ url = "https://files.pythonhosted.org/packages/b8/19/06b6cf5d604e2c382a6f31cafafd6f33d5dea706f4db7bdab184bad2b21d/greenlet-3.2.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:00fadb3fedccc447f517ee0d3fd8fe49eae949e1cd0f6a611818f4f6fb7dc83b", size = 1121662 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/a2/15/0d5e4e1a66fab130d98168fe984c509249c833c1a3c16806b90f253ce7b9/greenlet-3.2.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d25c5091190f2dc0eaa3f950252122edbbadbb682aa7b1ef2f8af0f8c0afefae", size = 1149210 },
|
{ url = "https://files.pythonhosted.org/packages/a2/15/0d5e4e1a66fab130d98168fe984c509249c833c1a3c16806b90f253ce7b9/greenlet-3.2.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d25c5091190f2dc0eaa3f950252122edbbadbb682aa7b1ef2f8af0f8c0afefae", size = 1149210 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1c/53/f9c440463b3057485b8594d7a638bed53ba531165ef0ca0e6c364b5cc807/greenlet-3.2.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e343822feb58ac4d0a1211bd9399de2b3a04963ddeec21530fc426cc121f19b", size = 1564759 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/47/e4/3bb4240abdd0a8d23f4f88adec746a3099f0d86bfedb623f063b2e3b4df0/greenlet-3.2.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca7f6f1f2649b89ce02f6f229d7c19f680a6238af656f61e0115b24857917929", size = 1634288 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/0b/55/2321e43595e6801e105fcfdee02b34c0f996eb71e6ddffca6b10b7e1d771/greenlet-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b", size = 299685 },
|
{ url = "https://files.pythonhosted.org/packages/0b/55/2321e43595e6801e105fcfdee02b34c0f996eb71e6ddffca6b10b7e1d771/greenlet-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b", size = 299685 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/22/5c/85273fd7cc388285632b0498dbbab97596e04b154933dfe0f3e68156c68c/greenlet-3.2.4-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:49a30d5fda2507ae77be16479bdb62a660fa51b1eb4928b524975b3bde77b3c0", size = 273586 },
|
{ url = "https://files.pythonhosted.org/packages/22/5c/85273fd7cc388285632b0498dbbab97596e04b154933dfe0f3e68156c68c/greenlet-3.2.4-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:49a30d5fda2507ae77be16479bdb62a660fa51b1eb4928b524975b3bde77b3c0", size = 273586 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d1/75/10aeeaa3da9332c2e761e4c50d4c3556c21113ee3f0afa2cf5769946f7a3/greenlet-3.2.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:299fd615cd8fc86267b47597123e3f43ad79c9d8a22bebdce535e53550763e2f", size = 686346 },
|
{ url = "https://files.pythonhosted.org/packages/d1/75/10aeeaa3da9332c2e761e4c50d4c3556c21113ee3f0afa2cf5769946f7a3/greenlet-3.2.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:299fd615cd8fc86267b47597123e3f43ad79c9d8a22bebdce535e53550763e2f", size = 686346 },
|
||||||
|
|
@ -318,6 +506,8 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/dc/8b/29aae55436521f1d6f8ff4e12fb676f3400de7fcf27fccd1d4d17fd8fecd/greenlet-3.2.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b4a1870c51720687af7fa3e7cda6d08d801dae660f75a76f3845b642b4da6ee1", size = 694659 },
|
{ url = "https://files.pythonhosted.org/packages/dc/8b/29aae55436521f1d6f8ff4e12fb676f3400de7fcf27fccd1d4d17fd8fecd/greenlet-3.2.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b4a1870c51720687af7fa3e7cda6d08d801dae660f75a76f3845b642b4da6ee1", size = 694659 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/92/2e/ea25914b1ebfde93b6fc4ff46d6864564fba59024e928bdc7de475affc25/greenlet-3.2.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:061dc4cf2c34852b052a8620d40f36324554bc192be474b9e9770e8c042fd735", size = 695355 },
|
{ url = "https://files.pythonhosted.org/packages/92/2e/ea25914b1ebfde93b6fc4ff46d6864564fba59024e928bdc7de475affc25/greenlet-3.2.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:061dc4cf2c34852b052a8620d40f36324554bc192be474b9e9770e8c042fd735", size = 695355 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/72/60/fc56c62046ec17f6b0d3060564562c64c862948c9d4bc8aa807cf5bd74f4/greenlet-3.2.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44358b9bf66c8576a9f57a590d5f5d6e72fa4228b763d0e43fee6d3b06d3a337", size = 657512 },
|
{ url = "https://files.pythonhosted.org/packages/72/60/fc56c62046ec17f6b0d3060564562c64c862948c9d4bc8aa807cf5bd74f4/greenlet-3.2.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44358b9bf66c8576a9f57a590d5f5d6e72fa4228b763d0e43fee6d3b06d3a337", size = 657512 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/23/6e/74407aed965a4ab6ddd93a7ded3180b730d281c77b765788419484cdfeef/greenlet-3.2.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2917bdf657f5859fbf3386b12d68ede4cf1f04c90c3a6bc1f013dd68a22e2269", size = 1612508 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0d/da/343cd760ab2f92bac1845ca07ee3faea9fe52bee65f7bcb19f16ad7de08b/greenlet-3.2.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:015d48959d4add5d6c9f6c5210ee3803a830dce46356e3bc326d6776bde54681", size = 1680760 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e3/a5/6ddab2b4c112be95601c13428db1d8b6608a8b6039816f2ba09c346c08fc/greenlet-3.2.4-cp314-cp314-win_amd64.whl", hash = "sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01", size = 303425 },
|
{ url = "https://files.pythonhosted.org/packages/e3/a5/6ddab2b4c112be95601c13428db1d8b6608a8b6039816f2ba09c346c08fc/greenlet-3.2.4-cp314-cp314-win_amd64.whl", hash = "sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01", size = 303425 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -745,6 +935,7 @@ version = "0.1.0"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "beautifulsoup4" },
|
{ name = "beautifulsoup4" },
|
||||||
|
{ name = "dotenv" },
|
||||||
{ name = "duckdb" },
|
{ name = "duckdb" },
|
||||||
{ name = "marimo" },
|
{ name = "marimo" },
|
||||||
{ name = "markdown-to-json" },
|
{ name = "markdown-to-json" },
|
||||||
|
|
@ -757,13 +948,16 @@ dependencies = [
|
||||||
{ name = "pytest" },
|
{ name = "pytest" },
|
||||||
{ name = "pytest-cov" },
|
{ name = "pytest-cov" },
|
||||||
{ name = "pytest-mock" },
|
{ name = "pytest-mock" },
|
||||||
|
{ name = "python-dotenv" },
|
||||||
{ name = "requests" },
|
{ name = "requests" },
|
||||||
{ name = "streamlit" },
|
{ name = "streamlit" },
|
||||||
|
{ name = "weasyprint" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [
|
requires-dist = [
|
||||||
{ name = "beautifulsoup4", specifier = ">=4.14.2" },
|
{ name = "beautifulsoup4", specifier = ">=4.14.2" },
|
||||||
|
{ name = "dotenv", specifier = ">=0.9.9" },
|
||||||
{ name = "duckdb", specifier = ">=1.4.1" },
|
{ name = "duckdb", specifier = ">=1.4.1" },
|
||||||
{ name = "marimo", specifier = ">=0.16.5" },
|
{ name = "marimo", specifier = ">=0.16.5" },
|
||||||
{ name = "markdown-to-json", specifier = ">=2.1.2" },
|
{ name = "markdown-to-json", specifier = ">=2.1.2" },
|
||||||
|
|
@ -776,8 +970,10 @@ requires-dist = [
|
||||||
{ name = "pytest", specifier = ">=8.4.2" },
|
{ name = "pytest", specifier = ">=8.4.2" },
|
||||||
{ name = "pytest-cov", specifier = ">=7.0.0" },
|
{ name = "pytest-cov", specifier = ">=7.0.0" },
|
||||||
{ name = "pytest-mock", specifier = ">=3.15.1" },
|
{ name = "pytest-mock", specifier = ">=3.15.1" },
|
||||||
|
{ name = "python-dotenv", specifier = ">=1.2.1" },
|
||||||
{ name = "requests", specifier = ">=2.32.5" },
|
{ name = "requests", specifier = ">=2.32.5" },
|
||||||
{ name = "streamlit", specifier = ">=1.50.0" },
|
{ name = "streamlit", specifier = ">=1.50.0" },
|
||||||
|
{ name = "weasyprint", specifier = ">=66.0" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -948,6 +1144,15 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/e5/4e/519c1bc1876625fe6b71e9a28287c43ec2f20f73c658b9ae1d485c0c206e/pyarrow-21.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:222c39e2c70113543982c6b34f3077962b44fca38c0bd9e68bb6781534425c10", size = 26371006 },
|
{ url = "https://files.pythonhosted.org/packages/e5/4e/519c1bc1876625fe6b71e9a28287c43ec2f20f73c658b9ae1d485c0c206e/pyarrow-21.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:222c39e2c70113543982c6b34f3077962b44fca38c0bd9e68bb6781534425c10", size = 26371006 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pycparser"
|
||||||
|
version = "2.23"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734 }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140 },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pydantic"
|
name = "pydantic"
|
||||||
version = "2.11.10"
|
version = "2.11.10"
|
||||||
|
|
@ -1018,6 +1223,15 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/ab/4c/b888e6cf58bd9db9c93f40d1c6be8283ff49d88919231afe93a6bcf61626/pydeck-0.9.1-py2.py3-none-any.whl", hash = "sha256:b3f75ba0d273fc917094fa61224f3f6076ca8752b93d46faf3bcfd9f9d59b038", size = 6900403 },
|
{ url = "https://files.pythonhosted.org/packages/ab/4c/b888e6cf58bd9db9c93f40d1c6be8283ff49d88919231afe93a6bcf61626/pydeck-0.9.1-py2.py3-none-any.whl", hash = "sha256:b3f75ba0d273fc917094fa61224f3f6076ca8752b93d46faf3bcfd9f9d59b038", size = 6900403 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pydyf"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/2e/c2/97fc6ce4ce0045080dc99446def812081b57750ed8aa67bfdfafa4561fe5/pydyf-0.11.0.tar.gz", hash = "sha256:394dddf619cca9d0c55715e3c55ea121a9bf9cbc780cdc1201a2427917b86b64", size = 17769 }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c9/ac/d5db977deaf28c6ecbc61bbca269eb3e8f0b3a1f55c8549e5333e606e005/pydyf-0.11.0-py3-none-any.whl", hash = "sha256:0aaf9e2ebbe786ec7a78ec3fbffa4cdcecde53fd6f563221d53c6bc1328848a3", size = 8104 },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyee"
|
name = "pyee"
|
||||||
version = "13.0.0"
|
version = "13.0.0"
|
||||||
|
|
@ -1103,6 +1317,15 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/19/99/f8fc04ae46fbf721b2935c59f3542810e72f50a4cb5b8aa092b6246a643f/pymongo-4.15.2-cp314-cp314t-win_arm64.whl", hash = "sha256:2c816a9e9d4aaaa0e4e9fb2534b72957666d262f3ce874a0408f8b925cfd4d99", size = 1050833 },
|
{ url = "https://files.pythonhosted.org/packages/19/99/f8fc04ae46fbf721b2935c59f3542810e72f50a4cb5b8aa092b6246a643f/pymongo-4.15.2-cp314-cp314t-win_arm64.whl", hash = "sha256:2c816a9e9d4aaaa0e4e9fb2534b72957666d262f3ce874a0408f8b925cfd4d99", size = 1050833 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyphen"
|
||||||
|
version = "0.17.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/69/56/e4d7e1bd70d997713649c5ce530b2d15a5fc2245a74ca820fc2d51d89d4d/pyphen-0.17.2.tar.gz", hash = "sha256:f60647a9c9b30ec6c59910097af82bc5dd2d36576b918e44148d8b07ef3b4aa3", size = 2079470 }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7b/1f/c2142d2edf833a90728e5cdeb10bdbdc094dde8dbac078cee0cf33f5e11b/pyphen-0.17.2-py3-none-any.whl", hash = "sha256:3a07fb017cb2341e1d9ff31b8634efb1ae4dc4b130468c7c39dd3d32e7c3affd", size = 2079358 },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pytest"
|
name = "pytest"
|
||||||
version = "8.4.2"
|
version = "8.4.2"
|
||||||
|
|
@ -1157,6 +1380,15 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 },
|
{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "python-dotenv"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221 }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230 },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pytz"
|
name = "pytz"
|
||||||
version = "2025.2"
|
version = "2025.2"
|
||||||
|
|
@ -1409,6 +1641,30 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248 },
|
{ url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinycss2"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "webencodings" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085 }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610 },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyhtml5"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "webencodings" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/fd/03/6111ed99e9bf7dfa1c30baeef0e0fb7e0bd387bd07f8e5b270776fe1de3f/tinyhtml5-2.0.0.tar.gz", hash = "sha256:086f998833da24c300c414d9fe81d9b368fd04cb9d2596a008421cbc705fcfcc", size = 179507 }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5c/de/27c57899297163a4a84104d5cec0af3b1ac5faf62f44667e506373c6b8ce/tinyhtml5-2.0.0-py3-none-any.whl", hash = "sha256:13683277c5b176d070f82d099d977194b7a1e26815b016114f581a74bbfbf47e", size = 39793 },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.10.2"
|
version = "0.10.2"
|
||||||
|
|
@ -1516,6 +1772,34 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067 },
|
{ url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "weasyprint"
|
||||||
|
version = "66.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "cffi" },
|
||||||
|
{ name = "cssselect2" },
|
||||||
|
{ name = "fonttools", extra = ["woff"] },
|
||||||
|
{ name = "pillow" },
|
||||||
|
{ name = "pydyf" },
|
||||||
|
{ name = "pyphen" },
|
||||||
|
{ name = "tinycss2" },
|
||||||
|
{ name = "tinyhtml5" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/32/99/480b5430b7eb0916e7d5df1bee7d9508b28b48fee28da894d0a050e0e930/weasyprint-66.0.tar.gz", hash = "sha256:da71dc87dc129ac9cffdc65e5477e90365ab9dbae45c744014ec1d06303dde40", size = 504224 }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0f/d1/c5d9b341bf3d556c1e4c6566b3efdda0b1bb175510aa7b09dd3eee246923/weasyprint-66.0-py3-none-any.whl", hash = "sha256:82b0783b726fcd318e2c977dcdddca76515b30044bc7a830cc4fbe717582a6d0", size = 301965 },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "webencodings"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721 }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774 },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "websockets"
|
name = "websockets"
|
||||||
version = "15.0.1"
|
version = "15.0.1"
|
||||||
|
|
@ -1546,3 +1830,31 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837 },
|
{ url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743 },
|
{ url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zopfli"
|
||||||
|
version = "0.2.3.post1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/5e/7c/a8f6696e694709e2abcbccd27d05ef761e9b6efae217e11d977471555b62/zopfli-0.2.3.post1.tar.gz", hash = "sha256:96484dc0f48be1c5d7ae9f38ed1ce41e3675fd506b27c11a6607f14b49101e99", size = 175629 }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3f/ce/b6441cc01881d06e0b5883f32c44e7cc9772e0d04e3e59277f59f80b9a19/zopfli-0.2.3.post1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3f0197b6aa6eb3086ae9e66d6dd86c4d502b6c68b0ec490496348ae8c05ecaef", size = 295489 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/93/f0/24dd708f00ae0a925bc5c9edae858641c80f6a81a516810dc4d21688a930/zopfli-0.2.3.post1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5fcfc0dc2761e4fcc15ad5d273b4d58c2e8e059d3214a7390d4d3c8e2aee644e", size = 163010 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/65/57/0378eeeb5e3e1e83b1b0958616b2bf954f102ba5b0755b9747dafbd8cb72/zopfli-0.2.3.post1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cac2b37ab21c2b36a10b685b1893ebd6b0f83ae26004838ac817680881576567", size = 823649 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ab/8a/3ab8a616d4655acf5cf63c40ca84e434289d7d95518a1a42d28b4a7228f8/zopfli-0.2.3.post1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d5ab297d660b75c159190ce6d73035502310e40fd35170aed7d1a1aea7ddd65", size = 826557 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ed/4d/7f6820af119c4fec6efaf007bffee7bc9052f695853a711a951be7afd26b/zopfli-0.2.3.post1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ba214f4f45bec195ee8559651154d3ac2932470b9d91c5715fc29c013349f8c", size = 851127 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e1/db/1ef5353ab06f9f2fb0c25ed0cddf1418fe275cc2ee548bc4a29340c44fe1/zopfli-0.2.3.post1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c1e0ed5d84ffa2d677cc9582fc01e61dab2e7ef8b8996e055f0a76167b1b94df", size = 1754183 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/39/03/44f8f39950354d330fa798e4bab1ac8e38ec787d3fde25d5b9c7770065a2/zopfli-0.2.3.post1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:bfa1eb759e07d8b7aa7a310a2bc535e127ee70addf90dc8d4b946b593c3e51a8", size = 1905945 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/74/7b/94b920c33cc64255f59e3cfc77c829b5c6e60805d189baeada728854a342/zopfli-0.2.3.post1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cd2c002f160502608dcc822ed2441a0f4509c52e86fcfd1a09e937278ed1ca14", size = 1835885 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ad/89/c869ac844351e285a6165e2da79b715b0619a122e3160d183805adf8ab45/zopfli-0.2.3.post1-cp312-cp312-win32.whl", hash = "sha256:7be5cc6732eb7b4df17305d8a7b293223f934a31783a874a01164703bc1be6cd", size = 82743 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/29/e6/c98912fd3a589d8a7316c408fd91519f72c237805c4400b753e3942fda0b/zopfli-0.2.3.post1-cp312-cp312-win_amd64.whl", hash = "sha256:4e50ffac74842c1c1018b9b73875a0d0a877c066ab06bf7cccbaa84af97e754f", size = 99403 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/24/0e552e2efce9a20625b56e9609d1e33c2966be33fc008681121ec267daec/zopfli-0.2.3.post1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ecb7572df5372abce8073df078207d9d1749f20b8b136089916a4a0868d56051", size = 295485 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/08/83/b2564369fb98797a617fe2796097b1d719a4937234375757ad2a3febc04b/zopfli-0.2.3.post1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a1cf720896d2ce998bc8e051d4b4ce0d8bec007aab6243102e8e1d22a0b2fb3f", size = 163000 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3c/55/81d419739c2aab35e19b58bce5498dcb58e6446e5eb69f2d3c748b1c9151/zopfli-0.2.3.post1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5aad740b4d4fcbaaae4887823925166ffd062db3b248b3f432198fc287381d1a", size = 823699 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9e/91/89f07c8ea3c9bc64099b3461627b07a8384302235ee0f357eaa86f98f509/zopfli-0.2.3.post1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6617fb10f9e4393b331941861d73afb119cd847e88e4974bdbe8068ceef3f73f", size = 826612 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/41/31/46670fc0c7805d42bc89702440fa9b73491d68abbc39e28d687180755178/zopfli-0.2.3.post1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a53b18797cdef27e019db595d66c4b077325afe2fd62145953275f53d84ce40c", size = 851148 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/22/00/71ad39277bbb88f9fd20fb786bd3ff2ea4025c53b31652a0da796fb546cd/zopfli-0.2.3.post1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b78008a69300d929ca2efeffec951b64a312e9a811e265ea4a907ab546d79fa6", size = 1754215 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d0/4e/e542c508d20c3dfbef1b90fcf726f824f505e725747f777b0b7b7d1deb95/zopfli-0.2.3.post1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0aa5f90d6298bda02a95bc8dc8c3c19004d5a4e44bda00b67ca7431d857b4b54", size = 1905988 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ba/a5/817ac1ecc888723e91dc172e8c6eeab9f48a1e52285803b965084e11bbd5/zopfli-0.2.3.post1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2768c877f76c8a0e7519b1c86c93757f3c01492ddde55751e9988afb7eff64e1", size = 1835907 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cd/35/2525f90c972d8aafc39784a8c00244eeee8e8221b26cbc576748ee9dc1cd/zopfli-0.2.3.post1-cp313-cp313-win32.whl", hash = "sha256:71390dbd3fbf6ebea9a5d85ffed8c26ee1453ee09248e9b88486e30e0397b775", size = 82742 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2f/c6/49b27570923956d52d37363e8f5df3a31a61bd7719bb8718527a9df3ae5f/zopfli-0.2.3.post1-cp313-cp313-win_amd64.whl", hash = "sha256:a86eb88e06bd87e1fff31dac878965c26b0c26db59ddcf78bb0379a954b120de", size = 99408 },
|
||||||
|
]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue