diff --git a/.github/workflows/pullreqeust_tests.yaml b/.github/workflows/pullreqeust_tests.yaml index 02941053a..2055c734e 100644 --- a/.github/workflows/pullreqeust_tests.yaml +++ b/.github/workflows/pullreqeust_tests.yaml @@ -19,9 +19,16 @@ jobs: poetry --version # Check if poetry lock file is current with pyproject.toml poetry check --lock - poetry install --with=dev + poetry install --with=dev --no-ansi + + - name: Run db/test with MySQL docker + run: | + sudo apt update + sudo apt install -y mysql-client + cd arxiv && poetry run pytest auth/legacy/tests --db=mysql + - name: Run arxiv-base tests with coverage - run: poetry run pytest --cov=arxiv.base fourohfour --cov-fail-under=67 arxiv/base fourohfour + run: poetry run pytest --cov=arxiv.base fourohfour --cov-fail-under=75 arxiv/base fourohfour # - name: Check Types # TODO The types are in bad shape and need to be fixed # run: poetry run mypy --exclude "test*" -p arxiv @@ -31,16 +38,17 @@ jobs: sudo add-apt-repository -y ppa:mozillateam/ppa sudo apt update sudo apt install -y firefox-esr - wget https://github.com/mozilla/geckodriver/releases/latest/download/geckodriver-v0.35.0-linux64.tar.gz - tar -xvzf geckodriver-v0.35.0-linux64.tar.gz - sudo mv geckodriver /usr/local/bin/ + wget https://github.com/mozilla/geckodriver/releases/latest/download/geckodriver-v0.35.0-linux64.tar.gz + tar -xvzf geckodriver-v0.35.0-linux64.tar.gz + sudo mv geckodriver /usr/local/bin/ sudo chmod +x /usr/local/bin/geckodriver - name: Run other tests # These tests are split out because their coverage is low - run: poetry run pytest --cov=arxiv --cov-fail-under=25 arxiv + run: poetry run pytest --cov=arxiv --cov-fail-under=40 arxiv --ignore=arxiv/base --ignore=arxiv/auth/legacy --db=sqlite #- name: Check Doc Style # run: poetry run pydocstyle --convention=numpy --add-ignore=D401 arxiv - name: Run App Tests run: poetry run python tests/run_app_tests.py + diff --git a/.gitignore b/.gitignore index 73366578e..c22c7ef5a 100644 --- a/.gitignore +++ b/.gitignore @@ -131,3 +131,7 @@ fastly_hourly_stats.ini foo.json test.db-journal + +arxiv/db/.autogen_models.py +/arxiv/db/autogen_models.py +/arxiv/db/near_models.py diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..2f27cebf5 --- /dev/null +++ b/Makefile @@ -0,0 +1,41 @@ +PROD_DB_PROXY_PORT := 2021 + +.PHONY: prod-proxy test + +default: venv/bin/poetry /usr/bin/firefox-esr /usr/local/bin/geckodriver + +venv/bin/poetry: venv/bin/pip + . venv/bin/activate && pip install poetry + +venv/bin/pip: venv + . venv/bin/activate && pip install --upgrade pip + +venv: + python3.11 -m venv venv + +/usr/bin/firefox-esr: + sudo add-apt-repository -y ppa:mozillateam/ppa + sudo apt update + sudo apt install -y firefox-esr + +/usr/local/bin/geckodriver: + wget https://github.com/mozilla/geckodriver/releases/latest/download/geckodriver-v0.35.0-linux64.tar.gz + tar -xvzf geckodriver-v0.35.0-linux64.tar.gz + sudo mv geckodriver /usr/local/bin/ + sudo chmod +x /usr/local/bin/geckodriver + +~/.arxiv: + mkdir ~/.arxiv + + ~/.arxiv/arxiv-db-prod-readonly: ~/.arxiv + op item get as76tjqjnr5wduypygusvfyy34 --fields username,password --reveal | python3 -c "import sys;import urllib.parse; unpw=sys.stdin.read().split(','); sys.stdout.write('mysql://%s:%s@127.0.0.1:2021/arXiv' % (unpw[0].strip(),urllib.parse.quote(unpw[1].strip(),safe='*')))" > $@ + + +prod-proxy: + /usr/local/bin/cloud-sql-proxy --address 0.0.0.0 --port ${PROD_DB_PROXY_PORT} arxiv-production:us-central1:arxiv-production-rep9 > /dev/null 2>&1 & + +test: venv/bin/poetry + venv/bin/poetry run pytest --cov=arxiv.base fourohfour --cov-fail-under=67 arxiv/base fourohfour + TEST_ARXIV_DB_URI=mysql://testuser:testpassword@127.0.0.1:13306/testdb venv/bin/poetry run pytest --cov=arxiv --cov-fail-under=25 arxiv + TEST_ARXIV_DB_URI=mysql://testuser:testpassword@127.0.0.1:13306/testdb venv/bin/poetry run python tests/run_app_tests.py + diff --git a/arxiv/auth/auth/tests/test_decorators.py b/arxiv/auth/auth/tests/test_decorators.py index 584860e52..fe6be2647 100644 --- a/arxiv/auth/auth/tests/test_decorators.py +++ b/arxiv/auth/auth/tests/test_decorators.py @@ -10,6 +10,7 @@ from .. import scopes, decorators from ... import domain + EASTERN = timezone('US/Eastern') """ @mock.patch(f'{decorators.__name__}.request')""" diff --git a/arxiv/auth/conftest.py b/arxiv/auth/conftest.py deleted file mode 100644 index c49732293..000000000 --- a/arxiv/auth/conftest.py +++ /dev/null @@ -1,171 +0,0 @@ -import shutil -import tempfile -from copy import copy -from datetime import datetime, UTC - -import pytest -import os - -from flask import Flask -from sqlalchemy import create_engine, select -from sqlalchemy.orm import Session, make_transient_to_detached - -from .legacy import util -from .legacy.passwords import hash_password -from arxiv.base import Base -from ..base.middleware import wrap -from ..db import models -from ..db.models import configure_db_engine - -from ..auth.auth import Auth -from ..auth.auth.middleware import AuthMiddleware - - -@pytest.fixture -def classic_db_engine(): - db_path = tempfile.mkdtemp() - uri = f'sqlite:///{db_path}/test.db' - engine = create_engine(uri) - util.create_all(engine) - yield engine - shutil.rmtree(db_path) - - - -@pytest.fixture -def classic_db_engine(): - db_path = tempfile.mkdtemp() - uri = f'sqlite:///{db_path}/test.db' - engine = create_engine(uri) - util.create_all(engine) - yield engine - shutil.rmtree(db_path) - - -@pytest.fixture -def foouser(mocker): - user_id = '15830' - email = 'first@last.iv' - # Why does this use a mock for the use and not a models.TapirUser? - # Using an ORM obj caused problems when outside a session, but it seems - # like there should be a way to do that. - user = mocker.MagicMock( - user_id=user_id, - first_name='first', - last_name='last', - suffix_name='iv', - email=email, - policy_class=2, - flag_edit_users=1, - flag_email_verified=1, - flag_edit_system=0, - flag_approved=1, - flag_deleted=0, - flag_banned=0, - tracking_cookie='foocookie', - ) - nick = mocker.MagicMock( - nickname='foouser', - user_id=user_id, - user_seq=1, - flag_valid=1, - role=0, - policy=0, - flag_primary=1 - ) - password = 'thepassword' - hashed = hash_password(password) - password = mocker.MagicMock( - user_id=user_id, - password_storage=2, - password_enc=hashed, - test_only_password=password, # this is not on the real obj, just used so tests have access to it - ) - n = util.epoch(datetime.now(tz=UTC)) - secret = 'foosecret' - token = mocker.MagicMock( - user_id=user_id, - secret=secret, - valid=1, - issued_when=n, - issued_to='127.0.0.1', - remote_host='foohost.foo.com', - session_id=0 - ) - user.tapir_nicknames = nick - user.tapir_passwords = password - user.tapir_tokens = token - - return user - -@pytest.fixture -def db_with_user(classic_db_engine, foouser): - # just combines classic_db_engine and foouser - with Session(classic_db_engine, expire_on_commit=False) as session: - user = models.TapirUser( - user_id=foouser.user_id, - first_name=foouser.first_name, - last_name=foouser.last_name, - suffix_name=foouser.suffix_name, - email=foouser.email, - policy_class=foouser.policy_class, - flag_edit_users=foouser.flag_edit_users, - flag_email_verified=foouser.flag_email_verified, - flag_edit_system=foouser.flag_edit_system, - flag_approved=foouser.flag_approved, - flag_deleted=foouser.flag_deleted, - flag_banned=foouser.flag_banned, - tracking_cookie=foouser.tracking_cookie, - ) - nick = models.TapirNickname( - nickname=foouser.tapir_nicknames.nickname, - user_id=foouser.tapir_nicknames.user_id, - user_seq=foouser.tapir_nicknames.user_seq, - flag_valid=foouser.tapir_nicknames.flag_valid, - role=foouser.tapir_nicknames.role, - policy=foouser.tapir_nicknames.policy, - flag_primary=foouser.tapir_nicknames.flag_primary, - ) - password = models.TapirUsersPassword( - user_id=foouser.user_id, - password_storage=foouser.tapir_passwords.password_storage, - password_enc=foouser.tapir_passwords.password_enc, - ) - token = models.TapirPermanentToken( - user_id=foouser.user_id, - secret=foouser.tapir_tokens.secret, - valid=foouser.tapir_tokens.valid, - issued_when=foouser.tapir_tokens.issued_when, - issued_to=foouser.tapir_tokens.issued_to, - remote_host=foouser.tapir_tokens.remote_host, - session_id=foouser.tapir_tokens.session_id, - ) - session.add(user) - session.add(token) - session.add(password) - session.add(nick) - session.commit() - session.close() - - foouser.tapir_nicknames.nickname - yield classic_db_engine - -@pytest.fixture -def db_configed(db_with_user): - configure_db_engine(db_with_user,None) - - -@pytest.fixture -def app(db_with_user): - app = Flask('test_auth_app') - - engine, _ = configure_db_engine(db_with_user, None) - Base(app) - Auth(app) - wrap(app, [AuthMiddleware]) - yield app - - -@pytest.fixture -def request_context(app): - yield app.test_request_context() diff --git a/arxiv/auth/legacy/tests/test_accounts.py b/arxiv/auth/legacy/tests/test_accounts.py index 10ffbe0e8..4731f41f9 100644 --- a/arxiv/auth/legacy/tests/test_accounts.py +++ b/arxiv/auth/legacy/tests/test_accounts.py @@ -31,7 +31,7 @@ def get_user(session, user_id): def test_with_nonexistant_user_w_app(app): """There is no user with the passed username.""" with app.app_context(): - assert not accounts.does_username_exist('baruser') + assert not accounts.does_username_exist('baruser') def test_with_nonexistant_user_wo_app(db_configed): """There is no user with the passed username.""" diff --git a/arxiv/auth/legacy/tests/test_bootstrap.py b/arxiv/auth/legacy/tests/test_bootstrap.py index cff44538e..991fa5214 100644 --- a/arxiv/auth/legacy/tests/test_bootstrap.py +++ b/arxiv/auth/legacy/tests/test_bootstrap.py @@ -1,21 +1,17 @@ """Test the legacy integration with synthetic data.""" -import os import shutil -import sys import tempfile from typing import Tuple from unittest import TestCase from flask import Flask -import locale +import pytest -from typing import List import random -from datetime import datetime -from pytz import timezone, UTC +from pytz import timezone from mimesis import Person, Internet, Datetime, locales -from sqlalchemy import select, func +from sqlalchemy import select import arxiv.db from arxiv.db import transaction @@ -65,6 +61,8 @@ def setUp(self): arxiv.db.models.configure_db_engine(engine,None) util.create_all(engine) + visited = set() + with self.app.app_context(): with transaction() as session: edc = session.execute(select(models.Endorsement)).all() @@ -80,21 +78,22 @@ def setUp(self): papers_to_endorse=3 )) - for category in definitions.CATEGORIES_ACTIVE.keys(): - if '.' in category: - archive, subject_class = category.split('.', 1) - else: - archive, subject_class = category, '' - - with transaction() as session: - #print(f"arch: {archive} sc: {subject_class}") - session.add(models.Category( - archive=archive, - subject_class=subject_class, - definitive=1, - active=1, - endorsement_domain='test_domain_bootstrap' - )) + # categories are loaded already + # for category in definitions.CATEGORIES_ACTIVE.keys(): + # if '.' in category: + # archive, subject_class = category.split('.', 1) + # else: + # archive, subject_class = category, '' + # + # with transaction() as session: + # #print(f"arch: {archive} sc: {subject_class}") + # session.add(models.Category( + # archive=archive, + # subject_class=subject_class, + # definitive=1, + # active=1, + # endorsement_domain='test_domain_bootstrap' + # )) COUNT = 100 @@ -192,6 +191,19 @@ def setUp(self): issued_when = util.epoch( Datetime(locale).datetime().replace(tzinfo=EASTERN) ) + + # These are the constraints on the table. + key = { + "endorsee": db_user.email, + "endorser_id": endorser_id, + "archive": archive, + "subject_class": subject_class, + } + key_str = repr(key) + if key_str in visited: + # print(f"{key_str} appeared already. This would violate the table constraint.") + continue + visited.add(key_str) session.add(models.Endorsement( endorsee=db_user, endorser_id=endorser_id, @@ -235,6 +247,8 @@ def setUp(self): def tearDown(self): shutil.rmtree(self.db_path) + @pytest.mark.skipif(lambda request: request.config.getoption("--db") == "mysql", + reason="is set up for sqlite3 only") def test_authenticate_and_use_session(self): """Attempt to authenticate users and create/load auth sessions.""" with self.app.app_context(): diff --git a/arxiv/auth/legacy/tests/test_endorsement_auto.py b/arxiv/auth/legacy/tests/test_endorsement_auto.py index eedbd8971..5f3862066 100644 --- a/arxiv/auth/legacy/tests/test_endorsement_auto.py +++ b/arxiv/auth/legacy/tests/test_endorsement_auto.py @@ -1,11 +1,11 @@ """Tests for :mod:`arxiv.users.legacy.endorsements` using a live test DB.""" -import os import shutil import tempfile -from unittest import TestCase, mock +from unittest import TestCase from datetime import datetime from pytz import timezone, UTC +import pytest from flask import Flask from sqlalchemy import insert @@ -43,7 +43,10 @@ def setUp(self): self.default_tracking_data = { 'remote_addr': '0.0.0.0', 'remote_host': 'foo-host.foo.com', - 'tracking_cookie': '0' + 'tracking_cookie': '0', + 'date': '2024-01-01', + 'flag_auto': 1, + 'added_by': 1, } with self.app.app_context(): @@ -97,6 +100,8 @@ def setUp(self): def tearDown(self): shutil.rmtree(self.db_path) + @pytest.mark.skipif(lambda request: request.config.getoption("--db") == "mysql", + reason="is set up for sqlite3 only") def test_invalidated_autoendorsements(self): """The user has two autoendorsements that have been invalidated.""" with self.app.app_context(): @@ -144,6 +149,8 @@ def test_invalidated_autoendorsements(self): result = endorsements.invalidated_autoendorsements(self.user) self.assertEqual(len(result), 2, "Two revoked endorsements are loaded") + @pytest.mark.skipif(lambda request: request.config.getoption("--db") == "mysql", + reason="is set up for sqlite3 only") def test_category_policies(self): """Load category endorsement policies from the database.""" with self.app.app_context(): @@ -171,6 +178,8 @@ def test_category_policies(self): self.assertTrue(policies[category]['endorse_email']) self.assertEqual(policies[category]['min_papers'], 3) + @pytest.mark.skipif(lambda request: request.config.getoption("--db") == "mysql", + reason="is set up for sqlite3 only") def test_domain_papers(self): """Get the number of papers published in each domain.""" with self.app.app_context(): @@ -292,6 +301,8 @@ def test_domain_papers(self): self.assertEqual(papers['firstdomain'], 2) self.assertEqual(papers['seconddomain'], 2) + @pytest.mark.skipif(lambda request: request.config.getoption("--db") == "mysql", + reason="is set up for sqlite3 only") def test_is_academic(self): """Determine whether a user is academic based on email.""" ok_patterns = ['%w3.org', '%aaas.org', '%agu.org', '%ams.org'] diff --git a/arxiv/auth/legacy/tests/test_endorsements.py b/arxiv/auth/legacy/tests/test_endorsements.py index ad606be5b..ba52de3b1 100644 --- a/arxiv/auth/legacy/tests/test_endorsements.py +++ b/arxiv/auth/legacy/tests/test_endorsements.py @@ -1,11 +1,11 @@ """Tests for :mod:`arxiv.users.legacy.endorsements` using a live test DB.""" -import os import shutil import tempfile -from unittest import TestCase, mock +from unittest import TestCase from datetime import datetime from pytz import timezone, UTC +import pytest from flask import Flask from mimesis import Person, Internet, Datetime @@ -40,7 +40,10 @@ def setUp(self): self.default_tracking_data = { 'remote_addr': '0.0.0.0', 'remote_host': 'foo-host.foo.com', - 'tracking_cookie': '0' + 'tracking_cookie': '0', + 'date': '2024-01-01', + 'flag_auto': 1, + 'added_by': 1, } with self.app.app_context(): @@ -79,6 +82,8 @@ def setUp(self): joined_remote_host=ip_addr ) session.add(db_user) + session.commit() + session.refresh(db_user) self.user = domain.User( user_id=str(db_user.user_id), @@ -106,13 +111,13 @@ def setUp(self): .values(pattern=str(pattern)) ) - session.add(models.EndorsementDomain( - endorsement_domain='test_domain', - endorse_all='n', - mods_endorse_all='n', - endorse_email='y', - papers_to_endorse=3 - )) + # session.add(models.EndorsementDomain( + # endorsement_domain='test_domain', + # endorse_all='n', + # mods_endorse_all='n', + # endorse_email='y', + # papers_to_endorse=3 + # )) # for category, definition in definitions.CATEGORIES_ACTIVE.items(): # if '.' in category: @@ -130,22 +135,24 @@ def setUp(self): def tearDown(self): shutil.rmtree(self.db_path) + @pytest.mark.skipif(lambda request: request.config.getoption("--db") == "mysql", + reason="is set up for sqlite3 only") def test_get_endorsements(self): """Test :func:`endoresement.get_endorsements`.""" with self.app.app_context(): - with transaction() as session: - for category, definition in definitions.CATEGORIES_ACTIVE.items(): - if '.' in category: - archive, subject_class = category.split('.', 1) - else: - archive, subject_class = category, '' - session.add(models.Category( - archive=archive, - subject_class=subject_class, - definitive=1, - active=1, - endorsement_domain='test_domain' - )) + # with transaction() as session: + # for category, definition in definitions.CATEGORIES_ACTIVE.items(): + # if '.' in category: + # archive, subject_class = category.split('.', 1) + # else: + # archive, subject_class = category, '' + # session.add(models.Category( + # archive=archive, + # subject_class=subject_class, + # definitive=1, + # active=1, + # endorsement_domain='test_domain' + # )) all_endorsements = set( endorsements.get_endorsements(self.user) ) @@ -172,7 +179,10 @@ def setUp(self): self.default_tracking_data = { 'remote_addr': '0.0.0.0', 'remote_host': 'foo-host.foo.com', - 'tracking_cookie': '0' + 'tracking_cookie': '0', + 'date': '2024-01-01', + 'flag_auto': 1, + 'added_by': 1, } with self.app.app_context(): @@ -226,6 +236,8 @@ def setUp(self): def tearDown(self): shutil.rmtree(self.db_path) + @pytest.mark.skipif(lambda request: request.config.getoption("--db") == "mysql", + reason="is set up for sqlite3 only") def test_invalidated_autoendorsements(self): """The user has two autoendorsements that have been invalidated.""" with self.app.app_context(): @@ -273,24 +285,26 @@ def test_invalidated_autoendorsements(self): result = endorsements.invalidated_autoendorsements(self.user) self.assertEqual(len(result), 2, "Two revoked endorsements are loaded") + @pytest.mark.skipif(lambda request: request.config.getoption("--db") == "mysql", + reason="is set up for sqlite3 only") def test_category_policies(self): """Load category endorsement policies from the database.""" with self.app.app_context(): - with transaction() as session: - session.add(models.Category( - archive='astro-ph', - subject_class='CO', - definitive=1, - active=1, - endorsement_domain='astro-ph' - )) - session.add(models.EndorsementDomain( - endorsement_domain='astro-ph', - endorse_all='n', - mods_endorse_all='n', - endorse_email='y', - papers_to_endorse=3 - )) + # with transaction() as session: + # session.add(models.Category( + # archive='astro-ph', + # subject_class='CO', + # definitive=1, + # active=1, + # endorsement_domain='astro-ph' + # )) + # session.add(models.EndorsementDomain( + # endorsement_domain='astro-ph', + # endorse_all='n', + # mods_endorse_all='n', + # endorse_email='y', + # papers_to_endorse=4 + # )) policies = endorsements.category_policies() category = definitions.CATEGORIES['astro-ph.CO'] @@ -298,8 +312,10 @@ def test_category_policies(self): self.assertEqual(policies[category]['domain'], 'astro-ph') self.assertFalse(policies[category]['endorse_all']) self.assertTrue(policies[category]['endorse_email']) - self.assertEqual(policies[category]['min_papers'], 3) + self.assertEqual(policies[category]['min_papers'], 4) + @pytest.mark.skipif(lambda request: request.config.getoption("--db") == "mysql", + reason="is set up for sqlite3 only") def test_domain_papers(self): """Get the number of papers published in each domain.""" with self.app.app_context(): @@ -320,6 +336,7 @@ def test_domain_papers(self): valid=1, **self.default_tracking_data )) + session.execute( insert(models.t_arXiv_in_category) .values( @@ -329,13 +346,15 @@ def test_domain_papers(self): is_primary=1 ) ) - session.add(models.Category( - archive='cs', - subject_class='DL', - definitive=1, - active=1, - endorsement_domain='firstdomain' - )) + + # session.add(models.Category( + # archive='cs', + # subject_class='DL', + # definitive=1, + # active=1, + # endorsement_domain='firstdomain' + # )) + # Here's another paper. document2 = models.Document( document_id=2, @@ -361,13 +380,13 @@ def test_domain_papers(self): is_primary=1 ) ) - session.add(models.Category( - archive='cs', - subject_class='IR', - definitive=1, - active=1, - endorsement_domain='firstdomain' - )) + # session.add(models.Category( + # archive='cs', + # subject_class='IR', + # definitive=1, + # active=1, + # endorsement_domain='firstdomain' + # )) # Here's a paper for which the user is an author. document3 = models.Document( document_id=3, @@ -403,24 +422,26 @@ def test_domain_papers(self): is_primary=0 # <- secondary! ) ) - session.add(models.Category( - archive='astro-ph', - subject_class='EP', - definitive=1, - active=1, - endorsement_domain='seconddomain' - )) - session.add(models.Category( - archive='astro-ph', - subject_class='CO', - definitive=1, - active=1, - endorsement_domain='seconddomain' - )) + # session.add(models.Category( + # archive='astro-ph', + # subject_class='EP', + # definitive=1, + # active=1, + # endorsement_domain='seconddomain' + # )) + # session.add(models.Category( + # archive='astro-ph', + # subject_class='CO', + # definitive=1, + # active=1, + # endorsement_domain='seconddomain' + # )) papers = endorsements.domain_papers(self.user) - self.assertEqual(papers['firstdomain'], 2) - self.assertEqual(papers['seconddomain'], 2) + self.assertEqual(papers['cs'], 2) + self.assertEqual(papers['astro-ph'], 2) + @pytest.mark.skipif(lambda request: request.config.getoption("--db") == "mysql", + reason="is set up for sqlite3 only") def test_is_academic(self): """Determine whether a user is academic based on email.""" ok_patterns = ['%w3.org', '%aaas.org', '%agu.org', '%ams.org'] diff --git a/arxiv/auth/legacy/util.py b/arxiv/auth/legacy/util.py index dd69577eb..b7ba97256 100644 --- a/arxiv/auth/legacy/util.py +++ b/arxiv/auth/legacy/util.py @@ -1,9 +1,10 @@ """Helpers and Flask application integration.""" - +import json from typing import List, Any from datetime import datetime from pytz import timezone, UTC import logging +import os from sqlalchemy import text, Engine from sqlalchemy.orm import Session as ORMSession @@ -13,12 +14,13 @@ from ..auth import scopes from .. import domain from ...db import Session, Base, session_factory -from ...db.models import TapirUser, TapirPolicyClass +from ...db.models import TapirUser, TapirPolicyClass, Category, Archive, Group, EndorsementDomain EASTERN = timezone('US/Eastern') logger = logging.getLogger(__name__) logger.propagate = False +arxiv_base_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) def now() -> int: """Get the current epoch/unix time.""" @@ -37,8 +39,19 @@ def from_epoch(t: int) -> datetime: def create_all(engine: Engine) -> None: + """Create all tables in the database, and bootstrap for test.""" + create_arxiv_db_schema(engine) + bootstrap_arxiv_db(engine) + + +def create_arxiv_db_schema(engine: Engine) -> None: """Create all tables in the database.""" Base.metadata.create_all(engine) + + +def bootstrap_arxiv_db(engine: Engine) -> None: + """Create all tables in the da.""" + with ORMSession(engine) as session: data = session.query(TapirPolicyClass).all() if data: @@ -48,6 +61,21 @@ def create_all(engine: Engine) -> None: session.add(TapirPolicyClass(**datum)) session.commit() + test_data_dir = os.path.join(arxiv_base_dir, "development", "test-data") + for data_class, data_file in [ + (Group, "arXiv_groups.json"), + (Archive, "arXiv_archives.json"), + (EndorsementDomain, "arXiv_endorsement_domains.json"), + (Category, "arXiv_categories.json"), + ]: + with ORMSession(engine) as session: + with open(os.path.join(test_data_dir, data_file), encoding="utf-8") as dfd: + data = json.load(dfd) + for datum in data: + session.add(data_class(**datum)) + session.commit() + + def drop_all(engine: Engine) -> None: """Drop all tables in the database.""" Base.metadata.drop_all(engine) diff --git a/arxiv/auth/openid/tests/test_keycloak.py b/arxiv/auth/openid/tests/test_keycloak.py index f9031e08e..195ff710c 100644 --- a/arxiv/auth/openid/tests/test_keycloak.py +++ b/arxiv/auth/openid/tests/test_keycloak.py @@ -5,15 +5,19 @@ from selenium.webdriver.firefox.service import Service from selenium.webdriver.firefox.options import Options import time +from shutil import which + +WEB_BROWSER = "firefox-esr" +WEB_DRIVER = "geckodriver" @pytest.fixture(scope="module") def web_driver() -> webdriver.Chrome: options = Options() options.headless = True - options.binary_location = "/usr/bin/firefox-esr" + options.binary_location = which(WEB_BROWSER) options.add_argument('--headless') - service = Service(executable_path="/usr/local/bin/geckodriver") + service = Service(executable_path=which(WEB_DRIVER)) _web_driver = webdriver.Firefox(service=service, options=options) _web_driver.implicitly_wait(10) # Wait for elements to be ready yield _web_driver @@ -29,6 +33,7 @@ def toy_flask(): flask_app.terminate() flask_app.wait() +@pytest.mark.skipif(which(WEB_BROWSER) is None or which(WEB_DRIVER) is None, reason="Web browser not found") def test_login(web_driver, toy_flask): web_driver.get("http://localhost:5101/login") # URL of your Flask app's login route diff --git a/arxiv/auth/tests/test_db.py b/arxiv/auth/tests/test_db.py index 0d5d67f9f..199689f73 100644 --- a/arxiv/auth/tests/test_db.py +++ b/arxiv/auth/tests/test_db.py @@ -10,6 +10,7 @@ def test_tables_exist(classic_db_engine): with classic_db_engine.connect() as conn: res = conn.execute(select(models.TapirPolicyClass).limit(1)) len(res.fetchall()) > 0 # would raise error if table did not exist. + conn.invalidate() def test_basic_load_db_and_app(app): @app.route("/get_policy_classes") diff --git a/arxiv/db/arxiv-db-metadata.yaml b/arxiv/db/arxiv-db-metadata.yaml new file mode 100644 index 000000000..ee46c21ae --- /dev/null +++ b/arxiv/db/arxiv-db-metadata.yaml @@ -0,0 +1,561 @@ +# +# sqlacodegen input +# +# Essentially, this is a catalog of changes made to the original sqlacodegen +# +# For example, the first class def - Subscription_UniversalInstitution -> MemberInstitution +# This is obviously not auto-generated from the db schema, or heavily modified. +# +# To preserve the code change, this file exists. When the customized sqlacodegen runs, this is used to change +# and override the behavior of codegen. +# +# sqlacodegen is driven from development/db_codegen.py +# + +# a minor hack +# globally suggests the column name to python variable name +# by default, sqlacodegen uses the suffix "_" +# +_names_map_: + class: _class + +# ================================================================================================================== +# MySQL arXiv tables +# +Subscription_UniversalInstitution: + class_name: MemberInstitution + relationships: + Subscription_UniversalInstitutionContact: "" + Subscription_UniversalInstitutionIP: "" + +Subscription_UniversalInstitutionContact: + class_name: MemberInstitutionContact + columns: + sid: "mapped_column(ForeignKey('Subscription_UniversalInstitution.id', ondelete='CASCADE'), nullable=False, index=True)" + +Subscription_UniversalInstitutionIP: + class_name: MemberInstitutionIP + +arXiv_admin_log: + class_name: AdminLog +arXiv_admin_metadata: + class_name: AdminMetadata + table_args: + - replace: ["Index('pidv', 'paper_id', 'version', unique=True)", "Index('arxiv_admin_pidv', 'paper_id', 'version', unique=True)"] +arXiv_archive_category: + class_name: ArchiveCategory +arXiv_archive_def: + class_name: ArchiveDef +arXiv_archive_group: + class_name: ArchiveGroup + +arXiv_archives: + class_name: Archive + relationships: + arXiv_categories: "relationship('Category', back_populates='arXiv_archive')" + arXiv_groups: "" + +arXiv_aws_config: + class_name: AwsConfig +arXiv_aws_files: + class_name: AwsFile +arXiv_bib_feeds: + class_name: BibFeed +arXiv_bib_updates: + class_name: BibUpdate +arXiv_bogus_countries: + class_name: BogusCountries + +arXiv_categories: + class_name: Category + relationships: + arXiv_archives: "" + arXiv_cross_control: + arXiv_cross_controls: "relationship('CrossControl', back_populates='arXiv_category')" + arXiv_endorsement_domains: + arXiv_endorsement_domain: "relationship('EndorsementDomain', primaryjoin='Category.endorsement_domain == EndorsementDomain.endorsement_domain', back_populates='arXiv_categories')" + arXiv_demographics: "relationship('Demographic', back_populates='arXiv_category')" + additional_relationships: + - "arXiv_endorsements = relationship('Endorsement', back_populates='arXiv_categories')" + - "arXiv_endorsement_requests = relationship('EndorsementRequest', back_populates='arXiv_categories')" + +arXiv_questionable_categories: + class_name: QuestionableCategory +arXiv_category_def: + class_name: CategoryDef + +arXiv_control_holds: + class_name: ControlHold + +arXiv_cross_control: + class_name: CrossControl + table_args: + - replace: ["Index('document_id', 'document_id', 'version'),", ""] + columns: + freeze_date: "mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue())" + relationships: + arXiv_categories: + arXiv_category: "relationship('Category', primaryjoin='and_(CrossControl.archive == Category.archive, CrossControl.subject_class == Category.subject_class)', back_populates='arXiv_cross_controls')" + document: "relationship('Document', primaryjoin='CrossControl.document_id == Document.document_id', back_populates='arXiv_cross_controls')" + user: "relationship('TapirUser', primaryjoin='CrossControl.user_id == TapirUser.user_id', back_populates='arXiv_cross_controls')" + +arXiv_datacite_dois: + class_name: DataciteDois + +arXiv_dblp_authors: + class_name: DBLPAuthor +arXiv_dblp_document_authors: + class_name: DBLPDocumentAuthor + +arXiv_document_category: + class_name: DocumentCategory + +arXiv_documents: + class_name: Document + relationships: + arXiv_dblp_document_authors: "" + arXiv_paper_owners: "" + arXiv_cross_control: "" + arXiv_jref_control: + arXiv_jref_controls: "relationship('JrefControl', back_populates='document')" + additional_relationships: + - "arXiv_cross_controls = relationship('CrossControl', back_populates='document')" + - "owners = relationship('PaperOwner', back_populates='document')" + +arXiv_dblp: + class_name: DBLP + +arXiv_paper_pw: + class_name: PaperPw + columns: + document_id: "mapped_column(ForeignKey('arXiv_documents.document_id'), primary_key=True, server_default=FetchedValue())" + password_storage: mapped_column(Integer) + password_enc: mapped_column(String(50)) + +arXiv_endorsement_domains: + class_name: EndorsementDomain + relationships: + arXiv_categories: "relationship('Category', back_populates='arXiv_endorsement_domain')" + +arXiv_endorsement_requests: + class_name: EndorsementRequest + relationships: + arXiv_categories: "relationship('Category', primaryjoin='and_(EndorsementRequest.archive == Category.archive, EndorsementRequest.subject_class == Category.subject_class)', back_populates='arXiv_endorsement_requests')" + endorsee: "relationship('TapirUser', primaryjoin='EndorsementRequest.endorsee_id == TapirUser.user_id', back_populates='arXiv_endorsement_requests', uselist=False)" + arXiv_endorsements: + endorsement: ":Mapped['Endorsement'] = relationship('Endorsement', back_populates='request', uselist=False)" + additional_relationships: + - "audit = relationship('EndorsementRequestsAudit', uselist=False)" + +arXiv_endorsement_requests_audit: + class_name: EndorsementRequestsAudit + +arXiv_endorsements: + class_name: Endorsement + table_args: + - replace: ["Index('archive', 'archive', 'subject_class'),", ""] + relationships: + endorsee: "relationship('TapirUser', primaryjoin='Endorsement.endorsee_id == TapirUser.user_id', back_populates='endorsee_of')" + endorser: "relationship('TapirUser', primaryjoin='Endorsement.endorser_id == TapirUser.user_id', back_populates='endorses')" + request: "relationship('EndorsementRequest', back_populates='endorsement')" + +arXiv_endorsements_audit: + class_name: EndorsementsAudit +arXiv_freeze_log: + class_name: FreezeLog +arXiv_group_def: + class_name: GroupDef +arXiv_groups: + class_name: Group + relationships: + arXiv_archives: "relationship('Archive', back_populates='arXiv_group')" + +arXiv_jref_control: + class_name: JrefControl + table_args: + - replace: ["Index('document_id', 'document_id', 'version'", "Index('jref_ctrl_document_id', 'document_id', 'version'"] + columns: + freeze_date: "mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue())" + status: "mapped_column(Enum('new', 'frozen', 'published', 'rejected'), nullable=False, index=True, server_default=FetchedValue())" + relationships: + document: "relationship('Document', back_populates='arXiv_jref_controls')" + user: "relationship('TapirUser', back_populates='arXiv_jref_controls')" + +arXiv_licenses: + class_name: License + relationships: + arXiv_metadata: "" + arXiv_submissions: "relationship('Submission', back_populates='arXiv_license')" + +arXiv_log_positions: + class_name: LogPosition + +arXiv_metadata: + class_name: Metadata + columns: + source_format: ": Mapped[Optional[SOURCE_FORMAT]] = mapped_column(String(12))" + relationships: + arXiv_licenses: "" + document: "relationship('Document', primaryjoin='Metadata.document_id == Document.document_id', back_populates='arXiv_metadata')" + submitter: "relationship('TapirUser', primaryjoin='Metadata.submitter_id == TapirUser.user_id', back_populates='arXiv_metadata')" + sword: "relationship('Tracking', primaryjoin='Submission.sword_id == Tracking.sword_id', back_populates='arXiv_submissions_sowrd')" + +arXiv_mirror_list: + class_name: MirrorList + +arXiv_moderator_api_key: + class_name: ModeratorApiKey + relationships: + user: "relationship('TapirUser', primaryjoin='ModeratorApiKey.user_id == TapirUser.user_id', back_populates='arXiv_moderator_api_keys')" +arXiv_monitor_klog: + class_name: MonitorKlog +arXiv_monitor_mailq: + class_name: MonitorMailq +arXiv_monitor_mailsent: + class_name: MonitorMailsent +arXiv_next_mail: + class_name: NextMail +arXiv_orcid_config: + class_name: OrcidConfig +arXiv_ownership_requests: + class_name: OwnershipRequest + table_args: drop + columns: + user_id: mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()) + endorsement_request_id: mapped_column(ForeignKey('arXiv_endorsement_requests.request_id'), index=True) + + relationships: + endorsement_request: "relationship('EndorsementRequest', primaryjoin='OwnershipRequest.endorsement_request_id == EndorsementRequest.request_id', back_populates='arXiv_ownership_requests')" + user: "relationship('TapirUser', primaryjoin='OwnershipRequest.user_id == TapirUser.user_id', back_populates='arXiv_ownership_requests')" + additional_relationships: + - "request_audit = relationship('OwnershipRequestsAudit', back_populates='ownership_request', uselist=False)" + - "documents = relationship('Document', secondary=t_arXiv_ownership_requests_papers)" + +# I think this is hand-edited, and not really used anywhere it seems +arXiv_ownership_requests_audit: + class_name: OwnershipRequestsAudit + table_args: drop + columns: + request_id: "mapped_column(ForeignKey('arXiv_ownership_requests.request_id'), primary_key=True, server_default=FetchedValue())" + additional_relationships: + - "ownership_request = relationship('OwnershipRequest', primaryjoin='OwnershipRequestsAudit.request_id == OwnershipRequest.request_id', back_populates='request_audit', uselist=False)" + +# Without this, arXiv_paper_owners would become simple Table, not Model +# +# The definition of PaperOwner is problematic. The main issue is that the table has no simple +# primary key. If this had a surrogate key as primary with the constraints as secondary, +# the table was a lot more usuable. +# Because of this, referencing the paper owner record from elsewhere is inconvinent, and +# sqlalchemy has trouble making the table to begin with. +arXiv_paper_owners: + class_name: PaperOwner + table_args: + # This is given by the document_id column - squelch the index name that's not relevant + - replace: ["ForeignKeyConstraint(['document_id'], ['arXiv_documents.document_id'], name='0_593'),", ""] + # This is give by the user_id column + - replace: ["ForeignKeyConstraint(['user_id'], ['tapir_users.user_id'], name='0_594'),", ""] + # Define this as primary key - don't add primay = true in the column + - replace: ["Index('document_id', 'document_id', 'user_id', unique=True)", "PrimaryKeyConstraint('document_id', 'user_id')"] + columns: + document_id: "mapped_column(ForeignKey('arXiv_documents.document_id'))" + user_id: "mapped_column(ForeignKey('tapir_users.user_id'))" + relationships: + document: "relationship('Document', back_populates='owners')" + tapir_users: "" + user: "" + + additional_relationships: + - "owner = relationship('TapirUser', foreign_keys='[PaperOwner.user_id]', back_populates='owned_papers')" +arXiv_paper_sessions: + class_name: PaperSession +arXiv_pilot_files: + class_name: PilotFile +arXiv_publish_log: + class_name: PublishLog +arXiv_reject_session_usernames: + class_name: RejectSessionUsername +arXiv_sciencewise_pings: + class_name: SciencewisePing +arXiv_show_email_requests: + class_name: ShowEmailRequest + table_args: + - replace: ["Index('email_reqs_user_id', 'user_id', 'dated'),", ""] + - replace: ["Index('user_id', 'user_id', 'dated')", "Index('email_reqs_user_id', 'user_id', 'dated')"] +arXiv_state: + class_name: State +arXiv_stats_monthly_downloads: + class_name: StatsMonthlyDownload +arXiv_stats_monthly_submissions: + class_name: StatsMonthlySubmission +arXiv_submission_agreements: + class_name: SubmissionAgreement +arXiv_submission_category: + class_name: SubmissionCategory + +arXiv_submission_category_proposal: + class_name: SubmissionCategoryProposal + relationships: + arXiv_category_def: "relationship('CategoryDef', primaryjoin='SubmissionCategoryProposal.category == CategoryDef.category', back_populates='arXiv_submission_category_proposal')" + proposal_comment: "relationship('AdminLog', primaryjoin='SubmissionCategoryProposal.proposal_comment_id == AdminLog.id', back_populates='arXiv_submission_category_proposal')" + response_comment: "relationship('AdminLog', primaryjoin='SubmissionCategoryProposal.response_comment_id == AdminLog.id', back_populates='arXiv_submission_category_proposal_')" + submission: "relationship('Submission', primaryjoin='SubmissionCategoryProposal.submission_id == Submission.submission_id', back_populates='arXiv_submission_category_proposal')" + user: "relationship('TapirUser', primaryjoin='SubmissionCategoryProposal.user_id == TapirUser.user_id', back_populates='arXiv_submission_category_proposal')" + + +arXiv_submission_control: + table_args: + # the document_id conflicts + - replace: ["Index('document_id', 'document_id', 'version'", "Index('sub_ctrl_document_id', 'document_id', 'version'"] + class_name: SubmissionControl + +arXiv_submission_flag: + class_name: SubmissionFlag +arXiv_submission_hold_reason: + class_name: SubmissionHoldReason +arXiv_submission_locks: + class_name: SubmissionLocks +arXiv_submission_near_duplicates: + class_name: SubmissionNearDuplicate +arXiv_submission_qa_reports: + class_name: SubmissionQaReport +arXiv_submission_view_flag: + class_name: SubmissionViewFlag +arXiv_submissions: + class_name: Submission + relationships: + agreement: "relationship('SubmissionAgreement', primaryjoin='Submission.agreement_id == SubmissionAgreement.agreement_id', back_populates='arXiv_submissions')" + document: "relationship('Document', primaryjoin='Submission.document_id == Document.document_id', back_populates='arXiv_submissions')" + submitter: "relationship('TapirUser', primaryjoin='Submission.submitter_id == TapirUser.user_id', back_populates='arXiv_submissions')" + sword: "relationship('Tracking', primaryjoin='Submission.sword_id == Tracking.sword_id', back_populates='arXiv_submissions')" + arXiv_licenses: + arXiv_license: "relationship('License', primaryjoin='Submission.license == License.name', back_populates='arXiv_submissions')" + +arXiv_pilot_datasets: + class_name: PilotDataset + columns: + created: drop + +arXiv_submission_abs_classifier_data: + class_name: SubmissionAbsClassifierDatum +arXiv_submission_classifier_data: + class_name: SubmissionClassifierDatum +arXiv_submitter_flags: + class_name: SubmitterFlag +arXiv_suspect_emails: + class_name: SuspectEmail +arXiv_titles: + class_name: Title + +arXiv_top_papers: + class_name: TopPaper + relationships: + document: "relationship('Document', primaryjoin='TopPaper.document_id == Document.document_id', back_populates='arXiv_top_papers')" + +arXiv_trackback_pings: + class_name: TrackbackPing + columns: + status: ":Mapped[Literal['pending', 'pending2', 'accepted', 'rejected', 'spam']] = mapped_column(Enum('pending', 'pending2', 'accepted', 'rejected', 'spam'), nullable=False, index=True, server_default=FetchedValue())" + +arXiv_trackback_sites: + class_name: TrackbackSite + columns: + action: ":Mapped[Literal['neutral', 'accept', 'reject', 'spam']] = mapped_column(Enum('neutral', 'accept', 'reject', 'spam'), nullable=False, server_default=FetchedValue())" + +arXiv_tracking: + class_name: Tracking + +# without this, arXiv_updates would become simple Table, not Model +# IOW, someone copy&pasted and did not ues sqlacodegen +arXiv_updates: + class_name: Updates + table_args: + - replace: ["Index('document_id', 'document_id', 'date', 'action', 'category', unique=True)", "PrimaryKeyConstraint('document_id', 'date', 'action', 'category')"] + columns: + action: ":Mapped[Optional[Literal['new', 'replace', 'absonly', 'cross', 'repcro']]] = mapped_column(Enum('new', 'replace', 'absonly', 'cross', 'repcro'))" + +arXiv_versions: + class_name: Version +arXiv_versions_checksum: + class_name: VersionsChecksum +dbix_class_schema_versions: + class_name: DbixClassSchemaVersion +sessions: + class_name: Session + +tapir_address: + class_name: TapirAddress + table_args: drop + columns: + user_id: "mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, nullable=False, server_default=FetchedValue())" + country: "mapped_column(ForeignKey('tapir_countries.digraph'), nullable=False, index=True, server_default=FetchedValue())" + relationships: + tapir_countries: + tapir_country: "relationship('TapirCountry', primaryjoin='TapirAddress.country == TapirCountry.digraph', back_populates='tapir_address')" + user: "relationship('TapirUser', primaryjoin='TapirAddress.user_id == TapirUser.user_id', back_populates='tapir_address')" + +tapir_admin_audit: + class_name: TapirAdminAudit + columns: + data: mapped_column(String(255)) + +tapir_countries: + class_name: TapirCountry + relationships: + tapir_address: "relationship('TapirAddress', back_populates='tapir_country')" + tapir_demographics: "relationship('TapirDemographic', back_populates='tapir_country')" + +tapir_email_change_tokens: + class_name: TapirEmailChangeToken +tapir_email_headers: + class_name: TapirEmailHeader +tapir_email_log: + class_name: TapirEmailLog +tapir_email_mailings: + class_name: TapirEmailMailing +tapir_email_templates: + class_name: TapirEmailTemplate +tapir_email_tokens: + class_name: TapirEmailToken +tapir_integer_variables: + class_name: TapirIntegerVariable +tapir_nicknames: + class_name: TapirNickname +tapir_nicknames_audit: + class_name: TapirNicknamesAudit +tapir_permanent_tokens: + class_name: TapirPermanentToken +tapir_phone: + class_name: TapirPhone +tapir_policy_classes: + class_name: TapirPolicyClass +tapir_presessions: + class_name: TapirPresession +tapir_recovery_tokens: + class_name: TapirRecoveryToken +tapir_recovery_tokens_used: + class_name: TapirRecoveryTokensUsed +tapir_sessions: + class_name: TapirSession + additional_relationships: + - "user = relationship('TapirUser', primaryjoin='TapirSession.user_id == TapirUser.user_id', back_populates='tapir_sessions')" +tapir_sessions_audit: + class_name: TapirSessionsAudit + additional_relationships: + - "session = relationship('TapirSession')" +tapir_string_variables: + class_name: TapirStringVariable +tapir_strings: + class_name: TapirString + +tapir_users: + class_name: TapirUser + relationships: + arXiv_endorsements: + endorsee_of: "relationship('Endorsement', foreign_keys='[Endorsement.endorsee_id]', back_populates='endorsee')" + arXiv_endorsements_: + endorses: "relationship('Endorsement', foreign_keys='[Endorsement.endorser_id]', back_populates='endorser')" + arXiv_moderator_api_key: + arXiv_moderator_api_keys: "relationship('ModeratorApiKey', back_populates='user')" + arXiv_paper_owners: + owned_papers: "relationship('PaperOwner', foreign_keys='[PaperOwner.user_id]', back_populates='owner')" + arXiv_paper_owners_: "" + arXiv_jref_control: + arXiv_jref_controls: "relationship('JrefControl', back_populates='user')" + arXiv_cross_control: + arXiv_cross_controls: "relationship('CrossControl', back_populates='user')" + + additional_relationships: + - "demographics = relationship('Demographic', foreign_keys='[Demographic.user_id]', uselist=False, back_populates='user')" + +arXiv_author_ids: + class_name: AuthorIds +arXiv_demographics: + class_name: Demographic + relationships: + arXiv_categories: + arXiv_category: "relationship('Category', primaryjoin='and_(Demographic.archive == Category.archive, Demographic.subject_class == Category.subject_class)', back_populates='arXiv_demographics')" + +arXiv_orcid_ids: + class_name: OrcidIds +arXiv_queue_view: + class_name: QueueView +arXiv_suspicious_names: + class_name: SuspiciousName +arXiv_sword_licenses: + class_name: SwordLicense +tapir_demographics: + class_name: TapirDemographic + relationships: + tapir_countries: + tapir_country: relationship('TapirCountry', primaryjoin='TapirDemographic.country == TapirCountry.digraph', back_populates='tapir_demographics') +tapir_users_hot: + class_name: TapirUsersHot +tapir_users_password: + class_name: TapirUsersPassword + table_args: drop + columns: + user_id: "mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, server_default=FetchedValue())" + additional_relationships: + - "user = relationship('TapirUser')" +arXiv_latexml_doc: + class_name: DBLaTeXMLDocuments +arXiv_latexml_sub: + class_name: DBLaTeXMLSubmissions +feedback: + class_name: DBLaTeXMLFeedback + +arXiv_in_category: + columns: + document_id: "Column('document_id', ForeignKey('arXiv_documents.document_id'), nullable=False, index=True, server_default=FetchedValue())" + indecies: + - replace: ["Index('archive'", "Index('in_cat_archive'"] + +arXiv_moderators: + indecies: + - replace: ["Index('user_id'", "Index('mod_user_id'"] + +# Student-lead membership dashboard +membership_institutions: + class_name: MembershipInstitutions +membership_users: + class_name: MembershipUsers + +# arXiv check from modapi + +arXiv_check_roles: + class_name: CheckRoles + relationships: + arXiv_checks: "" + +arXiv_check_result_views: + class_name: CheckResultViews + relationships: + arXiv_checks: "" + +arXiv_check_targets: + class_name: CheckTargets + relationships: + arXiv_checks: "" + +arXiv_checks: + class_name: Checks + relationships: + check_target: + target: "relationship('CheckTargets')" + check_role: + role: "relationship('CheckRoles')" + check_result_view: + view: "relationship('CheckResultViews')" + +arXiv_check_results: + class_name: CheckResults + table_args: drop + relationships: + arXiv_check_responses: + check_responses: "relationship('CheckResponses', back_populates='check_result')" + +arXiv_check_responses: + class_name: CheckResponses + table_args: drop + relationships: + check_result: "relationship('CheckResults', back_populates='check_responses')" diff --git a/arxiv/db/models.py b/arxiv/db/models.py index dec6fe37f..fce36dcd8 100644 --- a/arxiv/db/models.py +++ b/arxiv/db/models.py @@ -1,6 +1,19 @@ -"""These models represent the entire arXiv DB and the LaTeXML DB. +""" +************************************************* +DO NOT EDIT WITHOUT CONSULTING THE DOCUMENTATION! +************************************************* + +These models represent the entire arXiv DB and the LaTeXML DB. + +arxiv/db/models.py was generated by using arxiv/development/db_codegen.py along with arxiv/development/sqlacodegen. + +arxiv/db/orig_models.py, arxiv/db/arxiv-db-metadata.yaml are the inputs for the sqlacodegen. + +See development/README.md for the details. + +If you want to keep the model definition over time, add comment with the intention/reason. +Without it, it may be subjected to removal. -This file was generated by using sqlacodgen """ from typing import Optional, Literal, Any, Tuple, List @@ -9,96 +22,97 @@ import datetime as dt from datetime import datetime, date from dateutil.tz import gettz, tzutc +from sqlalchemy.dialects.mysql import VARCHAR from validators import url as is_valid_url from sqlalchemy import ( - BINARY, - BigInteger, + BINARY, + BigInteger, Column, - Date, - DateTime, - ForeignKey, - ForeignKeyConstraint, - Index, - Integer, - JSON, + Date, + DateTime, + Engine, + Enum, + ForeignKey, + ForeignKeyConstraint, + Index, + Integer, + JSON, Numeric, - PrimaryKeyConstraint, - SmallInteger, - String, - Text, + PrimaryKeyConstraint, + SmallInteger, + String, + TIMESTAMP, Table, - Enum, + Text, + func, text, - Engine ) from sqlalchemy.schema import FetchedValue -from sqlalchemy.orm import ( - Mapped, - mapped_column, - relationship -) +from sqlalchemy.orm import Mapped, mapped_column, relationship from ..config import settings -from . import Base, LaTeXMLBase, metadata, \ - session_factory, _classic_engine, _latexml_engine +from . import Base, LaTeXMLBase, metadata, session_factory, _classic_engine, _latexml_engine from .types import intpk +from ..document.version import SOURCE_FORMAT tb_secret = settings.TRACKBACK_SECRET tz = gettz(settings.ARXIV_BUSINESS_TZ) class MemberInstitution(Base): - __tablename__ = 'Subscription_UniversalInstitution' + """Deprecated - superceded by membership_institutions""" + + __tablename__ = "Subscription_UniversalInstitution" + __table_args__ = {"mysql_charset": "utf8mb3"} + resolver_URL: Mapped[Optional[str]] = mapped_column(String(255)) - resolver_URL: Mapped[Optional[str]] name: Mapped[str] = mapped_column(String(255), nullable=False, index=True) - label: Mapped[Optional[str]] + label: Mapped[Optional[str]] = mapped_column(String(255)) id: Mapped[intpk] - alt_text: Mapped[Optional[str]] - link_icon: Mapped[Optional[str]] - note: Mapped[Optional[str]] - + alt_text: Mapped[Optional[str]] = mapped_column(String(255)) + link_icon: Mapped[Optional[str]] = mapped_column(String(255)) + note: Mapped[Optional[str]] = mapped_column(String(255)) class MemberInstitutionContact(Base): - __tablename__ = 'Subscription_UniversalInstitutionContact' + """Deprecated - superceded by membership_institution_users""" - email: Mapped[Optional[str]] - sid: Mapped[int] = mapped_column(ForeignKey('Subscription_UniversalInstitution.id', ondelete='CASCADE'), nullable=False, index=True) + __tablename__ = "Subscription_UniversalInstitutionContact" + __table_args__ = {"mysql_charset": "utf8mb3"} + email: Mapped[Optional[str]] = mapped_column(String(255)) + + sid: Mapped[int] = mapped_column(ForeignKey("Subscription_UniversalInstitution.id", ondelete="CASCADE"), nullable=False, index=True) active: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) - contact_name: Mapped[Optional[str]] + contact_name: Mapped[Optional[str]] = mapped_column(String(255)) id: Mapped[intpk] - phone: Mapped[Optional[str]] + phone: Mapped[Optional[str]] = mapped_column(String(255)) note: Mapped[Optional[str]] = mapped_column(String(2048)) - Subscription_UniversalInstitution = relationship('MemberInstitution', primaryjoin='MemberInstitutionContact.sid == MemberInstitution.id') - + Subscription_UniversalInstitution: Mapped["MemberInstitution"] = relationship("MemberInstitution", primaryjoin="MemberInstitutionContact.sid == MemberInstitution.id") class MemberInstitutionIP(Base): - __tablename__ = 'Subscription_UniversalInstitutionIP' - __table_args__ = ( - Index('ip', 'start', 'end'), - ) + __tablename__ = "Subscription_UniversalInstitutionIP" + __table_args__ = (Index("ip", "start", "end"),) - sid: Mapped[int] = mapped_column(ForeignKey('Subscription_UniversalInstitution.id', ondelete='CASCADE'), nullable=False, index=True) + sid: Mapped[int] = mapped_column(ForeignKey("Subscription_UniversalInstitution.id", ondelete="CASCADE"), nullable=False, index=True) id: Mapped[intpk] exclude: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) end: Mapped[int] = mapped_column(BigInteger, nullable=False, index=True) start: Mapped[int] = mapped_column(BigInteger, nullable=False, index=True) - Subscription_UniversalInstitution = relationship('MemberInstitution', primaryjoin='MemberInstitutionIP.sid == MemberInstitution.id') - + Subscription_UniversalInstitution = relationship("MemberInstitution", primaryjoin="MemberInstitutionIP.sid == MemberInstitution.id") class AdminLog(Base): - __tablename__ = 'arXiv_admin_log' + __tablename__ = "arXiv_admin_log" + __table_args__ = {"mysql_charset": "latin1"} id: Mapped[intpk] logtime: Mapped[Optional[str]] = mapped_column(String(24)) - created: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=text('CURRENT_TIMESTAMP'), server_onupdate=text('CURRENT_TIMESTAMP')) + created: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=text("CURRENT_TIMESTAMP")) paper_id: Mapped[Optional[str]] = mapped_column(String(20), index=True) username: Mapped[Optional[str]] = mapped_column(String(20), index=True) host: Mapped[Optional[str]] = mapped_column(String(64)) @@ -109,19 +123,24 @@ class AdminLog(Base): submission_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) notify: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + arXiv_submission_category_proposal: Mapped[List["SubmissionCategoryProposal"]] = relationship( + "SubmissionCategoryProposal", foreign_keys="[SubmissionCategoryProposal.proposal_comment_id]", back_populates="proposal_comment" + ) + arXiv_submission_category_proposal_: Mapped[List["SubmissionCategoryProposal"]] = relationship( + "SubmissionCategoryProposal", foreign_keys="[SubmissionCategoryProposal.response_comment_id]", back_populates="response_comment" + ) + arXiv_submission_hold_reason: Mapped[List["SubmissionHoldReason"]] = relationship("SubmissionHoldReason", back_populates="comment") class AdminMetadata(Base): - __tablename__ = 'arXiv_admin_metadata' - __table_args__ = ( - Index('admin_metadata_pidv', 'paper_id', 'version'), - ) + __tablename__ = "arXiv_admin_metadata" + __table_args__ = (Index("arxiv_admin_pidv", "paper_id", "version", unique=True), {"mysql_charset": "latin1"}) metadata_id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True) - document_id = mapped_column(ForeignKey('arXiv_documents.document_id', ondelete='CASCADE'), index=True) + document_id: Mapped[Optional[int]] = mapped_column(ForeignKey("arXiv_documents.document_id", ondelete="CASCADE"), index=True) paper_id: Mapped[Optional[str]] = mapped_column(String(64)) - created: Mapped[Optional[datetime]] - updated: Mapped[Optional[datetime]] + created: Mapped[Optional[datetime]] = mapped_column(DateTime) + updated: Mapped[Optional[datetime]] = mapped_column(DateTime) submitter_name: Mapped[Optional[str]] = mapped_column(String(64)) submitter_email: Mapped[Optional[str]] = mapped_column(String(64)) history: Mapped[Optional[str]] = mapped_column(Text) @@ -129,93 +148,96 @@ class AdminMetadata(Base): source_type: Mapped[Optional[str]] = mapped_column(String(12)) title: Mapped[Optional[str]] = mapped_column(Text) authors: Mapped[Optional[str]] = mapped_column(Text) - category_string: Mapped[Optional[str]] + category_string: Mapped[Optional[str]] = mapped_column(String(255)) comments: Mapped[Optional[str]] = mapped_column(Text) - proxy: Mapped[Optional[str]] + proxy: Mapped[Optional[str]] = mapped_column(String(255)) report_num: Mapped[Optional[str]] = mapped_column(Text) - msc_class: Mapped[Optional[str]] - acm_class: Mapped[Optional[str]] + msc_class: Mapped[Optional[str]] = mapped_column(String(255)) + acm_class: Mapped[Optional[str]] = mapped_column(String(255)) journal_ref: Mapped[Optional[str]] = mapped_column(Text) - doi: Mapped[Optional[str]] + doi: Mapped[Optional[str]] = mapped_column(String(255)) abstract: Mapped[Optional[str]] = mapped_column(Text) - license: Mapped[Optional[str]] + license: Mapped[Optional[str]] = mapped_column(String(255)) version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) modtime: Mapped[Optional[int]] = mapped_column(Integer) is_current: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) - document = relationship('Document', primaryjoin='AdminMetadata.document_id == Document.document_id', backref='arXiv_admin_metadata') - + document: Mapped["Document"] = relationship("Document", back_populates="arXiv_admin_metadata") t_arXiv_admin_state = Table( - 'arXiv_admin_state', metadata, - Column('document_id', Integer, unique=True), - Column('timestamp', DateTime, nullable=False, server_default=FetchedValue()), - Column('abs_timestamp', Integer), - Column('src_timestamp', Integer), - Column('state', Enum('pending', 'ok', 'bad'), nullable=False, server_default=FetchedValue()), - Column('admin', String(32)), - Column('comment', String(255)) + "arXiv_admin_state", + metadata, + Column("document_id", Integer, unique=True), + Column("timestamp", DateTime, nullable=False, server_default=FetchedValue()), + Column("abs_timestamp", Integer), + Column("src_timestamp", Integer), + Column("state", Enum("pending", "ok", "bad"), nullable=False, server_default=FetchedValue()), + Column("admin", String(32)), + Column("comment", String(255)), ) - class ArchiveCategory(Base): - __tablename__ = 'arXiv_archive_category' + __tablename__ = "arXiv_archive_category" + __table_args__ = {"mysql_charset": "latin1"} archive_id: Mapped[str] = mapped_column(String(16), primary_key=True, nullable=False, server_default=FetchedValue()) category_id: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False) - class ArchiveDef(Base): - __tablename__ = 'arXiv_archive_def' + __tablename__ = "arXiv_archive_def" + __table_args__ = {"mysql_charset": "latin1"} archive: Mapped[str] = mapped_column(String(16), primary_key=True, server_default=FetchedValue()) - name: Mapped[Optional[str]] - + name: Mapped[Optional[str]] = mapped_column(String(255)) class ArchiveGroup(Base): - __tablename__ = 'arXiv_archive_group' + __tablename__ = "arXiv_archive_group" + __table_args__ = {"mysql_charset": "latin1"} archive_id: Mapped[str] = mapped_column(String(16), primary_key=True, nullable=False, server_default=FetchedValue()) group_id: Mapped[str] = mapped_column(String(16), primary_key=True, nullable=False, server_default=FetchedValue()) - class Archive(Base): - __tablename__ = 'arXiv_archives' + __tablename__ = "arXiv_archives" + __table_args__ = {"mysql_charset": "latin1"} archive_id: Mapped[str] = mapped_column(String(16), primary_key=True, server_default=FetchedValue()) - in_group = mapped_column(ForeignKey('arXiv_groups.group_id'), nullable=False, index=True, server_default=FetchedValue()) + in_group: Mapped[str] = mapped_column(ForeignKey("arXiv_groups.group_id"), nullable=False, index=True, server_default=FetchedValue()) archive_name: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) start_date: Mapped[str] = mapped_column(String(4), nullable=False, server_default=FetchedValue()) end_date: Mapped[str] = mapped_column(String(4), nullable=False, server_default=FetchedValue()) subdivided: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - arXiv_group = relationship('Group', primaryjoin='Archive.in_group == Group.group_id', backref='arXiv_archives') + arXiv_categories: Mapped[List["Category"]] = relationship("Category", back_populates="arXiv_archive") + # additional relation + arXiv_group = relationship("Group", primaryjoin="Archive.in_group == Group.group_id", back_populates="arXiv_archives") class AwsConfig(Base): - __tablename__ = 'arXiv_aws_config' + __tablename__ = "arXiv_aws_config" + __table_args__ = {"mysql_charset": "utf8mb3"} domain: Mapped[str] = mapped_column(String(75), primary_key=True, nullable=False) keyname: Mapped[str] = mapped_column(String(60), primary_key=True, nullable=False) value: Mapped[Optional[str]] = mapped_column(String(150)) - class AwsFile(Base): - __tablename__ = 'arXiv_aws_files' + __tablename__ = "arXiv_aws_files" + __table_args__ = {"mysql_charset": "utf8mb3"} type: Mapped[str] = mapped_column(String(10), nullable=False, index=True, server_default=FetchedValue()) filename: Mapped[str] = mapped_column(String(100), primary_key=True, server_default=FetchedValue()) md5sum: Mapped[Optional[str]] = mapped_column(String(50)) content_md5sum: Mapped[Optional[str]] = mapped_column(String(50)) size: Mapped[Optional[int]] = mapped_column(Integer) - timestamp: Mapped[Optional[datetime]] + timestamp: Mapped[Optional[datetime]] = mapped_column(DateTime) yymm: Mapped[Optional[str]] = mapped_column(String(4)) seq_num: Mapped[Optional[int]] = mapped_column(Integer) first_item: Mapped[Optional[str]] = mapped_column(String(20)) @@ -223,34 +245,31 @@ class AwsFile(Base): num_items: Mapped[Optional[int]] = mapped_column(Integer) - -t_arXiv_bad_pw = Table( - 'arXiv_bad_pw', metadata, - Column('user_id', ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()) -) +t_arXiv_bad_pw = Table("arXiv_bad_pw", metadata, Column("user_id", ForeignKey("tapir_users.user_id"), nullable=False, index=True, server_default=FetchedValue())) class BibFeed(Base): - __tablename__ = 'arXiv_bib_feeds' + __tablename__ = "arXiv_bib_feeds" + __table_args__ = {"mysql_charset": "latin1"} bib_id: Mapped[intpk] name: Mapped[str] = mapped_column(String(64), nullable=False, server_default=FetchedValue()) priority: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - uri: Mapped[Optional[str]] - identifier: Mapped[Optional[str]] - version: Mapped[Optional[str]] + uri: Mapped[Optional[str]] = mapped_column(String(255)) + identifier: Mapped[Optional[str]] = mapped_column(String(255)) + version: Mapped[Optional[str]] = mapped_column(String(255)) strip_journal_ref: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) concatenate_dupes: Mapped[Optional[int]] = mapped_column(Integer) max_updates: Mapped[Optional[int]] = mapped_column(Integer) - email_errors: Mapped[Optional[str]] + email_errors: Mapped[Optional[str]] = mapped_column(String(255)) prune_ids: Mapped[Optional[str]] = mapped_column(Text) prune_regex: Mapped[Optional[str]] = mapped_column(Text) enabled: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) - class BibUpdate(Base): - __tablename__ = 'arXiv_bib_updates' + __tablename__ = "arXiv_bib_updates" + __table_args__ = {"mysql_charset": "latin1"} update_id: Mapped[intpk] document_id: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) @@ -260,285 +279,309 @@ class BibUpdate(Base): doi: Mapped[Optional[str]] = mapped_column(Text) - -t_arXiv_black_email = Table( - 'arXiv_black_email', metadata, - Column('pattern', String(64)) -) +t_arXiv_black_email = Table("arXiv_black_email", metadata, Column("pattern", String(64))) +t_arXiv_block_email = Table("arXiv_block_email", metadata, Column("pattern", String(64))) -t_arXiv_block_email = Table( - 'arXiv_block_email', metadata, - Column('pattern', String(64)) -) - - -class BogusCountry(Base): - __tablename__ = 'arXiv_bogus_countries' +class BogusCountries(Base): + __tablename__ = "arXiv_bogus_countries" + __table_args__ = {"mysql_charset": "latin1"} user_id: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) country_name: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) - t_arXiv_bogus_subject_class = Table( - 'arXiv_bogus_subject_class', metadata, - Column('document_id', ForeignKey('arXiv_documents.document_id'), nullable=False, index=True, server_default=FetchedValue()), - Column('category_name', String(255), nullable=False, server_default=FetchedValue()) + "arXiv_bogus_subject_class", + metadata, + Column("document_id", ForeignKey("arXiv_documents.document_id"), nullable=False, index=True, server_default=FetchedValue()), + Column("category_name", String(255), nullable=False, server_default=FetchedValue()), ) class Category(Base): - __tablename__ = 'arXiv_categories' + __tablename__ = "arXiv_categories" + __table_args__ = {"mysql_charset": "latin1"} - archive: Mapped[str] = mapped_column(ForeignKey('arXiv_archives.archive_id'), primary_key=True, nullable=False, server_default=FetchedValue()) + # link to arXiv_archive + archive: Mapped[str] = mapped_column(ForeignKey("arXiv_archives.archive_id"), primary_key=True, nullable=False, server_default=FetchedValue()) subject_class: Mapped[str] = mapped_column(String(16), primary_key=True, nullable=False, server_default=FetchedValue()) definitive: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) active: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) - category_name: Mapped[Optional[str]] - endorse_all: Mapped[Literal['y', 'n', 'd']] = mapped_column(Enum('y', 'n', 'd'), nullable=False, server_default=text("'d'")) - endorse_email: Mapped[Literal['y', 'n', 'd']] = mapped_column(Enum('y', 'n', 'd'), nullable=False, server_default=text("'d'")) - papers_to_endorse: Mapped[int] = mapped_column(SmallInteger, nullable=False, server_default=text("'0'")) - endorsement_domain: Mapped[Optional[str]] = mapped_column(ForeignKey('arXiv_endorsement_domains.endorsement_domain'), index=True) + category_name: Mapped[Optional[str]] = mapped_column(String(255)) + endorse_all: Mapped[Literal["y", "n", "d"]] = mapped_column(Enum("y", "n", "d"), nullable=False, server_default=text("'d'")) + endorse_email: Mapped[Literal["y", "n", "d"]] = mapped_column(Enum("y", "n", "d"), nullable=False, server_default=text("'d'")) + papers_to_endorse: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + endorsement_domain: Mapped[Optional[str]] = mapped_column(ForeignKey("arXiv_endorsement_domains.endorsement_domain"), index=True) + arXiv_endorsements: Mapped[List["Endorsement"]] = relationship("Endorsement", back_populates="arXiv_categories") + arXiv_endorsements = relationship("Endorsement", back_populates="arXiv_categories") + + arXiv_endorsement_domain: Mapped["EndorsementDomain"] = relationship( + "EndorsementDomain", primaryjoin="Category.endorsement_domain == EndorsementDomain.endorsement_domain", back_populates="arXiv_categories" + ) + arXiv_endorsement_requests: Mapped[List["EndorsementRequest"]] = relationship("EndorsementRequest", back_populates="arXiv_categories") + arXiv_endorsement_requests = relationship("EndorsementRequest", back_populates="arXiv_categories") + arXiv_cross_controls: Mapped[List["CrossControl"]] = relationship("CrossControl", back_populates="arXiv_category") + arXiv_demographics: Mapped[List["Demographic"]] = relationship("Demographic", back_populates="arXiv_category") + + # link to category + arXiv_archive = relationship("Archive", primaryjoin="Category.archive == Archive.archive_id", back_populates="arXiv_categories") - arXiv_archive = relationship('Archive', primaryjoin='Category.archive == Archive.archive_id', backref='arXiv_categories') - arXiv_endorsements = relationship('Endorsement', back_populates='arXiv_categories') - arXiv_endorsement_domain = relationship('EndorsementDomain', primaryjoin='Category.endorsement_domain == EndorsementDomain.endorsement_domain', backref='arXiv_categories') - arXiv_endorsement_requests = relationship('EndorsementRequest', back_populates='arXiv_categories') class QuestionableCategory(Category): - __tablename__ = 'arXiv_questionable_categories' - __table_args__ = ( - ForeignKeyConstraint(['archive', 'subject_class'], ['arXiv_categories.archive', 'arXiv_categories.subject_class']), - ) + __tablename__ = "arXiv_questionable_categories" + __table_args__ = (ForeignKeyConstraint(["archive", "subject_class"], ["arXiv_categories.archive", "arXiv_categories.subject_class"]), {"mysql_charset": "latin1"}) archive: Mapped[str] = mapped_column(String(16), primary_key=True, nullable=False, server_default=FetchedValue()) subject_class: Mapped[str] = mapped_column(String(16), primary_key=True, nullable=False, server_default=FetchedValue()) - class CategoryDef(Base): - __tablename__ = 'arXiv_category_def' + __tablename__ = "arXiv_category_def" + __table_args__ = {"mysql_charset": "latin1"} category: Mapped[str] = mapped_column(String(32), primary_key=True) - name: Mapped[Optional[str]] + name: Mapped[Optional[str]] = mapped_column(String(255)) active: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + arXiv_document_category: Mapped[List["DocumentCategory"]] = relationship("DocumentCategory", back_populates="arXiv_category_def") + arXiv_submission_category: Mapped[List["SubmissionCategory"]] = relationship("SubmissionCategory", back_populates="arXiv_category_def") + arXiv_submission_category_proposal: Mapped[List["SubmissionCategoryProposal"]] = relationship("SubmissionCategoryProposal", back_populates="arXiv_category_def") class ControlHold(Base): - __tablename__ = 'arXiv_control_holds' - __table_args__ = ( - Index('control_id', 'hold_type'), - ) + __tablename__ = "arXiv_control_holds" + __table_args__ = (Index("control_id", "control_id", "hold_type", unique=True), {"mysql_charset": "latin1"}) hold_id: Mapped[intpk] control_id: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - hold_type: Mapped[Literal['submission', 'cross', 'jref']] = mapped_column(Enum('submission', 'cross', 'jref'), nullable=False, index=True, server_default=FetchedValue()) - hold_status: Mapped[Literal['held', 'extended', 'accepted', 'rejected']] = mapped_column(Enum('held', 'extended', 'accepted', 'rejected'), nullable=False, index=True, server_default=FetchedValue()) + hold_type: Mapped[Literal["submission", "cross", "jref"]] = mapped_column(Enum("submission", "cross", "jref"), nullable=False, index=True, server_default=FetchedValue()) + hold_status: Mapped[Literal["held", "extended", "accepted", "rejected"]] = mapped_column( + Enum("held", "extended", "accepted", "rejected"), nullable=False, index=True, server_default=FetchedValue() + ) hold_reason: Mapped[str] = mapped_column(String(255), nullable=False, index=True, server_default=FetchedValue()) hold_data: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) - origin: Mapped[Literal['auto', 'user', 'admin', 'moderator']] = mapped_column(Enum('auto', 'user', 'admin', 'moderator'), nullable=False, index=True, server_default=FetchedValue()) - placed_by: Mapped[Optional[int]] = mapped_column(ForeignKey('tapir_users.user_id'), index=True) - last_changed_by: Mapped[Optional[int]] = mapped_column(ForeignKey('tapir_users.user_id'), index=True) - - tapir_users = relationship('TapirUser', foreign_keys=[last_changed_by], back_populates='arXiv_control_holds') - tapir_users_ = relationship('TapirUser', foreign_keys=[placed_by], back_populates='arXiv_control_holds_') + origin: Mapped[Literal["auto", "user", "admin", "moderator"]] = mapped_column(Enum("auto", "user", "admin", "moderator"), nullable=False, index=True, server_default=FetchedValue()) + placed_by: Mapped[Optional[int]] = mapped_column(ForeignKey("tapir_users.user_id"), index=True) + last_changed_by: Mapped[Optional[int]] = mapped_column(ForeignKey("tapir_users.user_id"), index=True) + tapir_users: Mapped["TapirUser"] = relationship("TapirUser", foreign_keys=[last_changed_by], back_populates="arXiv_control_holds") + tapir_users_: Mapped["TapirUser"] = relationship("TapirUser", foreign_keys=[placed_by], back_populates="arXiv_control_holds_") class CrossControl(Base): - __tablename__ = 'arXiv_cross_control' - __table_args__ = ( - ForeignKeyConstraint(['archive', 'subject_class'], ['arXiv_categories.archive', 'arXiv_categories.subject_class']), - Index('document_id', 'document_id', 'version'), - Index('archive', 'archive', 'subject_class') - ) + __tablename__ = "arXiv_cross_control" + __table_args__ = (ForeignKeyConstraint(["archive", "subject_class"], ["arXiv_categories.archive", "arXiv_categories.subject_class"]), {"mysql_charset": "latin1"}) control_id: Mapped[intpk] - document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id'), nullable=False, server_default=FetchedValue()) + document_id: Mapped[int] = mapped_column(ForeignKey("arXiv_documents.document_id"), nullable=False, server_default=FetchedValue()) version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) desired_order: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()) - status: Mapped[Literal['new', 'frozen', 'published', 'rejected']] = mapped_column(Enum('new', 'frozen', 'published', 'rejected'), nullable=False, index=True, server_default=FetchedValue()) - flag_must_notify: Mapped[Optional[Literal['0', '1']]] = mapped_column(Enum('0', '1'), server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), nullable=False, index=True, server_default=FetchedValue()) + status: Mapped[Literal["new", "frozen", "published", "rejected"]] = mapped_column(Enum("new", "frozen", "published", "rejected"), nullable=False, index=True, server_default=FetchedValue()) + flag_must_notify: Mapped[Optional[Literal["0", "1"]]] = mapped_column(Enum("0", "1"), server_default=FetchedValue()) archive: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) subject_class: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) request_date: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) freeze_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) publish_date: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - arXiv_category = relationship('Category', primaryjoin='and_(CrossControl.archive == Category.archive, CrossControl.subject_class == Category.subject_class)', backref='arXiv_cross_controls') - document = relationship('Document', primaryjoin='CrossControl.document_id == Document.document_id', back_populates='arXiv_cross_controls') - user = relationship('TapirUser', primaryjoin='CrossControl.user_id == TapirUser.user_id', back_populates='arXiv_cross_controls') - + arXiv_category: Mapped["Category"] = relationship( + "Category", primaryjoin="and_(CrossControl.archive == Category.archive, CrossControl.subject_class == Category.subject_class)", back_populates="arXiv_cross_controls" + ) + document: Mapped["Document"] = relationship("Document", primaryjoin="CrossControl.document_id == Document.document_id", back_populates="arXiv_cross_controls") + user: Mapped["TapirUser"] = relationship("TapirUser", primaryjoin="CrossControl.user_id == TapirUser.user_id", back_populates="arXiv_cross_controls") class DataciteDois(Base): - __tablename__ = 'arXiv_datacite_dois' - __table_args__ = ( - Index('account_paper_id', 'account', 'paper_id'), - ) + __tablename__ = "arXiv_datacite_dois" + __table_args__ = (Index("account_paper_id", "account", "paper_id", unique=True), {"mysql_charset": "latin1"}) doi: Mapped[str] = mapped_column(String(255), primary_key=True) - account: Mapped[Optional[Literal['test', 'prod']]] = mapped_column(Enum('test', 'prod')) - metadata_id: Mapped[int] = mapped_column(ForeignKey('arXiv_metadata.metadata_id'), nullable=False, index=True) + account: Mapped[Optional[Literal["test", "prod"]]] = mapped_column(Enum("test", "prod")) + metadata_id: Mapped[int] = mapped_column(ForeignKey("arXiv_metadata.metadata_id"), nullable=False, index=True) paper_id: Mapped[str] = mapped_column(String(64), nullable=False) created: Mapped[Optional[datetime]] = mapped_column(DateTime, server_default=FetchedValue()) updated: Mapped[Optional[datetime]] = mapped_column(DateTime, server_default=FetchedValue()) - metadata_ = relationship('Metadata', primaryjoin='DataciteDois.metadata_id == Metadata.metadata_id', backref='arXiv_datacite_dois') - + metadata_: Mapped["Metadata"] = relationship("Metadata", back_populates="arXiv_datacite_dois") class DBLPAuthor(Base): - __tablename__ = 'arXiv_dblp_authors' + __tablename__ = "arXiv_dblp_authors" author_id: Mapped[int] = mapped_column(Integer, primary_key=True, unique=True) name: Mapped[Optional[str]] = mapped_column(String(40), unique=True) - class DBLPDocumentAuthor(Base): - __tablename__ = 'arXiv_dblp_document_authors' + __tablename__ = "arXiv_dblp_document_authors" + __table_args__ = {"mysql_charset": "latin1"} + + # join with document + document_id: Mapped[int] = mapped_column(ForeignKey("arXiv_documents.document_id"), primary_key=True, nullable=False, index=True) - document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id'), primary_key=True, nullable=False, index=True) - author_id: Mapped[int] = mapped_column(ForeignKey('arXiv_dblp_authors.author_id'), primary_key=True, nullable=False, index=True, server_default=FetchedValue()) + # join with author + author_id: Mapped[int] = mapped_column(ForeignKey("arXiv_dblp_authors.author_id"), primary_key=True, nullable=False, index=True, server_default=FetchedValue()) position: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - author = relationship('DBLPAuthor', primaryjoin='DBLPDocumentAuthor.author_id == DBLPAuthor.author_id', backref='arXiv_dblp_document_authors') - document = relationship('Document', primaryjoin='DBLPDocumentAuthor.document_id == Document.document_id', backref='arXiv_dblp_document_authors') + # join with dblp author + author = relationship("DBLPAuthor", primaryjoin="DBLPDocumentAuthor.author_id == DBLPAuthor.author_id", backref="arXiv_dblp_document_authors") + # join with document + document = relationship("Document", primaryjoin="DBLPDocumentAuthor.document_id == Document.document_id", backref="arXiv_dblp_document_authors") class DocumentCategory(Base): - __tablename__ = 'arXiv_document_category' + __tablename__ = "arXiv_document_category" + __table_args__ = {"mysql_charset": "latin1"} - document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id', ondelete='CASCADE'), primary_key=True, nullable=False, index=True, server_default=FetchedValue()) - category = mapped_column(ForeignKey('arXiv_category_def.category'), primary_key=True, nullable=False, index=True) + document_id: Mapped[int] = mapped_column(ForeignKey("arXiv_documents.document_id", ondelete="CASCADE"), primary_key=True, nullable=False, index=True, server_default=FetchedValue()) + category: Mapped[str] = mapped_column(ForeignKey("arXiv_category_def.category"), primary_key=True, nullable=False, index=True) is_primary: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - arXiv_category_def: Mapped[Optional[str]] = relationship('CategoryDef', primaryjoin='DocumentCategory.category == CategoryDef.category', backref='arXiv_document_categories') - document = relationship('Document', primaryjoin='DocumentCategory.document_id == Document.document_id', backref='arXiv_document_categories') - + arXiv_category_def: Mapped["CategoryDef"] = relationship("CategoryDef", back_populates="arXiv_document_category") + document: Mapped["Document"] = relationship("Document", back_populates="arXiv_document_category") class Document(Base): - __tablename__ = 'arXiv_documents' + __tablename__ = "arXiv_documents" + __table_args__ = {"mysql_charset": "latin1"} document_id: Mapped[intpk] - paper_id: Mapped[str] = mapped_column(String(20), nullable=False, unique=True, server_default=FetchedValue()) + paper_id: Mapped[str] = mapped_column(String(20), nullable=False, unique=True, index=True, server_default=FetchedValue()) title: Mapped[str] = mapped_column(String(255), nullable=False, index=True, server_default=FetchedValue()) authors: Mapped[Optional[str]] = mapped_column(Text) submitter_email: Mapped[str] = mapped_column(String(64), nullable=False, index=True, server_default=FetchedValue()) - submitter_id: Mapped[Optional[int]] = mapped_column(ForeignKey('tapir_users.user_id'), index=True) + submitter_id: Mapped[Optional[int]] = mapped_column(ForeignKey("tapir_users.user_id"), index=True) dated: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) primary_subject_class: Mapped[Optional[str]] = mapped_column(String(16)) - created: Mapped[Optional[datetime]] + created: Mapped[Optional[datetime]] = mapped_column(DateTime) + + # join it with user to get the user info + submitter = relationship("TapirUser", primaryjoin="Document.submitter_id == TapirUser.user_id", back_populates="arXiv_documents") + owners = relationship("PaperOwner", back_populates="document") + arXiv_cross_controls = relationship("CrossControl", back_populates="document") + arXiv_admin_metadata: Mapped[List["AdminMetadata"]] = relationship("AdminMetadata", back_populates="document") + arXiv_document_category: Mapped[List["DocumentCategory"]] = relationship("DocumentCategory", back_populates="document") + arXiv_jref_controls: Mapped[List["JrefControl"]] = relationship("JrefControl", back_populates="document") + arXiv_metadata: Mapped[List["Metadata"]] = relationship("Metadata", back_populates="document") + arXiv_mirror_list: Mapped[List["MirrorList"]] = relationship("MirrorList", back_populates="document") + arXiv_show_email_requests: Mapped[List["ShowEmailRequest"]] = relationship("ShowEmailRequest", back_populates="document") + arXiv_submission_control: Mapped[List["SubmissionControl"]] = relationship("SubmissionControl", back_populates="document") + arXiv_submissions: Mapped[List["Submission"]] = relationship("Submission", back_populates="document") + arXiv_top_papers: Mapped[List["TopPaper"]] = relationship("TopPaper", back_populates="document") + arXiv_versions: Mapped[List["Version"]] = relationship("Version", back_populates="document") - owners = relationship('PaperOwner', back_populates='document') - submitter = relationship('TapirUser', primaryjoin='Document.submitter_id == TapirUser.user_id', back_populates='arXiv_documents') - arXiv_cross_controls = relationship('CrossControl', back_populates='document') class DBLP(Document): - __tablename__ = 'arXiv_dblp' + __tablename__ = "arXiv_dblp" + __table_args__ = {"mysql_charset": "latin1"} - document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id'), primary_key=True, server_default=FetchedValue()) + document_id: Mapped[int] = mapped_column(ForeignKey("arXiv_documents.document_id"), primary_key=True, server_default=FetchedValue()) url: Mapped[Optional[str]] = mapped_column(String(80)) class PaperPw(Document): - __tablename__ = 'arXiv_paper_pw' + __tablename__ = "arXiv_paper_pw" + __table_args__ = {"mysql_charset": "latin1"} - document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id'), primary_key=True, server_default=FetchedValue()) + document_id: Mapped[int] = mapped_column(ForeignKey("arXiv_documents.document_id"), primary_key=True, server_default=FetchedValue()) password_storage: Mapped[Optional[int]] = mapped_column(Integer) password_enc: Mapped[Optional[str]] = mapped_column(String(50)) - t_arXiv_duplicates = Table( - 'arXiv_duplicates', metadata, - Column('user_id', ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()), - Column('email', String(255)), - Column('username', String(255)) + "arXiv_duplicates", + metadata, + Column("user_id", ForeignKey("tapir_users.user_id"), nullable=False, index=True, server_default=FetchedValue()), + Column("email", String(255)), + Column("username", String(255)), ) class EndorsementDomain(Base): - __tablename__ = 'arXiv_endorsement_domains' + __tablename__ = "arXiv_endorsement_domains" + __table_args__ = {"mysql_charset": "latin1"} endorsement_domain: Mapped[str] = mapped_column(String(32), primary_key=True, server_default=FetchedValue()) - endorse_all: Mapped[Literal['y', 'n']] = mapped_column(Enum('y', 'n'), nullable=False, server_default=FetchedValue()) - mods_endorse_all: Mapped[Literal['y', 'n']] = mapped_column(Enum('y', 'n'), nullable=False, server_default=FetchedValue()) - endorse_email: Mapped[Literal['y', 'n']] = mapped_column(Enum('y', 'n'), nullable=False, server_default=FetchedValue()) - papers_to_endorse: Mapped[int] = mapped_column(SmallInteger, nullable=False, server_default=FetchedValue()) + endorse_all: Mapped[Literal["y", "n"]] = mapped_column(Enum("y", "n"), nullable=False, server_default=FetchedValue()) + mods_endorse_all: Mapped[Literal["y", "n"]] = mapped_column(Enum("y", "n"), nullable=False, server_default=FetchedValue()) + endorse_email: Mapped[Literal["y", "n"]] = mapped_column(Enum("y", "n"), nullable=False, server_default=FetchedValue()) + papers_to_endorse: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + arXiv_categories: Mapped[List["Category"]] = relationship("Category", back_populates="arXiv_endorsement_domain") class EndorsementRequest(Base): - __tablename__ = 'arXiv_endorsement_requests' + __tablename__ = "arXiv_endorsement_requests" __table_args__ = ( - ForeignKeyConstraint(['archive', 'subject_class'], ['arXiv_categories.archive', 'arXiv_categories.subject_class']), - Index('endorsee_id_2', 'endorsee_id', 'archive', 'subject_class') + ForeignKeyConstraint(["archive", "subject_class"], ["arXiv_categories.archive", "arXiv_categories.subject_class"]), + Index("endorsee_id_2", "endorsee_id", "archive", "subject_class", unique=True), + {"mysql_charset": "latin1"}, ) request_id: Mapped[intpk] - endorsee_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()) + endorsee_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), nullable=False, index=True, server_default=FetchedValue()) archive: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) subject_class: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) - secret: Mapped[str] = mapped_column(String(16), nullable=False, unique=True, server_default=FetchedValue()) + secret: Mapped[str] = mapped_column(String(16), nullable=False, unique=True, index=True, server_default=FetchedValue()) flag_valid: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) issued_when: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) point_value: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - arXiv_categories = relationship('Category', primaryjoin='and_(EndorsementRequest.archive == Category.archive, EndorsementRequest.subject_class == Category.subject_class)', back_populates='arXiv_endorsement_requests') - endorsee = relationship('TapirUser', primaryjoin='EndorsementRequest.endorsee_id == TapirUser.user_id', back_populates='arXiv_endorsement_requests', uselist=False) - endorsement = relationship('Endorsement', back_populates='request', uselist=False) - audit = relationship('EndorsementRequestsAudit', uselist=False) + arXiv_categories: Mapped["Category"] = relationship( + "Category", primaryjoin="and_(EndorsementRequest.archive == Category.archive, EndorsementRequest.subject_class == Category.subject_class)", back_populates="arXiv_endorsement_requests" + ) + endorsee: Mapped["TapirUser"] = relationship("TapirUser", primaryjoin="EndorsementRequest.endorsee_id == TapirUser.user_id", back_populates="arXiv_endorsement_requests", uselist=False) + endorsement: Mapped["Endorsement"] = relationship("Endorsement", back_populates="request", uselist=False) + audit = relationship("EndorsementRequestsAudit", uselist=False) + arXiv_ownership_requests: Mapped[List["OwnershipRequest"]] = relationship("OwnershipRequest", back_populates="endorsement_request") class EndorsementRequestsAudit(EndorsementRequest): - __tablename__ = 'arXiv_endorsement_requests_audit' + __tablename__ = "arXiv_endorsement_requests_audit" + __table_args__ = {"mysql_charset": "latin1"} - request_id: Mapped[int] = mapped_column(ForeignKey('arXiv_endorsement_requests.request_id'), primary_key=True, server_default=FetchedValue()) + request_id: Mapped[int] = mapped_column(ForeignKey("arXiv_endorsement_requests.request_id"), primary_key=True, server_default=FetchedValue()) session_id: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) remote_addr: Mapped[Optional[str]] = mapped_column(String(16)) - remote_host: Mapped[Optional[str]] - tracking_cookie: Mapped[Optional[str]] - + remote_host: Mapped[Optional[str]] = mapped_column(String(255)) + tracking_cookie: Mapped[Optional[str]] = mapped_column(String(255)) class Endorsement(Base): - __tablename__ = 'arXiv_endorsements' + __tablename__ = "arXiv_endorsements" __table_args__ = ( - ForeignKeyConstraint(['archive', 'subject_class'], ['arXiv_categories.archive', 'arXiv_categories.subject_class']), - Index('endorsement_archive', 'archive', 'subject_class'), - Index('endorser_id_2', 'endorser_id', 'endorsee_id', 'archive', 'subject_class') + ForeignKeyConstraint(["archive", "subject_class"], ["arXiv_categories.archive", "arXiv_categories.subject_class"]), + Index("endorser_id_2", "endorser_id", "endorsee_id", "archive", "subject_class", unique=True), + {"mysql_charset": "latin1"}, ) endorsement_id: Mapped[intpk] - endorser_id: Mapped[Optional[int]] = mapped_column(ForeignKey('tapir_users.user_id'), index=True) - endorsee_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()) + endorser_id: Mapped[Optional[int]] = mapped_column(ForeignKey("tapir_users.user_id"), index=True) + endorsee_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), nullable=False, index=True, server_default=FetchedValue()) archive: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) subject_class: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) flag_valid: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - type: Mapped[Optional[Literal['user', 'admin', 'auto']]] = mapped_column(Enum('user', 'admin', 'auto')) + type: Mapped[Optional[Literal["user", "admin", "auto"]]] = mapped_column(Enum("user", "admin", "auto")) point_value: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) issued_when: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - request_id: Mapped[Optional[int]] = mapped_column(ForeignKey('arXiv_endorsement_requests.request_id'), index=True) + request_id: Mapped[Optional[int]] = mapped_column(ForeignKey("arXiv_endorsement_requests.request_id"), index=True) - arXiv_categories = relationship('Category', primaryjoin='and_(Endorsement.archive == Category.archive, Endorsement.subject_class == Category.subject_class)', back_populates='arXiv_endorsements') - endorsee = relationship('TapirUser', primaryjoin='Endorsement.endorsee_id == TapirUser.user_id', back_populates='endorsee_of') - endorser = relationship('TapirUser', primaryjoin='Endorsement.endorser_id == TapirUser.user_id', back_populates='endorses') - request = relationship('EndorsementRequest', primaryjoin='Endorsement.request_id == EndorsementRequest.request_id', back_populates='endorsement') + arXiv_categories: Mapped["Category"] = relationship("Category", back_populates="arXiv_endorsements") + endorsee: Mapped["TapirUser"] = relationship("TapirUser", primaryjoin="Endorsement.endorsee_id == TapirUser.user_id", back_populates="endorsee_of") + endorser: Mapped["TapirUser"] = relationship("TapirUser", primaryjoin="Endorsement.endorser_id == TapirUser.user_id", back_populates="endorses") + request: Mapped["EndorsementRequest"] = relationship("EndorsementRequest", back_populates="endorsement") class EndorsementsAudit(Endorsement): - __tablename__ = 'arXiv_endorsements_audit' + __tablename__ = "arXiv_endorsements_audit" + __table_args__ = {"mysql_charset": "latin1"} - endorsement_id: Mapped[int] = mapped_column(ForeignKey('arXiv_endorsements.endorsement_id'), primary_key=True, server_default=FetchedValue()) + endorsement_id: Mapped[int] = mapped_column(ForeignKey("arXiv_endorsements.endorsement_id"), primary_key=True, server_default=FetchedValue()) session_id: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) remote_addr: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) @@ -548,180 +591,182 @@ class EndorsementsAudit(Endorsement): comment: Mapped[Optional[str]] = mapped_column(Text) - class FreezeLog(Base): - __tablename__ = 'arXiv_freeze_log' + __tablename__ = "arXiv_freeze_log" + __table_args__ = {"mysql_charset": "latin1"} date: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) - class GroupDef(Base): - __tablename__ = 'arXiv_group_def' + __tablename__ = "arXiv_group_def" + __table_args__ = {"mysql_charset": "latin1"} archive_group: Mapped[str] = mapped_column(String(16), primary_key=True, server_default=FetchedValue()) - name: Mapped[Optional[str]] - + name: Mapped[Optional[str]] = mapped_column(String(255)) class Group(Base): - __tablename__ = 'arXiv_groups' + __tablename__ = "arXiv_groups" + __table_args__ = {"mysql_charset": "latin1"} group_id: Mapped[str] = mapped_column(String(16), primary_key=True, server_default=FetchedValue()) group_name: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) start_year: Mapped[str] = mapped_column(String(4), nullable=False, server_default=FetchedValue()) + arXiv_archives: Mapped[List["Archive"]] = relationship("Archive", back_populates="arXiv_group") t_arXiv_in_category = Table( - 'arXiv_in_category', metadata, - Column('document_id', ForeignKey('arXiv_documents.document_id'), nullable=False, index=True, server_default=FetchedValue()), - Column('archive', String(16), nullable=False, server_default=FetchedValue()), - Column('subject_class', String(16), nullable=False, server_default=FetchedValue()), - Column('is_primary', Integer, nullable=False, server_default=FetchedValue()), - ForeignKeyConstraint(['archive', 'subject_class'], ['arXiv_categories.archive', 'arXiv_categories.subject_class']), - Index('in_cat_archive', 'archive', 'subject_class', 'document_id'), - Index('arXiv_in_category_mp', 'archive', 'subject_class') + "arXiv_in_category", + metadata, + Column("document_id", ForeignKey("arXiv_documents.document_id"), nullable=False, index=True, server_default=FetchedValue()), + Column("archive", String(16), nullable=False, server_default=FetchedValue()), + Column("subject_class", String(16), nullable=False, server_default=FetchedValue()), + Column("is_primary", Integer, nullable=False, server_default=FetchedValue()), + ForeignKeyConstraint(["archive", "subject_class"], ["arXiv_categories.archive", "arXiv_categories.subject_class"]), + Index("arXiv_in_category_mp", "archive", "subject_class"), + Index("in_cat_archive", "archive", "subject_class", "document_id", unique=True), ) class JrefControl(Base): - __tablename__ = 'arXiv_jref_control' - __table_args__ = ( - Index('jref_ctrl_document_id', 'document_id', 'version'), - ) + __tablename__ = "arXiv_jref_control" + __table_args__ = (Index("jref_ctrl_document_id", "document_id", "version", unique=True), {"mysql_charset": "latin1"}) control_id: Mapped[intpk] - document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id'), nullable=False, server_default=FetchedValue()) + document_id: Mapped[int] = mapped_column(ForeignKey("arXiv_documents.document_id"), nullable=False, server_default=FetchedValue()) version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()) - status: Mapped[Literal['new', 'frozen', 'published', 'rejected']] = mapped_column(Enum('new', 'frozen', 'published', 'rejected'), nullable=False, index=True, server_default=FetchedValue()) - flag_must_notify: Mapped[Optional[Literal['0', '1']]] = mapped_column(Enum('0', '1'), server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), nullable=False, index=True, server_default=FetchedValue()) + status: Mapped[Literal["new", "frozen", "published", "rejected"]] = mapped_column(Enum("new", "frozen", "published", "rejected"), nullable=False, index=True, server_default=FetchedValue()) + flag_must_notify: Mapped[Optional[Literal["0", "1"]]] = mapped_column(Enum("0", "1"), server_default=FetchedValue()) jref: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) request_date: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) freeze_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) publish_date: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - document = relationship('Document', primaryjoin='JrefControl.document_id == Document.document_id', backref='arXiv_jref_controls') - user = relationship('TapirUser', primaryjoin='JrefControl.user_id == TapirUser.user_id', back_populates='arXiv_jref_controls') - + document: Mapped["Document"] = relationship("Document", back_populates="arXiv_jref_controls") + user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_jref_controls") class License(Base): - __tablename__ = 'arXiv_licenses' + __tablename__ = "arXiv_licenses" + __table_args__ = {"mysql_charset": "latin1"} name: Mapped[str] = mapped_column(String(255), primary_key=True) - label: Mapped[Optional[str]] + label: Mapped[Optional[str]] = mapped_column(String(255)) active: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) note: Mapped[Optional[str]] = mapped_column(String(400)) sequence: Mapped[Optional[int]] = mapped_column(Integer) + arXiv_submissions: Mapped[List["Submission"]] = relationship("Submission", back_populates="arXiv_license") class LogPosition(Base): - __tablename__ = 'arXiv_log_positions' + __tablename__ = "arXiv_log_positions" + __table_args__ = {"mysql_charset": "latin1"} id: Mapped[str] = mapped_column(String(255), primary_key=True, server_default=FetchedValue()) - position: Mapped[Optional[int]] - date: Mapped[Optional[int]] - + position: Mapped[Optional[int]] = mapped_column(Integer) + date: Mapped[Optional[int]] = mapped_column(Integer) class Metadata(Base): - __tablename__ = 'arXiv_metadata' - __table_args__ = ( - Index('pidv', 'paper_id', 'version'), - ) + __tablename__ = "arXiv_metadata" + __table_args__ = (Index("pidv", "paper_id", "version", unique=True), {"mysql_charset": "latin1"}) metadata_id: Mapped[intpk] - document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id', ondelete='CASCADE', onupdate='CASCADE'), nullable=False, index=True, server_default=FetchedValue()) + document_id: Mapped[int] = mapped_column(ForeignKey("arXiv_documents.document_id", ondelete="CASCADE", onupdate="CASCADE"), nullable=False, index=True, server_default=FetchedValue()) paper_id: Mapped[str] = mapped_column(String(64), nullable=False) - created: Mapped[Optional[datetime]] - updated: Mapped[Optional[datetime]] - submitter_id: Mapped[Optional[int]] = mapped_column(ForeignKey('tapir_users.user_id'), index=True) + created: Mapped[Optional[datetime]] = mapped_column(DateTime) + updated: Mapped[Optional[datetime]] = mapped_column(DateTime) + submitter_id: Mapped[Optional[int]] = mapped_column(ForeignKey("tapir_users.user_id"), index=True) submitter_name: Mapped[str] = mapped_column(String(64), nullable=False) submitter_email: Mapped[str] = mapped_column(String(64), nullable=False) source_size: Mapped[Optional[int]] = mapped_column(Integer) - source_format: Mapped[Optional[Literal['tex', 'ps', 'html', 'pdf', 'withdrawn', 'pdftex', 'docx']]] = mapped_column(String(12)) + source_format: Mapped[Optional[SOURCE_FORMAT]] = mapped_column(String(12)) source_flags: Mapped[Optional[str]] = mapped_column(String(12)) title: Mapped[Optional[str]] = mapped_column(Text) authors: Mapped[Optional[str]] = mapped_column(Text) - abs_categories: Mapped[Optional[str]] + abs_categories: Mapped[Optional[str]] = mapped_column(String(255)) comments: Mapped[Optional[str]] = mapped_column(Text) - proxy: Mapped[Optional[str]] + proxy: Mapped[Optional[str]] = mapped_column(String(255)) report_num: Mapped[Optional[str]] = mapped_column(Text) - msc_class: Mapped[Optional[str]] - acm_class: Mapped[Optional[str]] + msc_class: Mapped[Optional[str]] = mapped_column(String(255)) + acm_class: Mapped[Optional[str]] = mapped_column(String(255)) journal_ref: Mapped[Optional[str]] = mapped_column(Text) - doi: Mapped[Optional[str]] + doi: Mapped[Optional[str]] = mapped_column(String(255)) abstract: Mapped[Optional[str]] = mapped_column(Text) - license: Mapped[Optional[str]] = mapped_column(ForeignKey('arXiv_licenses.name'), index=True) + license: Mapped[Optional[str]] = mapped_column(ForeignKey("arXiv_licenses.name"), index=True) version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) modtime: Mapped[Optional[int]] = mapped_column(Integer) is_current: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) is_withdrawn: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - document = relationship('Document', primaryjoin='Metadata.document_id == Document.document_id', backref='arXiv_metadata') - arXiv_license = relationship('License', primaryjoin='Metadata.license == License.name', backref='arXiv_metadata') - submitter = relationship('TapirUser', primaryjoin='Metadata.submitter_id == TapirUser.user_id', back_populates='arXiv_metadata') - + document: Mapped["Document"] = relationship("Document", primaryjoin="Metadata.document_id == Document.document_id", back_populates="arXiv_metadata") + submitter: Mapped["TapirUser"] = relationship("TapirUser", primaryjoin="Metadata.submitter_id == TapirUser.user_id", back_populates="arXiv_metadata") + arXiv_datacite_dois: Mapped[List["DataciteDois"]] = relationship("DataciteDois", back_populates="metadata_") + # Link to the license + arXiv_license = relationship("License", primaryjoin="Metadata.license == License.name", backref="arXiv_metadata") class MirrorList(Base): - __tablename__ = 'arXiv_mirror_list' + __tablename__ = "arXiv_mirror_list" + __table_args__ = {"mysql_charset": "latin1"} mirror_list_id: Mapped[intpk] - created: Mapped[Optional[datetime]] - updated: Mapped[Optional[datetime]] - document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id'), nullable=False, index=True, server_default=FetchedValue()) + created: Mapped[Optional[datetime]] = mapped_column(DateTime) + updated: Mapped[Optional[datetime]] = mapped_column(DateTime) + document_id: Mapped[int] = mapped_column(ForeignKey("arXiv_documents.document_id"), nullable=False, index=True, server_default=FetchedValue()) version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) write_source: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) write_abs: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) is_written: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - document = relationship('Document', primaryjoin='MirrorList.document_id == Document.document_id', backref='arXiv_mirror_lists') - + document: Mapped["Document"] = relationship("Document", back_populates="arXiv_mirror_list") class ModeratorApiKey(Base): - __tablename__ = 'arXiv_moderator_api_key' + __tablename__ = "arXiv_moderator_api_key" + __table_args__ = {"mysql_charset": "utf8mb3"} - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, nullable=False, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), primary_key=True, nullable=False, server_default=FetchedValue()) secret: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False, server_default=FetchedValue()) valid: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) issued_when: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) issued_to: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) - user = relationship('TapirUser', primaryjoin='ModeratorApiKey.user_id == TapirUser.user_id', back_populates='arXiv_moderator_api_keys') - + user: Mapped["TapirUser"] = relationship("TapirUser", primaryjoin="ModeratorApiKey.user_id == TapirUser.user_id", back_populates="arXiv_moderator_api_keys") t_arXiv_moderators = Table( - 'arXiv_moderators', metadata, - Column('user_id', ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()), - Column('archive', ForeignKey('arXiv_archive_group.archive_id'), nullable=False, server_default=FetchedValue()), - Column('subject_class', String(16), nullable=False, server_default=FetchedValue()), - Column('is_public', Integer, nullable=False, server_default=FetchedValue()), - Column('no_email', Integer, index=True, server_default=FetchedValue()), - Column('no_web_email', Integer, index=True, server_default=FetchedValue()), - Column('no_reply_to', Integer, index=True, server_default=FetchedValue()), - Column('daily_update', Integer, server_default=FetchedValue()), - ForeignKeyConstraint(['archive', 'subject_class'], ['arXiv_categories.archive', 'arXiv_categories.subject_class']), - Index('mod_user_id', 'archive', 'subject_class', 'user_id') + "arXiv_moderators", + metadata, + Column("user_id", ForeignKey("tapir_users.user_id"), nullable=False, index=True, server_default=FetchedValue()), + Column("archive", ForeignKey("arXiv_archive_group.archive_id"), nullable=False, server_default=FetchedValue()), + Column("subject_class", String(16), nullable=False, server_default=FetchedValue()), + Column("is_public", Integer, nullable=False, server_default=FetchedValue()), + Column("no_email", Integer, index=True, server_default=FetchedValue()), + Column("no_web_email", Integer, index=True, server_default=FetchedValue()), + Column("no_reply_to", Integer, index=True, server_default=FetchedValue()), + Column("daily_update", Integer, server_default=FetchedValue()), + ForeignKeyConstraint(["archive", "subject_class"], ["arXiv_categories.archive", "arXiv_categories.subject_class"]), + Index("mod_user_id", "archive", "subject_class", "user_id", unique=True), ) class MonitorKlog(Base): - __tablename__ = 'arXiv_monitor_klog' + __tablename__ = "arXiv_monitor_klog" + __table_args__ = {"mysql_charset": "latin1"} t: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) sent: Mapped[Optional[int]] = mapped_column(Integer) - class MonitorMailq(Base): - __tablename__ = 'arXiv_monitor_mailq' + __tablename__ = "arXiv_monitor_mailq" + __table_args__ = {"mysql_charset": "latin1"} t: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) main_q: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) @@ -732,20 +777,17 @@ class MonitorMailq(Base): local_in_flight: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - class MonitorMailsent(Base): - __tablename__ = 'arXiv_monitor_mailsent' + __tablename__ = "arXiv_monitor_mailsent" + __table_args__ = {"mysql_charset": "latin1"} t: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) sent: Mapped[Optional[int]] = mapped_column(Integer) - class NextMail(Base): - __tablename__ = 'arXiv_next_mail' - __table_args__ = ( - Index('arXiv_next_mail_idx_document_id_version', 'document_id', 'version'), - ) + __tablename__ = "arXiv_next_mail" + __table_args__ = (Index("arXiv_next_mail_idx_document_id_version", "document_id", "version"), {"mysql_charset": "latin1"}) next_mail_id: Mapped[intpk] submission_id: Mapped[int] = mapped_column(Integer, nullable=False) @@ -753,14 +795,14 @@ class NextMail(Base): paper_id: Mapped[Optional[str]] = mapped_column(String(20)) version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) type: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) - extra: Mapped[Optional[str]] + extra: Mapped[Optional[str]] = mapped_column(String(255)) mail_id: Mapped[Optional[str]] = mapped_column(String(6)) is_written: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - class OrcidConfig(Base): - __tablename__ = 'arXiv_orcid_config' + __tablename__ = "arXiv_orcid_config" + __table_args__ = {"mysql_charset": "utf8mb3"} domain: Mapped[str] = mapped_column(String(75), primary_key=True, nullable=False) keyname: Mapped[str] = mapped_column(String(60), primary_key=True, nullable=False) @@ -768,66 +810,67 @@ class OrcidConfig(Base): t_arXiv_ownership_requests_papers = Table( - 'arXiv_ownership_requests_papers', metadata, - Column('request_id', ForeignKey('arXiv_ownership_requests.request_id'), nullable=False, server_default=FetchedValue()), - Column('document_id', ForeignKey('arXiv_documents.document_id'), nullable=False, index=True, server_default=FetchedValue()), - Index('request_id', 'request_id', 'document_id', unique=True) + "arXiv_ownership_requests_papers", + metadata, + Column("request_id", ForeignKey("arXiv_ownership_requests.request_id"), nullable=False, server_default=FetchedValue()), + Column("document_id", ForeignKey("arXiv_documents.document_id"), nullable=False, index=True, server_default=FetchedValue()), + Index("request_id", "request_id", "document_id", unique=True), ) + class OwnershipRequest(Base): - __tablename__ = 'arXiv_ownership_requests' + __tablename__ = "arXiv_ownership_requests" + __table_args__ = {"mysql_charset": "latin1"} request_id: Mapped[intpk] - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()) - endorsement_request_id: Mapped[Optional[int]] = mapped_column(ForeignKey('arXiv_endorsement_requests.request_id'), index=True) - workflow_status: Mapped[Literal['pending', 'accepted', 'rejected']] = mapped_column(Enum('pending', 'accepted', 'rejected'), nullable=False, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), nullable=False, index=True, server_default=FetchedValue()) + endorsement_request_id: Mapped[Optional[int]] = mapped_column(ForeignKey("arXiv_endorsement_requests.request_id"), index=True) + workflow_status: Mapped[Literal["pending", "accepted", "rejected"]] = mapped_column(Enum("pending", "accepted", "rejected"), nullable=False, server_default=FetchedValue()) + request_audit = relationship("OwnershipRequestsAudit", back_populates="ownership_request", uselist=False) - request_audit = relationship('OwnershipRequestsAudit', back_populates='ownership_request', uselist=False) - endorsement_request = relationship('EndorsementRequest', primaryjoin='OwnershipRequest.endorsement_request_id == EndorsementRequest.request_id', backref='arXiv_ownership_requests') - user = relationship('TapirUser', primaryjoin='OwnershipRequest.user_id == TapirUser.user_id', back_populates='arXiv_ownership_requests') + endorsement_request: Mapped["EndorsementRequest"] = relationship( + "EndorsementRequest", primaryjoin="OwnershipRequest.endorsement_request_id == EndorsementRequest.request_id", back_populates="arXiv_ownership_requests" + ) + user: Mapped["TapirUser"] = relationship("TapirUser", primaryjoin="OwnershipRequest.user_id == TapirUser.user_id", back_populates="arXiv_ownership_requests") documents = relationship("Document", secondary=t_arXiv_ownership_requests_papers) + class OwnershipRequestsAudit(Base): - __tablename__ = 'arXiv_ownership_requests_audit' + __tablename__ = "arXiv_ownership_requests_audit" + __table_args__ = {"mysql_charset": "latin1"} - request_id: Mapped[int] = mapped_column(ForeignKey('arXiv_ownership_requests.request_id'), primary_key=True, server_default=FetchedValue()) + request_id: Mapped[int] = mapped_column(ForeignKey("arXiv_ownership_requests.request_id"), primary_key=True, server_default=FetchedValue()) session_id: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) remote_addr: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) tracking_cookie: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) date: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - ownership_request = relationship('OwnershipRequest', primaryjoin='OwnershipRequestsAudit.request_id == OwnershipRequest.request_id', back_populates='request_audit', uselist=False) + ownership_request = relationship("OwnershipRequest", primaryjoin="OwnershipRequestsAudit.request_id == OwnershipRequest.request_id", back_populates="request_audit", uselist=False) class PaperOwner(Base): - __tablename__ = 'arXiv_paper_owners' - __table_args__ = ( - ForeignKeyConstraint(['added_by'], ['tapir_users.user_id'], name='0_595'), - ForeignKeyConstraint(['document_id'], ['arXiv_documents.document_id'], name='0_593'), - ForeignKeyConstraint(['user_id'], ['tapir_users.user_id'], name='0_594'), - Index('added_by', 'added_by'), - # Index('document_id', 'document_id', 'user_id', unique=True), - # Index('user_id', 'user_id'), - ) + __tablename__ = "arXiv_paper_owners" + __table_args__ = (PrimaryKeyConstraint("document_id", "user_id"), {"mysql_charset": "latin1"}) - document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id'), primary_key=True) - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True) + document_id: Mapped[int] = mapped_column(ForeignKey("arXiv_documents.document_id")) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id")) date: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) - added_by: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + added_by: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), nullable=False, index=True, server_default=text("'0'")) remote_addr: Mapped[str] = mapped_column(String(16), nullable=False, server_default=text("''")) remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=text("''")) tracking_cookie: Mapped[str] = mapped_column(String(32), nullable=False, server_default=text("''")) - valid: Mapped[int] = mapped_column(SmallInteger, nullable=False, server_default=text("'0'")) - flag_author: Mapped[int] = mapped_column(SmallInteger, nullable=False, server_default=text("'0'")) - flag_auto: Mapped[int] = mapped_column(SmallInteger, nullable=False, server_default=text("'1'")) + valid: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + flag_author: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + flag_auto: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) - document = relationship('Document', back_populates='owners') - owner = relationship('TapirUser', foreign_keys="[PaperOwner.user_id]", back_populates='owned_papers') + document: Mapped["Document"] = relationship("Document", back_populates="owners") + owner = relationship("TapirUser", foreign_keys="[PaperOwner.user_id]", back_populates="owned_papers") class PaperSession(Base): - __tablename__ = 'arXiv_paper_sessions' + __tablename__ = "arXiv_paper_sessions" + __table_args__ = {"mysql_charset": "latin1"} paper_session_id: Mapped[intpk] paper_id: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) @@ -836,58 +879,53 @@ class PaperSession(Base): ip_name: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) - class PilotFile(Base): - __tablename__ = 'arXiv_pilot_files' + """arXiv_pilot is deprecated""" + + __tablename__ = "arXiv_pilot_files" + __table_args__ = {"mysql_charset": "latin1"} file_id: Mapped[intpk] - submission_id: Mapped[int] = mapped_column(ForeignKey('arXiv_submissions.submission_id'), nullable=False, index=True) + submission_id: Mapped[int] = mapped_column(ForeignKey("arXiv_submissions.submission_id"), nullable=False, index=True) filename: Mapped[Optional[str]] = mapped_column(String(256), server_default=FetchedValue()) entity_url: Mapped[Optional[str]] = mapped_column(String(256)) description: Mapped[Optional[str]] = mapped_column(String(80)) byRef: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) - submission = relationship('Submission', primaryjoin='PilotFile.submission_id == Submission.submission_id', backref='arXiv_pilot_files') - + submission: Mapped["Submission"] = relationship("Submission", back_populates="arXiv_pilot_files") class PublishLog(Base): - __tablename__ = 'arXiv_publish_log' + __tablename__ = "arXiv_publish_log" + __table_args__ = {"mysql_charset": "latin1"} date: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) - -t_arXiv_refresh_list = Table( - 'arXiv_refresh_list', metadata, - Column('filename', String(255)), - Column('mtime', Integer, index=True) -) +t_arXiv_refresh_list = Table("arXiv_refresh_list", metadata, Column("filename", String(255)), Column("mtime", Integer, index=True)) class RejectSessionUsername(Base): - __tablename__ = 'arXiv_reject_session_usernames' + __tablename__ = "arXiv_reject_session_usernames" + __table_args__ = {"mysql_charset": "latin1"} username: Mapped[str] = mapped_column(String(64), primary_key=True, server_default=FetchedValue()) - class SciencewisePing(Base): - __tablename__ = 'arXiv_sciencewise_pings' + __tablename__ = "arXiv_sciencewise_pings" + __table_args__ = {"mysql_charset": "utf8mb3"} paper_id_v: Mapped[str] = mapped_column(String(32), primary_key=True) - updated: Mapped[Optional[datetime]] - + updated: Mapped[Optional[datetime]] = mapped_column(DateTime) class ShowEmailRequest(Base): - __tablename__ = 'arXiv_show_email_requests' - __table_args__ = ( - Index('email_reqs_user_id', 'user_id', 'dated'), - ) + __tablename__ = "arXiv_show_email_requests" + __table_args__ = (Index("email_reqs_user_id", "user_id", "dated"), {"mysql_charset": "latin1"}) - document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id'), nullable=False, index=True, server_default=FetchedValue()) - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, server_default=FetchedValue()) + document_id: Mapped[int] = mapped_column(ForeignKey("arXiv_documents.document_id"), nullable=False, index=True, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), nullable=False, server_default=FetchedValue()) session_id: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) dated: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) flag_allowed: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) @@ -896,211 +934,209 @@ class ShowEmailRequest(Base): tracking_cookie: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) request_id: Mapped[intpk] - document = relationship('Document', primaryjoin='ShowEmailRequest.document_id == Document.document_id', backref='arXiv_show_email_requests') - user = relationship('TapirUser', primaryjoin='ShowEmailRequest.user_id == TapirUser.user_id', back_populates='arXiv_show_email_requests') - + document: Mapped["Document"] = relationship("Document", back_populates="arXiv_show_email_requests") + user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_show_email_requests") class State(Base): - __tablename__ = 'arXiv_state' + __tablename__ = "arXiv_state" + __table_args__ = {"mysql_charset": "latin1"} id: Mapped[intpk] name: Mapped[Optional[str]] = mapped_column(String(24)) value: Mapped[Optional[str]] = mapped_column(String(24)) - t_arXiv_stats_hourly = Table( - 'arXiv_stats_hourly', metadata, - Column('ymd', Date, nullable=False, index=True), - Column('hour', Integer, nullable=False, index=True), - Column('node_num', Integer, nullable=False, index=True), - Column('access_type', String(1), nullable=False, index=True), - Column('connections', Integer, nullable=False) + "arXiv_stats_hourly", + metadata, + Column("ymd", Date, nullable=False, index=True), + Column("hour", Integer, nullable=False, index=True), + Column("node_num", Integer, nullable=False, index=True), + Column("access_type", String(1), nullable=False, index=True), + Column("connections", Integer, nullable=False), ) class StatsMonthlyDownload(Base): - __tablename__ = 'arXiv_stats_monthly_downloads' + __tablename__ = "arXiv_stats_monthly_downloads" + __table_args__ = {"mysql_charset": "latin1"} - ym: Mapped[date] = mapped_column(Date, primary_key=True) + ym: Mapped[dt.date] = mapped_column(Date, primary_key=True) downloads: Mapped[int] = mapped_column(Integer, nullable=False) - class StatsMonthlySubmission(Base): - __tablename__ = 'arXiv_stats_monthly_submissions' + __tablename__ = "arXiv_stats_monthly_submissions" + __table_args__ = {"mysql_charset": "latin1"} - ym: Mapped[date] = mapped_column(Date, primary_key=True, server_default=FetchedValue()) - num_submissions: Mapped[int] = mapped_column(SmallInteger, nullable=False) + ym: Mapped[dt.date] = mapped_column(Date, primary_key=True, server_default=FetchedValue()) + num_submissions: Mapped[int] = mapped_column(Integer, nullable=False) historical_delta: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - class SubmissionAgreement(Base): - __tablename__ = 'arXiv_submission_agreements' + __tablename__ = "arXiv_submission_agreements" + __table_args__ = {"mysql_charset": "latin1"} - agreement_id: Mapped[int] = mapped_column(SmallInteger, primary_key=True) + agreement_id: Mapped[int] = mapped_column(Integer, primary_key=True) effective_date: Mapped[Optional[datetime]] = mapped_column(DateTime, server_default=FetchedValue()) commit_ref: Mapped[str] = mapped_column(String(255), nullable=False) content: Mapped[Optional[str]] = mapped_column(Text) + arXiv_submissions: Mapped[List["Submission"]] = relationship("Submission", back_populates="agreement") class SubmissionCategory(Base): - __tablename__ = 'arXiv_submission_category' + __tablename__ = "arXiv_submission_category" + __table_args__ = {"mysql_charset": "latin1"} - submission_id: Mapped[int] = mapped_column(ForeignKey('arXiv_submissions.submission_id', ondelete='CASCADE', onupdate='CASCADE'), primary_key=True, nullable=False, index=True) - category: Mapped[str] = mapped_column(ForeignKey('arXiv_category_def.category'), primary_key=True, nullable=False, index=True, server_default=FetchedValue()) + submission_id: Mapped[int] = mapped_column(ForeignKey("arXiv_submissions.submission_id", ondelete="CASCADE", onupdate="CASCADE"), primary_key=True, nullable=False, index=True) + category: Mapped[str] = mapped_column(ForeignKey("arXiv_category_def.category"), primary_key=True, nullable=False, index=True, server_default=FetchedValue()) is_primary: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) is_published: Mapped[Optional[int]] = mapped_column(Integer, index=True, server_default=FetchedValue()) - arXiv_category_def = relationship('CategoryDef', primaryjoin='SubmissionCategory.category == CategoryDef.category', backref='arXiv_submission_categories') - submission = relationship('Submission', primaryjoin='SubmissionCategory.submission_id == Submission.submission_id', backref='arXiv_submission_categories') - + arXiv_category_def: Mapped["CategoryDef"] = relationship("CategoryDef", back_populates="arXiv_submission_category") + submission: Mapped["Submission"] = relationship("Submission", back_populates="arXiv_submission_category") class SubmissionCategoryProposal(Base): - __tablename__ = 'arXiv_submission_category_proposal' + __tablename__ = "arXiv_submission_category_proposal" + __table_args__ = {"mysql_charset": "utf8mb3"} proposal_id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, index=True) - submission_id: Mapped[int] = mapped_column(ForeignKey('arXiv_submissions.submission_id', ondelete='CASCADE', onupdate='CASCADE'), primary_key=True, nullable=False, index=True) - category: Mapped[str] = mapped_column(ForeignKey('arXiv_category_def.category'), primary_key=True, nullable=False, index=True) + submission_id: Mapped[int] = mapped_column(ForeignKey("arXiv_submissions.submission_id", ondelete="CASCADE", onupdate="CASCADE"), primary_key=True, nullable=False, index=True) + category: Mapped[str] = mapped_column(ForeignKey("arXiv_category_def.category"), primary_key=True, nullable=False, index=True) is_primary: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, index=True, server_default=FetchedValue()) proposal_status: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, index=True) - updated: Mapped[Optional[datetime]] - proposal_comment_id: Mapped[Optional[int]] = mapped_column(ForeignKey('arXiv_admin_log.id'), index=True) - response_comment_id: Mapped[Optional[int]] = mapped_column(ForeignKey('arXiv_admin_log.id'), index=True) - - arXiv_category_def = relationship('CategoryDef', primaryjoin='SubmissionCategoryProposal.category == CategoryDef.category', backref='arXiv_submission_category_proposals') - proposal_comment = relationship('AdminLog', primaryjoin='SubmissionCategoryProposal.proposal_comment_id == AdminLog.id', backref='arxivadminlog_arXiv_submission_category_proposals') - response_comment = relationship('AdminLog', primaryjoin='SubmissionCategoryProposal.response_comment_id == AdminLog.id', backref='arxivadminlog_arXiv_submission_category_proposals_0') - submission = relationship('Submission', primaryjoin='SubmissionCategoryProposal.submission_id == Submission.submission_id', backref='arXiv_submission_category_proposals') - user = relationship('TapirUser', primaryjoin='SubmissionCategoryProposal.user_id == TapirUser.user_id', back_populates='arXiv_submission_category_proposal') + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), nullable=False, index=True) + updated: Mapped[Optional[datetime]] = mapped_column(DateTime) + proposal_comment_id: Mapped[Optional[int]] = mapped_column(ForeignKey("arXiv_admin_log.id"), index=True) + response_comment_id: Mapped[Optional[int]] = mapped_column(ForeignKey("arXiv_admin_log.id"), index=True) + arXiv_category_def: Mapped["CategoryDef"] = relationship( + "CategoryDef", primaryjoin="SubmissionCategoryProposal.category == CategoryDef.category", back_populates="arXiv_submission_category_proposal" + ) + proposal_comment: Mapped["AdminLog"] = relationship("AdminLog", primaryjoin="SubmissionCategoryProposal.proposal_comment_id == AdminLog.id", back_populates="arXiv_submission_category_proposal") + response_comment: Mapped["AdminLog"] = relationship("AdminLog", primaryjoin="SubmissionCategoryProposal.response_comment_id == AdminLog.id", back_populates="arXiv_submission_category_proposal_") + submission: Mapped["Submission"] = relationship( + "Submission", primaryjoin="SubmissionCategoryProposal.submission_id == Submission.submission_id", back_populates="arXiv_submission_category_proposal" + ) + user: Mapped["TapirUser"] = relationship("TapirUser", primaryjoin="SubmissionCategoryProposal.user_id == TapirUser.user_id", back_populates="arXiv_submission_category_proposal") class SubmissionControl(Base): - __tablename__ = 'arXiv_submission_control' - __table_args__ = ( - Index('sub_ctrl_document_id', 'document_id', 'version'), - ) + __tablename__ = "arXiv_submission_control" + __table_args__ = (Index("sub_ctrl_document_id", "document_id", "version", unique=True), {"mysql_charset": "latin1"}) control_id: Mapped[intpk] - document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id'), nullable=False, server_default=FetchedValue()) + document_id: Mapped[int] = mapped_column(ForeignKey("arXiv_documents.document_id"), nullable=False, server_default=FetchedValue()) version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) pending_paper_id: Mapped[str] = mapped_column(String(20), nullable=False, index=True, server_default=FetchedValue()) - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()) - status: Mapped[Literal['new', 'frozen', 'published', 'rejected']] = mapped_column(Enum('new', 'frozen', 'published', 'rejected'), nullable=False, index=True, server_default=FetchedValue()) - flag_must_notify: Mapped[Optional[Literal['0', '1']]] = mapped_column(Enum('0', '1'), server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), nullable=False, index=True, server_default=FetchedValue()) + status: Mapped[Literal["new", "frozen", "published", "rejected"]] = mapped_column(Enum("new", "frozen", "published", "rejected"), nullable=False, index=True, server_default=FetchedValue()) + flag_must_notify: Mapped[Optional[Literal["0", "1"]]] = mapped_column(Enum("0", "1"), server_default=FetchedValue()) request_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) freeze_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) publish_date: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - document = relationship('Document', primaryjoin='SubmissionControl.document_id == Document.document_id', backref='arXiv_submission_controls') - user = relationship('TapirUser', primaryjoin='SubmissionControl.user_id == TapirUser.user_id', back_populates='arXiv_submission_control') - + document: Mapped["Document"] = relationship("Document", back_populates="arXiv_submission_control") + user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_submission_control") class SubmissionFlag(Base): - __tablename__ = 'arXiv_submission_flag' - __table_args__ = ( - Index('uniq_one_flag_per_mod', 'submission_id', 'user_id'), - ) + __tablename__ = "arXiv_submission_flag" + __table_args__ = (Index("uniq_one_flag_per_mod", "submission_id", "user_id", unique=True), {"mysql_charset": "utf8mb3"}) flag_id: Mapped[intpk] - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id', ondelete='CASCADE'), nullable=False, index=True, server_default=FetchedValue()) - submission_id: Mapped[int] = mapped_column(ForeignKey('arXiv_submissions.submission_id', ondelete='CASCADE'), nullable=False) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id", ondelete="CASCADE"), nullable=False, index=True, server_default=FetchedValue()) + submission_id: Mapped[int] = mapped_column(ForeignKey("arXiv_submissions.submission_id", ondelete="CASCADE"), nullable=False) flag: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) updated: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) - submission = relationship('Submission', primaryjoin='SubmissionFlag.submission_id == Submission.submission_id', backref='arXiv_submission_flags') - user = relationship('TapirUser', primaryjoin='SubmissionFlag.user_id == TapirUser.user_id', back_populates='arXiv_submission_flag') - + submission: Mapped["Submission"] = relationship("Submission", back_populates="arXiv_submission_flag") + user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_submission_flag") class SubmissionHoldReason(Base): - __tablename__ = 'arXiv_submission_hold_reason' + __tablename__ = "arXiv_submission_hold_reason" + __table_args__ = {"mysql_charset": "utf8mb3"} reason_id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False) - submission_id: Mapped[int] = mapped_column(ForeignKey('arXiv_submissions.submission_id', ondelete='CASCADE'), nullable=False, index=True) - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id', ondelete='CASCADE'), primary_key=True, nullable=False, index=True) + submission_id: Mapped[int] = mapped_column(ForeignKey("arXiv_submissions.submission_id", ondelete="CASCADE"), nullable=False, index=True) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id", ondelete="CASCADE"), primary_key=True, nullable=False, index=True) reason: Mapped[Optional[str]] = mapped_column(String(30)) type: Mapped[Optional[str]] = mapped_column(String(30)) - comment_id: Mapped[Optional[int]] = mapped_column(ForeignKey('arXiv_admin_log.id'), index=True) - - comment = relationship('AdminLog', primaryjoin='SubmissionHoldReason.comment_id == AdminLog.id', backref='arXiv_submission_hold_reasons') - submission = relationship('Submission', primaryjoin='SubmissionHoldReason.submission_id == Submission.submission_id', backref='arXiv_submission_hold_reasons') - user = relationship('TapirUser', primaryjoin='SubmissionHoldReason.user_id == TapirUser.user_id', back_populates='arXiv_submission_hold_reason') + comment_id: Mapped[Optional[int]] = mapped_column(ForeignKey("arXiv_admin_log.id"), index=True) + comment: Mapped["AdminLog"] = relationship("AdminLog", back_populates="arXiv_submission_hold_reason") + submission: Mapped["Submission"] = relationship("Submission", back_populates="arXiv_submission_hold_reason") + user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_submission_hold_reason") class SubmissionNearDuplicate(Base): - __tablename__ = 'arXiv_submission_near_duplicates' - __table_args__ = ( - Index('match', 'submission_id', 'matching_id'), - ) + __tablename__ = "arXiv_submission_near_duplicates" + __table_args__ = (Index("match", "submission_id", "matching_id", unique=True), {"mysql_charset": "utf8mb3"}) - submission_id: Mapped[int] = mapped_column(ForeignKey('arXiv_submissions.submission_id', ondelete='CASCADE'), primary_key=True, nullable=False, server_default=FetchedValue()) + submission_id: Mapped[int] = mapped_column(ForeignKey("arXiv_submissions.submission_id", ondelete="CASCADE"), primary_key=True, nullable=False, server_default=FetchedValue()) matching_id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, server_default=FetchedValue()) similarity: Mapped[float] = mapped_column(Numeric(2, 1), nullable=False) last_update: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) - submission = relationship('Submission', primaryjoin='SubmissionNearDuplicate.submission_id == Submission.submission_id', backref='arXiv_submission_near_duplicates') - + submission: Mapped["Submission"] = relationship("Submission", back_populates="arXiv_submission_near_duplicates") class SubmissionQaReport(Base): - __tablename__ = 'arXiv_submission_qa_reports' + __tablename__ = "arXiv_submission_qa_reports" + __table_args__ = {"mysql_charset": "utf8mb3"} id: Mapped[intpk] - submission_id: Mapped[int] = mapped_column(ForeignKey('arXiv_submissions.submission_id'), nullable=False, index=True) + submission_id: Mapped[int] = mapped_column(ForeignKey("arXiv_submissions.submission_id"), nullable=False, index=True) report_key_name: Mapped[str] = mapped_column(String(64), nullable=False, index=True) created: Mapped[Optional[datetime]] = mapped_column(DateTime, server_default=FetchedValue()) num_flags: Mapped[int] = mapped_column(SmallInteger, nullable=False, server_default=FetchedValue()) - report: Mapped[dict[str, Any]] = mapped_column(JSON, nullable=False) + report: Mapped[dict] = mapped_column(JSON, nullable=False) report_uri: Mapped[Optional[str]] = mapped_column(String(256)) - submission = relationship('Submission', primaryjoin='SubmissionQaReport.submission_id == Submission.submission_id', backref='arXiv_submission_qa_reports') - + submission: Mapped["Submission"] = relationship("Submission", back_populates="arXiv_submission_qa_reports") class SubmissionViewFlag(Base): - __tablename__ = 'arXiv_submission_view_flag' + __tablename__ = "arXiv_submission_view_flag" + __table_args__ = {"mysql_charset": "utf8mb3"} - submission_id: Mapped[int] = mapped_column(ForeignKey('arXiv_submissions.submission_id', ondelete='CASCADE'), primary_key=True, nullable=False) + submission_id: Mapped[int] = mapped_column(ForeignKey("arXiv_submissions.submission_id", ondelete="CASCADE"), primary_key=True, nullable=False) flag: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id', ondelete='CASCADE'), primary_key=True, nullable=False, index=True) - updated: Mapped[Optional[datetime]] - - submission = relationship('Submission', primaryjoin='SubmissionViewFlag.submission_id == Submission.submission_id', backref='arXiv_submission_view_flags') - user = relationship('TapirUser', primaryjoin='SubmissionViewFlag.user_id == TapirUser.user_id', back_populates='arXiv_submission_view_flag') + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id", ondelete="CASCADE"), primary_key=True, nullable=False, index=True) + updated: Mapped[Optional[datetime]] = mapped_column(DateTime) + submission: Mapped["Submission"] = relationship("Submission", back_populates="arXiv_submission_view_flag") + user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_submission_view_flag") class Submission(Base): - __tablename__ = 'arXiv_submissions' + __tablename__ = "arXiv_submissions" + __table_args__ = {"mysql_charset": "utf8mb3"} submission_id: Mapped[intpk] - document_id: Mapped[Optional[int]] = mapped_column(ForeignKey('arXiv_documents.document_id', ondelete='CASCADE', onupdate='CASCADE'), index=True) + document_id: Mapped[Optional[int]] = mapped_column(ForeignKey("arXiv_documents.document_id", ondelete="CASCADE", onupdate="CASCADE"), index=True) doc_paper_id: Mapped[Optional[str]] = mapped_column(String(20), index=True) - sword_id: Mapped[Optional[int]] = mapped_column(ForeignKey('arXiv_tracking.sword_id'), index=True) + sword_id: Mapped[Optional[int]] = mapped_column(ForeignKey("arXiv_tracking.sword_id"), index=True) userinfo: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) is_author: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) agree_policy: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) viewed: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) stage: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) - submitter_id: Mapped[Optional[int]] = mapped_column(ForeignKey('tapir_users.user_id', ondelete='CASCADE', onupdate='CASCADE'), index=True) + submitter_id: Mapped[Optional[int]] = mapped_column(ForeignKey("tapir_users.user_id", ondelete="CASCADE", onupdate="CASCADE"), index=True) submitter_name: Mapped[Optional[str]] = mapped_column(String(64)) submitter_email: Mapped[Optional[str]] = mapped_column(String(64)) - created: Mapped[Optional[datetime]] - updated: Mapped[Optional[datetime]] + created: Mapped[Optional[datetime]] = mapped_column(DateTime) + updated: Mapped[Optional[datetime]] = mapped_column(DateTime) status: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) sticky_status: Mapped[Optional[int]] = mapped_column(Integer) must_process: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) - submit_time: Mapped[Optional[datetime]] - release_time: Mapped[Optional[datetime]] + submit_time: Mapped[Optional[datetime]] = mapped_column(DateTime) + release_time: Mapped[Optional[datetime]] = mapped_column(DateTime) source_size: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) source_format: Mapped[Optional[str]] = mapped_column(String(12)) source_flags: Mapped[Optional[str]] = mapped_column(String(12)) @@ -1109,14 +1145,14 @@ class Submission(Base): title: Mapped[Optional[str]] = mapped_column(Text) authors: Mapped[Optional[str]] = mapped_column(Text) comments: Mapped[Optional[str]] = mapped_column(Text) - proxy: Mapped[Optional[str]] + proxy: Mapped[Optional[str]] = mapped_column(String(255)) report_num: Mapped[Optional[str]] = mapped_column(Text) - msc_class: Mapped[Optional[str]] - acm_class: Mapped[Optional[str]] + msc_class: Mapped[Optional[str]] = mapped_column(String(255)) + acm_class: Mapped[Optional[str]] = mapped_column(String(255)) journal_ref: Mapped[Optional[str]] = mapped_column(Text) - doi: Mapped[Optional[str]] + doi: Mapped[Optional[str]] = mapped_column(String(255)) abstract: Mapped[Optional[str]] = mapped_column(Text) - license: Mapped[Optional[str]] = mapped_column(ForeignKey('arXiv_licenses.name', onupdate='CASCADE'), index=True) + license: Mapped[Optional[str]] = mapped_column(ForeignKey("arXiv_licenses.name", onupdate="CASCADE"), index=True) version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) type: Mapped[Optional[str]] = mapped_column(String(8), index=True) is_ok: Mapped[Optional[int]] = mapped_column(Integer, index=True) @@ -1129,20 +1165,43 @@ class Submission(Base): rt_ticket_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) auto_hold: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) is_locked: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) - agreement_id = mapped_column(ForeignKey('arXiv_submission_agreements.agreement_id'), index=True) - - agreement = relationship('SubmissionAgreement', primaryjoin='Submission.agreement_id == SubmissionAgreement.agreement_id', backref='arXiv_submissions') - document = relationship('Document', primaryjoin='Submission.document_id == Document.document_id', backref='arXiv_submissions') - arXiv_license = relationship('License', primaryjoin='Submission.license == License.name', backref='arXiv_submissions') - submitter = relationship('TapirUser', primaryjoin='Submission.submitter_id == TapirUser.user_id', back_populates='arXiv_submissions') - sword = relationship('Tracking', primaryjoin='Submission.sword_id == Tracking.sword_id', backref='arXiv_submissions') + agreement_id: Mapped[Optional[int]] = mapped_column(ForeignKey("arXiv_submission_agreements.agreement_id"), index=True) + + agreement: Mapped["SubmissionAgreement"] = relationship("SubmissionAgreement", primaryjoin="Submission.agreement_id == SubmissionAgreement.agreement_id", back_populates="arXiv_submissions") + document: Mapped["Document"] = relationship("Document", primaryjoin="Submission.document_id == Document.document_id", back_populates="arXiv_submissions") + arXiv_license: Mapped["License"] = relationship("License", primaryjoin="Submission.license == License.name", back_populates="arXiv_submissions") + submitter: Mapped["TapirUser"] = relationship("TapirUser", primaryjoin="Submission.submitter_id == TapirUser.user_id", back_populates="arXiv_submissions") + sword: Mapped["Tracking"] = relationship("Tracking", primaryjoin="Submission.sword_id == Tracking.sword_id", back_populates="arXiv_submissions") + + # to arxiv check + arXiv_check_results: Mapped[List["CheckResults"]] = relationship("CheckResults", back_populates="submission") + # to submission locks + arXiv_submission_locks: Mapped[List["SubmissionLocks"]] = relationship("SubmissionLocks", back_populates="submission") + data_version: Mapped[int] = mapped_column(SmallInteger, nullable=False, server_default=text("'1'")) + metadata_version: Mapped[int] = mapped_column(SmallInteger, nullable=False, server_default=text("'1'")) + data_needed: Mapped[int] = mapped_column(SmallInteger, nullable=False, server_default=text("'0'")) + data_version_queued: Mapped[int] = mapped_column(SmallInteger, nullable=False, server_default=text("'0'")) + metadata_version_queued: Mapped[int] = mapped_column(SmallInteger, nullable=False, server_default=text("'0'")) + data_queued_time: Mapped[Optional[datetime]] = mapped_column(DateTime) + metadata_queued_time: Mapped[Optional[datetime]] = mapped_column(DateTime) + arXiv_pilot_files: Mapped[List["PilotFile"]] = relationship("PilotFile", back_populates="submission") + arXiv_submission_category: Mapped[List["SubmissionCategory"]] = relationship("SubmissionCategory", back_populates="submission") + arXiv_submission_category_proposal: Mapped[List["SubmissionCategoryProposal"]] = relationship("SubmissionCategoryProposal", back_populates="submission") + arXiv_submission_flag: Mapped[List["SubmissionFlag"]] = relationship("SubmissionFlag", back_populates="submission") + arXiv_submission_hold_reason: Mapped[List["SubmissionHoldReason"]] = relationship("SubmissionHoldReason", back_populates="submission") + arXiv_submission_near_duplicates: Mapped[List["SubmissionNearDuplicate"]] = relationship("SubmissionNearDuplicate", back_populates="submission") + arXiv_submission_qa_reports: Mapped[List["SubmissionQaReport"]] = relationship("SubmissionQaReport", back_populates="submission") + arXiv_submission_view_flag: Mapped[List["SubmissionViewFlag"]] = relationship("SubmissionViewFlag", back_populates="submission") class PilotDataset(Submission): - __tablename__ = 'arXiv_pilot_datasets' + """arXiv_pilot is deprecated""" + + __tablename__ = "arXiv_pilot_datasets" + __table_args__ = {"mysql_charset": "latin1"} - submission_id: Mapped[int] = mapped_column(ForeignKey('arXiv_submissions.submission_id'), primary_key=True) - numfiles: Mapped[Optional[int]] = mapped_column(SmallInteger, server_default=FetchedValue()) + submission_id: Mapped[int] = mapped_column(ForeignKey("arXiv_submissions.submission_id"), primary_key=True) + numfiles: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) feed_url: Mapped[Optional[str]] = mapped_column(String(256)) manifestation: Mapped[Optional[str]] = mapped_column(String(256)) published: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) @@ -1152,14 +1211,15 @@ class PilotDataset(Submission): class SubmissionAbsClassifierDatum(Base): - __tablename__ = 'arXiv_submission_abs_classifier_data' + __tablename__ = "arXiv_submission_abs_classifier_data" + __table_args__ = {"mysql_charset": "utf8mb3"} - submission_id: Mapped[int] = mapped_column(ForeignKey('arXiv_submissions.submission_id', ondelete='CASCADE'), primary_key=True, server_default=FetchedValue()) + submission_id: Mapped[int] = mapped_column(ForeignKey("arXiv_submissions.submission_id", ondelete="CASCADE"), primary_key=True, server_default=FetchedValue()) json: Mapped[Optional[str]] = mapped_column(Text) last_update: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) - status: Mapped[Optional[Literal['processing', 'success', 'failed', 'no connection']]] = mapped_column(Enum('processing', 'success', 'failed', 'no connection')) + status: Mapped[Optional[Literal["processing", "success", "failed", "no connection"]]] = mapped_column(Enum("processing", "success", "failed", "no connection")) message: Mapped[Optional[str]] = mapped_column(Text) - is_oversize: Mapped[Optional[int]] = mapped_column(Integer) + is_oversize: Mapped[Optional[int]] = mapped_column(Integer, server_default=text("'0'")) suggested_primary: Mapped[Optional[str]] = mapped_column(Text) suggested_reason: Mapped[Optional[str]] = mapped_column(Text) autoproposal_primary: Mapped[Optional[str]] = mapped_column(Text) @@ -1169,27 +1229,29 @@ class SubmissionAbsClassifierDatum(Base): class SubmissionClassifierDatum(Base): - __tablename__ = 'arXiv_submission_classifier_data' + __tablename__ = "arXiv_submission_classifier_data" + __table_args__ = {"mysql_charset": "utf8mb3"} - submission_id: Mapped[int] = mapped_column(ForeignKey('arXiv_submissions.submission_id', ondelete='CASCADE'), primary_key=True, server_default=FetchedValue()) + submission_id: Mapped[int] = mapped_column(ForeignKey("arXiv_submissions.submission_id", ondelete="CASCADE"), primary_key=True, server_default=FetchedValue()) json: Mapped[Optional[str]] = mapped_column(Text) last_update: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) - status: Mapped[Optional[Literal['processing', 'success', 'failed', 'no connection']]] = mapped_column(Enum('processing', 'success', 'failed', 'no connection')) + status: Mapped[Optional[Literal["processing", "success", "failed", "no connection"]]] = mapped_column(Enum("processing", "success", "failed", "no connection")) message: Mapped[Optional[str]] = mapped_column(Text) - is_oversize: Mapped[Optional[int]] = mapped_column(Integer) + is_oversize: Mapped[Optional[int]] = mapped_column(Integer, server_default=text("'0'")) class SubmitterFlag(Base): - __tablename__ = 'arXiv_submitter_flags' + __tablename__ = "arXiv_submitter_flags" + __table_args__ = {"mysql_charset": "latin1"} flag_id: Mapped[intpk] - comment: Mapped[Optional[str]] - pattern: Mapped[Optional[str]] - + comment: Mapped[Optional[str]] = mapped_column(String(255)) + pattern: Mapped[Optional[str]] = mapped_column(String(255)) class SuspectEmail(Base): - __tablename__ = 'arXiv_suspect_emails' + __tablename__ = "arXiv_suspect_emails" + __table_args__ = {"mysql_charset": "latin1"} id: Mapped[intpk] type: Mapped[str] = mapped_column(String(10), nullable=False) @@ -1198,9 +1260,9 @@ class SuspectEmail(Base): updated: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) - class Title(Base): - __tablename__ = 'arXiv_titles' + __tablename__ = "arXiv_titles" + __table_args__ = {"mysql_charset": "latin1"} paper_id: Mapped[str] = mapped_column(String(64), primary_key=True) title: Mapped[Optional[str]] = mapped_column(String(255), index=True) @@ -1208,22 +1270,22 @@ class Title(Base): date: Mapped[Optional[dt.date]] = mapped_column(Date) - class TopPaper(Base): - __tablename__ = 'arXiv_top_papers' + __tablename__ = "arXiv_top_papers" + __table_args__ = {"mysql_charset": "latin1"} - from_week: Mapped[date] = mapped_column(Date, primary_key=True, nullable=False, server_default=FetchedValue()) - _class: Mapped[str] = mapped_column('class', String(1), primary_key=True, nullable=False, server_default=FetchedValue()) - rank: Mapped[int] = mapped_column(SmallInteger, primary_key=True, nullable=False, server_default=FetchedValue()) - document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id'), nullable=False, index=True, server_default=FetchedValue()) + from_week: Mapped[dt.date] = mapped_column(Date, primary_key=True, nullable=False, server_default=FetchedValue()) + _class: Mapped[str] = mapped_column("class", String(1), primary_key=True, nullable=False, server_default=FetchedValue()) + rank: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, server_default=FetchedValue()) + document_id: Mapped[int] = mapped_column(ForeignKey("arXiv_documents.document_id"), nullable=False, index=True, server_default=FetchedValue()) viewers: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - document = relationship('Document', primaryjoin='TopPaper.document_id == Document.document_id', backref='arXiv_top_papers') - + document: Mapped["Document"] = relationship("Document", primaryjoin="TopPaper.document_id == Document.document_id", back_populates="arXiv_top_papers") class TrackbackPing(Base): - __tablename__ = 'arXiv_trackback_pings' + __tablename__ = "arXiv_trackback_pings" + __table_args__ = {"mysql_charset": "latin1"} trackback_id: Mapped[intpk] document_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) @@ -1237,7 +1299,9 @@ class TrackbackPing(Base): is_stale: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) approved_by_user: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) approved_time: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - status: Mapped[Literal['pending', 'pending2', 'accepted', 'rejected', 'spam']] = mapped_column(Enum('pending', 'pending2', 'accepted', 'rejected', 'spam'), nullable=False, index=True, server_default=FetchedValue()) + status: Mapped[Literal["pending", "pending2", "accepted", "rejected", "spam"]] = mapped_column( + Enum("pending", "pending2", "accepted", "rejected", "spam"), nullable=False, index=True, server_default=FetchedValue() + ) site_id: Mapped[Optional[int]] = mapped_column(Integer) @property @@ -1249,7 +1313,14 @@ def posted_datetime(self) -> DateTime: @property def display_url(self) -> str: """Get the URL without the protocol, for display.""" - return str(re.sub(r"^[a-z]+:\/\/", "", self.url.strip(), flags=re.IGNORECASE,)) + return str( + re.sub( + r"^[a-z]+:\/\/", + "", + self.url.strip(), + flags=re.IGNORECASE, + ) + ) @property def has_valid_url(self) -> bool: @@ -1264,153 +1335,154 @@ def hashed_document_id(self) -> str: s = f"{self.document_id}{self.trackback_id}{tb_secret}" return hashlib.md5(s.encode()).hexdigest()[0:9] + class TrackbackSite(Base): - __tablename__ = 'arXiv_trackback_sites' + __tablename__ = "arXiv_trackback_sites" + __table_args__ = {"mysql_charset": "latin1"} pattern: Mapped[str] = mapped_column(String(255), nullable=False, index=True, server_default=FetchedValue()) site_id: Mapped[intpk] - action: Mapped[Literal['neutral', 'accept', 'reject', 'spam']] = mapped_column(Enum('neutral', 'accept', 'reject', 'spam'), nullable=False, server_default=FetchedValue()) - + action: Mapped[Literal["neutral", "accept", "reject", "spam"]] = mapped_column(Enum("neutral", "accept", "reject", "spam"), nullable=False, server_default=FetchedValue()) class Tracking(Base): - __tablename__ = 'arXiv_tracking' + __tablename__ = "arXiv_tracking" + __table_args__ = {"mysql_charset": "latin1"} tracking_id: Mapped[intpk] - sword_id: Mapped[int] = mapped_column(Integer, nullable=False, unique=True, server_default=FetchedValue()) + sword_id: Mapped[int] = mapped_column(Integer, nullable=False, unique=True, index=True, server_default=FetchedValue()) paper_id: Mapped[str] = mapped_column(String(32), nullable=False) submission_errors: Mapped[Optional[str]] = mapped_column(Text) timestamp: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) + arXiv_submissions: Mapped[List["Submission"]] = relationship("Submission", back_populates="sword") class Updates(Base): __tablename__ = "arXiv_updates" - __table_args__ = (PrimaryKeyConstraint('document_id', 'date', 'action', 'category'),) + __table_args__ = (PrimaryKeyConstraint("document_id", "date", "action", "category"), {"mysql_charset": "latin1"}) + # primary key is foregn key document_id: Mapped[Optional[int]] = mapped_column( ForeignKey("arXiv_documents.document_id", ondelete="CASCADE", onupdate="CASCADE"), - nullable=False, index=True, server_default=text("'0'"), ) + version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) date: Mapped[Optional[dt.date]] = mapped_column(Date, index=True) - action: Mapped[Optional[Literal['new', 'replace', 'absonly', 'cross', 'repcro']]] = mapped_column(Enum('new', 'replace', 'absonly', 'cross', 'repcro')) + action: Mapped[Optional[Literal["new", "replace", "absonly", "cross", "repcro"]]] = mapped_column(Enum("new", "replace", "absonly", "cross", "repcro")) archive: Mapped[Optional[str]] = mapped_column(String(20), index=True) - category: Mapped[Optional[int]] = mapped_column(String(20), index=True) + category: Mapped[Optional[str]] = mapped_column(String(20), index=True) def __repr__(self) -> str: - return f"ArXivUpdate(document_id={self.document_id}, version={self.version}, action={self.action}, date={self.date}, category={self.category}, archive={self.archive})" + return f"Update(document_id={self.document_id}, version={self.version}, action={self.action}, date={self.date}, category={self.category}, archive={self.archive})" t_arXiv_updates_tmp = Table( - 'arXiv_updates_tmp', metadata, - Column('document_id', Integer), - Column('date', Date), - Column('action', Enum('new', 'replace', 'absonly', 'cross', 'repcro')), - Column('category', String(20)), - Index('updates_temp_document_id', 'document_id', 'date', 'action', 'category') + "arXiv_updates_tmp", + metadata, + Column("document_id", Integer), + Column("date", Date), + Column("action", Enum("new", "replace", "absonly", "cross", "repcro")), + Column("category", String(20)), + Index("updates_temp_document_id", "document_id", "date", "action", "category"), ) class Version(Base): - __tablename__ = 'arXiv_versions' + __tablename__ = "arXiv_versions" + __table_args__ = {"mysql_charset": "latin1"} - document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id'), primary_key=True, nullable=False, server_default=FetchedValue()) + document_id: Mapped[int] = mapped_column(ForeignKey("arXiv_documents.document_id"), primary_key=True, nullable=False, server_default=FetchedValue()) version: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, server_default=FetchedValue()) request_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) freeze_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) publish_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) flag_current: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - document = relationship('Document', primaryjoin='Version.document_id == Document.document_id', backref='arXiv_versions') + document: Mapped["Document"] = relationship("Document", back_populates="arXiv_versions") class VersionsChecksum(Version): - __tablename__ = 'arXiv_versions_checksum' - __table_args__ = ( - ForeignKeyConstraint(['document_id', 'version'], ['arXiv_versions.document_id', 'arXiv_versions.version']), - ) + __tablename__ = "arXiv_versions_checksum" + __table_args__ = (ForeignKeyConstraint(["document_id", "version"], ["arXiv_versions.document_id", "arXiv_versions.version"]), {"mysql_charset": "latin1"}) document_id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, server_default=FetchedValue()) version: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, server_default=FetchedValue()) flag_abs_present: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) abs_size: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) - abs_md5sum: Mapped[Optional[str]] = mapped_column(BINARY(16), index=True) + abs_md5sum: Mapped[Optional[bytes]] = mapped_column(BINARY(16), index=True) flag_src_present: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) src_size: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) - src_md5sum: Mapped[Optional[str]] = mapped_column(BINARY(16), index=True) + src_md5sum: Mapped[Optional[bytes]] = mapped_column(BINARY(16), index=True) - -t_arXiv_white_email = Table( - 'arXiv_white_email', metadata, - Column('pattern', String(64), unique=True) -) - +t_arXiv_white_email = Table("arXiv_white_email", metadata, Column("pattern", String(64), unique=True, index=True)) t_arXiv_xml_notifications = Table( - 'arXiv_xml_notifications', metadata, - Column('control_id', Integer, index=True), - Column('type', Enum('submission', 'cross', 'jref')), - Column('queued_date', Integer, nullable=False, server_default=FetchedValue()), - Column('sent_date', Integer, nullable=False, server_default=FetchedValue()), - Column('status', Enum('unsent', 'sent', 'failed'), index=True) + "arXiv_xml_notifications", + metadata, + Column("control_id", Integer, index=True), + Column("type", Enum("submission", "cross", "jref")), + Column("queued_date", Integer, nullable=False, server_default=FetchedValue()), + Column("sent_date", Integer, nullable=False, server_default=FetchedValue()), + Column("status", Enum("unsent", "sent", "failed"), index=True), ) - class DbixClassSchemaVersion(Base): - __tablename__ = 'dbix_class_schema_versions' + __tablename__ = "dbix_class_schema_versions" + __table_args__ = {"mysql_charset": "latin1"} version: Mapped[str] = mapped_column(String(10), primary_key=True) installed: Mapped[str] = mapped_column(String(20), nullable=False) - t_demographics_backup = Table( - 'demographics_backup', metadata, - Column('user_id', Integer, nullable=False, server_default=FetchedValue()), - Column('country', String(2), nullable=False, server_default=FetchedValue()), - Column('affiliation', String(255), nullable=False, server_default=FetchedValue()), - Column('url', String(255), nullable=False, server_default=FetchedValue()), - Column('type', SmallInteger), - Column('os', SmallInteger), - Column('archive', String(16)), - Column('subject_class', String(16)), - Column('original_subject_classes', String(255), nullable=False, server_default=FetchedValue()), - Column('flag_group_physics', Integer), - Column('flag_group_math', Integer, nullable=False, server_default=FetchedValue()), - Column('flag_group_cs', Integer, nullable=False, server_default=FetchedValue()), - Column('flag_group_nlin', Integer, nullable=False, server_default=FetchedValue()), - Column('flag_proxy', Integer, nullable=False, server_default=FetchedValue()), - Column('flag_journal', Integer, nullable=False, server_default=FetchedValue()), - Column('flag_xml', Integer, nullable=False, server_default=FetchedValue()), - Column('dirty', Integer, nullable=False, server_default=FetchedValue()), - Column('flag_group_test', Integer, nullable=False, server_default=FetchedValue()), - Column('flag_suspect', Integer, nullable=False, server_default=FetchedValue()), - Column('flag_group_q_bio', Integer, nullable=False, server_default=FetchedValue()), - Column('flag_no_upload', Integer, nullable=False, server_default=FetchedValue()), - Column('flag_no_endorse', Integer, nullable=False, server_default=FetchedValue()), - Column('veto_status', Enum('ok', 'no-endorse', 'no-upload'), server_default=FetchedValue()) + "demographics_backup", + metadata, + Column("user_id", Integer, nullable=False, server_default=FetchedValue()), + Column("country", String(2), nullable=False, server_default=FetchedValue()), + Column("affiliation", String(255), nullable=False, server_default=FetchedValue()), + Column("url", String(255), nullable=False, server_default=FetchedValue()), + Column("type", Integer), + Column("os", Integer), + Column("archive", String(16)), + Column("subject_class", String(16)), + Column("original_subject_classes", String(255), nullable=False, server_default=FetchedValue()), + Column("flag_group_physics", Integer), + Column("flag_group_math", Integer, nullable=False, server_default=FetchedValue()), + Column("flag_group_cs", Integer, nullable=False, server_default=FetchedValue()), + Column("flag_group_nlin", Integer, nullable=False, server_default=FetchedValue()), + Column("flag_proxy", Integer, nullable=False, server_default=FetchedValue()), + Column("flag_journal", Integer, nullable=False, server_default=FetchedValue()), + Column("flag_xml", Integer, nullable=False, server_default=FetchedValue()), + Column("dirty", Integer, nullable=False, server_default=FetchedValue()), + Column("flag_group_test", Integer, nullable=False, server_default=FetchedValue()), + Column("flag_suspect", Integer, nullable=False, server_default=FetchedValue()), + Column("flag_group_q_bio", Integer, nullable=False, server_default=FetchedValue()), + Column("flag_no_upload", Integer, nullable=False, server_default=FetchedValue()), + Column("flag_no_endorse", Integer, nullable=False, server_default=FetchedValue()), + Column("veto_status", Enum("ok", "no-endorse", "no-upload"), server_default=FetchedValue()), ) class Session(Base): - __tablename__ = 'sessions' + __tablename__ = "sessions" + __table_args__ = {"mysql_charset": "utf8mb3"} id: Mapped[str] = mapped_column(String(72), primary_key=True) session_data: Mapped[Optional[str]] = mapped_column(Text) expires: Mapped[Optional[int]] = mapped_column(Integer) - class TapirAddress(Base): - __tablename__ = 'tapir_address' + __tablename__ = "tapir_address" + __table_args__ = {"mysql_charset": "latin1"} - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, nullable=False, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), primary_key=True, nullable=False, server_default=FetchedValue()) address_type: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, index=True, server_default=FetchedValue()) company: Mapped[str] = mapped_column(String(80), nullable=False, server_default=FetchedValue()) line1: Mapped[str] = mapped_column(String(80), nullable=False, server_default=FetchedValue()) @@ -1418,49 +1490,53 @@ class TapirAddress(Base): city: Mapped[str] = mapped_column(String(50), nullable=False, index=True, server_default=FetchedValue()) state: Mapped[str] = mapped_column(String(50), nullable=False, server_default=FetchedValue()) postal_code: Mapped[str] = mapped_column(String(16), nullable=False, index=True, server_default=FetchedValue()) - country: Mapped[str] = mapped_column(ForeignKey('tapir_countries.digraph'), nullable=False, index=True, server_default=FetchedValue()) + country: Mapped[str] = mapped_column(ForeignKey("tapir_countries.digraph"), nullable=False, index=True, server_default=FetchedValue()) share_addr: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - tapir_country = relationship('TapirCountry', primaryjoin='TapirAddress.country == TapirCountry.digraph', backref='tapir_address') - user = relationship('TapirUser', primaryjoin='TapirAddress.user_id == TapirUser.user_id', back_populates='tapir_address') - + tapir_country: Mapped["TapirCountry"] = relationship("TapirCountry", primaryjoin="TapirAddress.country == TapirCountry.digraph", back_populates="tapir_address") + user: Mapped["TapirUser"] = relationship("TapirUser", primaryjoin="TapirAddress.user_id == TapirUser.user_id", back_populates="tapir_address") class TapirAdminAudit(Base): - __tablename__ = 'tapir_admin_audit' + __tablename__ = "tapir_admin_audit" + __table_args__ = {"mysql_charset": "latin1"} log_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) - session_id: Mapped[Optional[int]] = mapped_column(ForeignKey('tapir_sessions.session_id'), index=True) + session_id: Mapped[Optional[int]] = mapped_column(ForeignKey("tapir_sessions.session_id"), index=True) ip_addr: Mapped[str] = mapped_column(String(16), nullable=False, index=True, server_default=FetchedValue()) remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) - admin_user: Mapped[Optional[int]] = mapped_column(ForeignKey('tapir_users.user_id'), index=True) - affected_user: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()) + admin_user: Mapped[Optional[int]] = mapped_column(ForeignKey("tapir_users.user_id"), index=True) + affected_user: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), nullable=False, index=True, server_default=FetchedValue()) tracking_cookie: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) action: Mapped[str] = mapped_column(String(32), nullable=False, server_default=FetchedValue()) - data: Mapped[str] = mapped_column(Text, nullable=False, index=True) + data: Mapped[str] = mapped_column(String(255)) comment: Mapped[str] = mapped_column(Text, nullable=False) entry_id: Mapped[intpk] - tapir_users = relationship('TapirUser', foreign_keys=[admin_user], back_populates='tapir_admin_audit') - tapir_users_ = relationship('TapirUser', foreign_keys=[affected_user], back_populates='tapir_admin_audit_') - session = relationship('TapirSession', primaryjoin='TapirAdminAudit.session_id == TapirSession.session_id', backref='tapir_admin_audits') - + tapir_users: Mapped["TapirUser"] = relationship("TapirUser", foreign_keys=[admin_user], back_populates="tapir_admin_audit") + tapir_users_: Mapped["TapirUser"] = relationship("TapirUser", foreign_keys=[affected_user], back_populates="tapir_admin_audit_") + session: Mapped["TapirSession"] = relationship("TapirSession", back_populates="tapir_admin_audit") class TapirCountry(Base): - __tablename__ = 'tapir_countries' + __tablename__ = "tapir_countries" + __table_args__ = {"mysql_charset": "latin1"} digraph: Mapped[str] = mapped_column(String(2), primary_key=True, server_default=FetchedValue()) country_name: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) rank: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + tapir_address: Mapped[List["TapirAddress"]] = relationship("TapirAddress", back_populates="tapir_country") + tapir_demographics: Mapped[List["TapirDemographic"]] = relationship("TapirDemographic", back_populates="tapir_country") + class TapirEmailChangeToken(Base): - __tablename__ = 'tapir_email_change_tokens' + __tablename__ = "tapir_email_change_tokens" + __table_args__ = {"mysql_charset": "latin1"} - user_id = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, nullable=False, server_default=FetchedValue()) - old_email: Mapped[Optional[str]] - new_email: Mapped[Optional[str]] + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), primary_key=True, nullable=False, server_default=FetchedValue()) + old_email: Mapped[Optional[str]] = mapped_column(String(255)) + new_email: Mapped[Optional[str]] = mapped_column(String(255)) secret: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False, index=True, server_default=FetchedValue()) tapir_dest: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) issued_when: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) @@ -1472,69 +1548,68 @@ class TapirEmailChangeToken(Base): consumed_when: Mapped[Optional[int]] = mapped_column(Integer) consumed_from: Mapped[Optional[str]] = mapped_column(String(16)) - user = relationship('TapirUser', primaryjoin='TapirEmailChangeToken.user_id == TapirUser.user_id', back_populates='tapir_email_change_tokens') + user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="tapir_email_change_tokens") t_tapir_email_change_tokens_used = Table( - 'tapir_email_change_tokens_used', metadata, - Column('user_id', ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()), - Column('secret', String(32), nullable=False, server_default=FetchedValue()), - Column('used_when', Integer, nullable=False, server_default=FetchedValue()), - Column('used_from', String(16), nullable=False, server_default=FetchedValue()), - Column('remote_host', String(255), nullable=False, server_default=FetchedValue()), - Column('session_id', ForeignKey('tapir_sessions.session_id'), nullable=False, index=True, server_default=FetchedValue()) + "tapir_email_change_tokens_used", + metadata, + Column("user_id", ForeignKey("tapir_users.user_id"), nullable=False, index=True, server_default=FetchedValue()), + Column("secret", String(32), nullable=False, server_default=FetchedValue()), + Column("used_when", Integer, nullable=False, server_default=FetchedValue()), + Column("used_from", String(16), nullable=False, server_default=FetchedValue()), + Column("remote_host", String(255), nullable=False, server_default=FetchedValue()), + Column("session_id", ForeignKey("tapir_sessions.session_id"), nullable=False, index=True, server_default=FetchedValue()), ) class TapirEmailHeader(Base): - __tablename__ = 'tapir_email_headers' + __tablename__ = "tapir_email_headers" + __table_args__ = {"mysql_charset": "latin1"} - template_id: Mapped[int] = mapped_column(ForeignKey('tapir_email_templates.template_id'), primary_key=True, nullable=False, server_default=FetchedValue()) + template_id: Mapped[int] = mapped_column(ForeignKey("tapir_email_templates.template_id"), primary_key=True, nullable=False, server_default=FetchedValue()) header_name: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False, server_default=FetchedValue()) header_content: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) - template = relationship('TapirEmailTemplate', primaryjoin='TapirEmailHeader.template_id == TapirEmailTemplate.template_id', backref='tapir_email_headers') - + template: Mapped["TapirEmailTemplate"] = relationship("TapirEmailTemplate", back_populates="tapir_email_headers") class TapirEmailLog(Base): - __tablename__ = 'tapir_email_log' + __tablename__ = "tapir_email_log" + __table_args__ = {"mysql_charset": "latin1"} mail_id: Mapped[intpk] reference_type: Mapped[Optional[str]] = mapped_column(String(1)) reference_id: Mapped[Optional[int]] = mapped_column(Integer) sent_date: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - email: Mapped[Optional[str]] + email: Mapped[Optional[str]] = mapped_column(String(255)) flag_bounced: Mapped[Optional[int]] = mapped_column(Integer) mailing_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) template_id: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - class TapirEmailMailing(Base): - __tablename__ = 'tapir_email_mailings' + __tablename__ = "tapir_email_mailings" + __table_args__ = {"mysql_charset": "latin1"} mailing_id: Mapped[intpk] - template_id: Mapped[Optional[int]] = mapped_column(ForeignKey('tapir_email_templates.template_id'), index=True) - created_by: Mapped[Optional[int]] = mapped_column(ForeignKey('tapir_users.user_id'), index=True) - sent_by: Mapped[Optional[int]] = mapped_column(ForeignKey('tapir_users.user_id'), index=True) + template_id: Mapped[Optional[int]] = mapped_column(ForeignKey("tapir_email_templates.template_id"), index=True) + created_by: Mapped[Optional[int]] = mapped_column(ForeignKey("tapir_users.user_id"), index=True) + sent_by: Mapped[Optional[int]] = mapped_column(ForeignKey("tapir_users.user_id"), index=True) created_date: Mapped[Optional[int]] = mapped_column(Integer) sent_date: Mapped[Optional[int]] = mapped_column(Integer) complete_date: Mapped[Optional[int]] = mapped_column(Integer) - mailing_name: Mapped[Optional[str]] + mailing_name: Mapped[Optional[str]] = mapped_column(String(255)) comment: Mapped[Optional[str]] = mapped_column(Text) - tapir_users = relationship('TapirUser', foreign_keys=[created_by], back_populates='tapir_email_mailings') - tapir_users_ = relationship('TapirUser', foreign_keys=[sent_by], back_populates='tapir_email_mailings_') - template = relationship('TapirEmailTemplate', primaryjoin='TapirEmailMailing.template_id == TapirEmailTemplate.template_id', backref='tapir_email_mailings') - + tapir_users: Mapped["TapirUser"] = relationship("TapirUser", foreign_keys=[created_by], back_populates="tapir_email_mailings") + tapir_users_: Mapped["TapirUser"] = relationship("TapirUser", foreign_keys=[sent_by], back_populates="tapir_email_mailings_") + template: Mapped["TapirEmailTemplate"] = relationship("TapirEmailTemplate", back_populates="tapir_email_mailings") class TapirEmailTemplate(Base): - __tablename__ = 'tapir_email_templates' - __table_args__ = ( - Index('short_name', 'short_name', 'lang'), - ) + __tablename__ = "tapir_email_templates" + __table_args__ = (Index("short_name", "short_name", "lang", unique=True), {"mysql_charset": "latin1"}) template_id: Mapped[intpk] short_name: Mapped[str] = mapped_column(String(32), nullable=False, server_default=FetchedValue()) @@ -1543,20 +1618,22 @@ class TapirEmailTemplate(Base): data: Mapped[str] = mapped_column(Text, nullable=False) sql_statement: Mapped[str] = mapped_column(Text, nullable=False) update_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) - created_by: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()) - updated_by: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()) + created_by: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), nullable=False, index=True, server_default=FetchedValue()) + updated_by: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), nullable=False, index=True, server_default=FetchedValue()) workflow_status: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) flag_system: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - tapir_users = relationship('TapirUser', foreign_keys=[created_by], back_populates='tapir_email_templates') - tapir_users_ = relationship('TapirUser', foreign_keys=[updated_by], back_populates='tapir_email_templates_') - + tapir_users: Mapped["TapirUser"] = relationship("TapirUser", foreign_keys=[created_by], back_populates="tapir_email_templates") + tapir_users_: Mapped["TapirUser"] = relationship("TapirUser", foreign_keys=[updated_by], back_populates="tapir_email_templates_") + tapir_email_headers: Mapped[List["TapirEmailHeader"]] = relationship("TapirEmailHeader", back_populates="template") + tapir_email_mailings: Mapped[List["TapirEmailMailing"]] = relationship("TapirEmailMailing", back_populates="template") class TapirEmailToken(Base): - __tablename__ = 'tapir_email_tokens' + __tablename__ = "tapir_email_tokens" + __table_args__ = {"mysql_charset": "latin1"} - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, nullable=False, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), primary_key=True, nullable=False, server_default=FetchedValue()) secret: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False, index=True, server_default=FetchedValue()) tapir_dest: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) issued_when: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) @@ -1565,66 +1642,62 @@ class TapirEmailToken(Base): tracking_cookie: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) wants_perm_token: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - user = relationship('TapirUser', primaryjoin='TapirEmailToken.user_id == TapirUser.user_id', back_populates='tapir_email_tokens') - + user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="tapir_email_tokens") t_tapir_email_tokens_used = Table( - 'tapir_email_tokens_used', metadata, - Column('user_id', ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()), - Column('secret', String(32), nullable=False, server_default=FetchedValue()), - Column('used_when', Integer, nullable=False, server_default=FetchedValue()), - Column('used_from', String(16), nullable=False, server_default=FetchedValue()), - Column('remote_host', String(255), nullable=False, server_default=FetchedValue()), - Column('session_id', ForeignKey('tapir_sessions.session_id'), nullable=False, index=True, server_default=FetchedValue()) + "tapir_email_tokens_used", + metadata, + Column("user_id", ForeignKey("tapir_users.user_id"), nullable=False, index=True, server_default=FetchedValue()), + Column("secret", String(32), nullable=False, server_default=FetchedValue()), + Column("used_when", Integer, nullable=False, server_default=FetchedValue()), + Column("used_from", String(16), nullable=False, server_default=FetchedValue()), + Column("remote_host", String(255), nullable=False, server_default=FetchedValue()), + Column("session_id", ForeignKey("tapir_sessions.session_id"), nullable=False, index=True, server_default=FetchedValue()), ) - t_tapir_error_log = Table( - 'tapir_error_log', metadata, - Column('error_date', Integer, nullable=False, index=True, server_default=FetchedValue()), - Column('user_id', Integer, index=True), - Column('session_id', Integer, index=True), - Column('ip_addr', String(16), nullable=False, index=True, server_default=FetchedValue()), - Column('remote_host', String(255), nullable=False, server_default=FetchedValue()), - Column('tracking_cookie', String(32), nullable=False, index=True, server_default=FetchedValue()), - Column('message', String(32), nullable=False, index=True, server_default=FetchedValue()), - Column('url', String(255), nullable=False, server_default=FetchedValue()), - Column('error_url', String(255), nullable=False, server_default=FetchedValue()) + "tapir_error_log", + metadata, + Column("error_date", Integer, nullable=False, index=True, server_default=FetchedValue()), + Column("user_id", Integer, index=True), + Column("session_id", Integer, index=True), + Column("ip_addr", String(16), nullable=False, index=True, server_default=FetchedValue()), + Column("remote_host", String(255), nullable=False, server_default=FetchedValue()), + Column("tracking_cookie", String(32), nullable=False, index=True, server_default=FetchedValue()), + Column("message", String(32), nullable=False, index=True, server_default=FetchedValue()), + Column("url", String(255), nullable=False, server_default=FetchedValue()), + Column("error_url", String(255), nullable=False, server_default=FetchedValue()), ) - class TapirIntegerVariable(Base): - __tablename__ = 'tapir_integer_variables' + __tablename__ = "tapir_integer_variables" + __table_args__ = {"mysql_charset": "latin1"} variable_id: Mapped[str] = mapped_column(String(32), primary_key=True, server_default=FetchedValue()) value: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - class TapirNickname(Base): - __tablename__ = 'tapir_nicknames' - __table_args__ = ( - Index('user_id', 'user_id', 'user_seq'), - ) + __tablename__ = "tapir_nicknames" + __table_args__ = (Index("user_id", "user_id", "user_seq", unique=True), {"mysql_charset": "latin1"}) nick_id: Mapped[intpk] - nickname: Mapped[str] = mapped_column(String(20), nullable=False, unique=True, server_default=FetchedValue()) - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, server_default=FetchedValue()) + nickname: Mapped[str] = mapped_column(String(20), nullable=False, unique=True, index=True, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), nullable=False, server_default=FetchedValue()) user_seq: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) flag_valid: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) role: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) policy: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) flag_primary: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) - user = relationship('TapirUser', primaryjoin='TapirNickname.user_id == TapirUser.user_id', back_populates='tapir_nicknames') - + user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="tapir_nicknames") class TapirNicknamesAudit(Base): - __tablename__ = 'tapir_nicknames_audit' + __tablename__ = "tapir_nicknames_audit" nick_id: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) creation_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) @@ -1633,69 +1706,73 @@ class TapirNicknamesAudit(Base): tracking_cookie: Mapped[str] = mapped_column(String(255), nullable=False, index=True, server_default=FetchedValue()) - t_tapir_no_cookies = Table( - 'tapir_no_cookies', metadata, - Column('log_date', Integer, nullable=False, server_default=FetchedValue()), - Column('ip_addr', String(16), nullable=False, server_default=FetchedValue()), - Column('remote_host', String(255), nullable=False, server_default=FetchedValue()), - Column('tracking_cookie', String(255), nullable=False, server_default=FetchedValue()), - Column('session_data', String(255), nullable=False, server_default=FetchedValue()), - Column('user_agent', String(255), nullable=False, server_default=FetchedValue()) + "tapir_no_cookies", + metadata, + Column("log_date", Integer, nullable=False, server_default=FetchedValue()), + Column("ip_addr", String(16), nullable=False, server_default=FetchedValue()), + Column("remote_host", String(255), nullable=False, server_default=FetchedValue()), + Column("tracking_cookie", String(255), nullable=False, server_default=FetchedValue()), + Column("session_data", String(255), nullable=False, server_default=FetchedValue()), + Column("user_agent", String(255), nullable=False, server_default=FetchedValue()), ) - -t_tapir_periodic_tasks_log = Table( - 'tapir_periodic_tasks_log', metadata, - Column('t', Integer, nullable=False, index=True, server_default=FetchedValue()), - Column('entry', Text) -) - +t_tapir_periodic_tasks_log = Table("tapir_periodic_tasks_log", metadata, Column("t", Integer, nullable=False, index=True, server_default=FetchedValue()), Column("entry", Text)) class TapirPermanentToken(Base): - __tablename__ = 'tapir_permanent_tokens' + __tablename__ = "tapir_permanent_tokens" + __table_args__ = {"mysql_charset": "latin1"} - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, nullable=False, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), primary_key=True, nullable=False, server_default=FetchedValue()) secret: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False, server_default=FetchedValue()) valid: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) issued_when: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) issued_to: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) - session_id: Mapped[int] = mapped_column(ForeignKey('tapir_sessions.session_id'), nullable=False, index=True, server_default=FetchedValue()) - - session = relationship('TapirSession', primaryjoin='TapirPermanentToken.session_id == TapirSession.session_id', backref='tapir_permanent_tokens') - user = relationship('TapirUser', primaryjoin='TapirPermanentToken.user_id == TapirUser.user_id', back_populates='tapir_permanent_tokens') + session_id: Mapped[int] = mapped_column(ForeignKey("tapir_sessions.session_id"), nullable=False, index=True, server_default=FetchedValue()) + session: Mapped["TapirSession"] = relationship("TapirSession", back_populates="tapir_permanent_tokens") + user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="tapir_permanent_tokens") t_tapir_permanent_tokens_used = Table( - 'tapir_permanent_tokens_used', metadata, - Column('user_id', ForeignKey('tapir_users.user_id'), index=True), - Column('secret', String(32), nullable=False, server_default=FetchedValue()), - Column('used_when', Integer), - Column('used_from', String(16)), - Column('remote_host', String(255), nullable=False, server_default=FetchedValue()), - Column('session_id', ForeignKey('tapir_sessions.session_id'), nullable=False, index=True, server_default=FetchedValue()) + "tapir_permanent_tokens_used", + metadata, + Column("user_id", ForeignKey("tapir_users.user_id"), index=True), + Column("secret", String(32), nullable=False, server_default=FetchedValue()), + Column("used_when", Integer), + Column("used_from", String(16)), + Column("remote_host", String(255), nullable=False, server_default=FetchedValue()), + Column("session_id", ForeignKey("tapir_sessions.session_id"), nullable=False, index=True, server_default=FetchedValue()), ) - class TapirPhone(Base): - __tablename__ = 'tapir_phone' + __tablename__ = "tapir_phone" + __table_args__ = {"mysql_charset": "latin1"} - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, nullable=False, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), primary_key=True, nullable=False, server_default=FetchedValue()) phone_type: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, index=True, server_default=FetchedValue()) phone_number: Mapped[Optional[str]] = mapped_column(String(32), index=True) share_phone: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - user = relationship('TapirUser', primaryjoin='TapirPhone.user_id == TapirUser.user_id', back_populates='tapir_phone') - + user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="tapir_phone") class TapirPolicyClass(Base): - __tablename__ = 'tapir_policy_classes' + __tablename__ = "tapir_policy_classes" + __table_args__ = {"mysql_charset": "latin1"} + + class_id: Mapped[int] = mapped_column(Integer, primary_key=True) + name: Mapped[str] = mapped_column(String(64), nullable=False, server_default=FetchedValue()) + description: Mapped[str] = mapped_column(Text, nullable=False) + password_storage: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + recovery_policy: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + permanent_login: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + tapir_users: Mapped[List["TapirUser"]] = relationship("TapirUser", back_populates="tapir_policy_classes") ADMIN = 1 PUBLIC_USER = 2 @@ -1706,17 +1783,10 @@ class TapirPolicyClass(Base): {"name": "Legacy user", "class_id": LEGACY_USER, "description": "", "password_storage": 2, "recovery_policy": 3, "permanent_login": 1}, ] - class_id: Mapped[int] = mapped_column(SmallInteger, primary_key=True) - name: Mapped[str] = mapped_column(String(64), nullable=False, server_default=FetchedValue()) - description: Mapped[str] = mapped_column(Text, nullable=False) - password_storage: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - recovery_policy: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - permanent_login: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - - tapir_users = relationship('TapirUser', back_populates='tapir_policy_classes') class TapirPresession(Base): - __tablename__ = 'tapir_presessions' + __tablename__ = "tapir_presessions" + __table_args__ = {"mysql_charset": "latin1"} presession_id: Mapped[intpk] ip_num: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) @@ -1725,11 +1795,11 @@ class TapirPresession(Base): created_at: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - class TapirRecoveryToken(Base): - __tablename__ = 'tapir_recovery_tokens' + __tablename__ = "tapir_recovery_tokens" + __table_args__ = {"mysql_charset": "latin1"} - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, nullable=False, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), primary_key=True, nullable=False, server_default=FetchedValue()) secret: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False, index=True, server_default=FetchedValue()) valid: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) tapir_dest: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) @@ -1738,68 +1808,74 @@ class TapirRecoveryToken(Base): remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) tracking_cookie: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) - user = relationship('TapirUser', primaryjoin='TapirRecoveryToken.user_id == TapirUser.user_id', back_populates='tapir_recovery_tokens') - + user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="tapir_recovery_tokens") class TapirRecoveryTokensUsed(Base): - __tablename__ = 'tapir_recovery_tokens_used' + __tablename__ = "tapir_recovery_tokens_used" + __table_args__ = {"mysql_charset": "latin1"} - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, nullable=False, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), primary_key=True, nullable=False, server_default=FetchedValue()) secret: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False, server_default=FetchedValue()) used_when: Mapped[Optional[int]] = mapped_column(Integer) used_from: Mapped[Optional[str]] = mapped_column(String(16)) remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) - session_id: Mapped[Optional[int]] = mapped_column(ForeignKey('tapir_sessions.session_id'), index=True) - - session = relationship('TapirSession', primaryjoin='TapirRecoveryTokensUsed.session_id == TapirSession.session_id', backref='tapir_recovery_tokens_useds') - user = relationship('TapirUser', primaryjoin='TapirRecoveryTokensUsed.user_id == TapirUser.user_id', back_populates='tapir_recovery_tokens_used') + session_id: Mapped[Optional[int]] = mapped_column(ForeignKey("tapir_sessions.session_id"), index=True) + session: Mapped["TapirSession"] = relationship("TapirSession", back_populates="tapir_recovery_tokens_used") + user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="tapir_recovery_tokens_used") t_tapir_save_post_variables = Table( - 'tapir_save_post_variables', metadata, - Column('presession_id', ForeignKey('tapir_presessions.presession_id'), nullable=False, index=True, server_default=FetchedValue()), - Column('name', String(255)), - Column('value', String, nullable=False), - Column('seq', Integer, nullable=False, server_default=FetchedValue()) + "tapir_save_post_variables", + metadata, + Column("presession_id", ForeignKey("tapir_presessions.presession_id"), nullable=False, index=True, server_default=FetchedValue()), + Column("name", String(255)), + Column("value", Text, nullable=False), + Column("seq", Integer, nullable=False, server_default=FetchedValue()), ) class TapirSession(Base): - __tablename__ = 'tapir_sessions' + __tablename__ = "tapir_sessions" + __table_args__ = {"mysql_charset": "latin1"} - session_id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=text("'0'")) + session_id: Mapped[int] = mapped_column(Integer, primary_key=True) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), nullable=False, index=True, server_default=text("'0'")) last_reissue: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) start_time: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) end_time: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) - user = relationship('TapirUser', primaryjoin='TapirSession.user_id == TapirUser.user_id', back_populates='tapir_sessions') + user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="tapir_sessions") + user = relationship("TapirUser", primaryjoin="TapirSession.user_id == TapirUser.user_id", back_populates="tapir_sessions") + tapir_admin_audit: Mapped[List["TapirAdminAudit"]] = relationship("TapirAdminAudit", back_populates="session") + tapir_permanent_tokens: Mapped[List["TapirPermanentToken"]] = relationship("TapirPermanentToken", back_populates="session") + tapir_recovery_tokens_used: Mapped[List["TapirRecoveryTokensUsed"]] = relationship("TapirRecoveryTokensUsed", back_populates="session") class TapirSessionsAudit(Base): - __tablename__ = 'tapir_sessions_audit' + __tablename__ = "tapir_sessions_audit" + __table_args__ = {"mysql_charset": "latin1"} - session_id: Mapped[int] = mapped_column(ForeignKey('tapir_sessions.session_id'), primary_key=True, server_default=text("'0'"), autoincrement="false") + session_id: Mapped[int] = mapped_column(ForeignKey("tapir_sessions.session_id"), primary_key=True, server_default=text("'0'")) ip_addr: Mapped[str] = mapped_column(String(16), nullable=False, index=True, server_default=FetchedValue()) remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) tracking_cookie: Mapped[str] = mapped_column(String(255), nullable=False, index=True, server_default=FetchedValue()) - session = relationship('TapirSession') - + session = relationship("TapirSession") class TapirStringVariable(Base): - __tablename__ = 'tapir_string_variables' + __tablename__ = "tapir_string_variables" + __table_args__ = {"mysql_charset": "latin1"} variable_id: Mapped[str] = mapped_column(String(32), primary_key=True, server_default=FetchedValue()) value: Mapped[str] = mapped_column(Text, nullable=False) - class TapirString(Base): - __tablename__ = 'tapir_strings' + __tablename__ = "tapir_strings" + __table_args__ = {"mysql_charset": "latin1"} name: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False, server_default=FetchedValue()) module: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False, server_default=FetchedValue()) @@ -1807,25 +1883,9 @@ class TapirString(Base): string: Mapped[str] = mapped_column(Text, nullable=False) - class TapirUser(Base): - __tablename__ = 'tapir_users' - __table_args__ = ( - ForeignKeyConstraint(['policy_class'], ['tapir_policy_classes.class_id'], name='0_510'), - Index('email', 'email', unique=True), - Index('first_name', 'first_name'), - Index('flag_approved', 'flag_approved'), - Index('flag_banned', 'flag_banned'), - Index('flag_can_lock', 'flag_can_lock'), - Index('flag_deleted', 'flag_deleted'), - Index('flag_edit_users', 'flag_edit_users'), - Index('flag_internal', 'flag_internal'), - Index('joined_date', 'joined_date'), - Index('joined_ip_num', 'joined_ip_num'), - Index('last_name', 'last_name'), - Index('policy_class', 'policy_class'), - Index('tracking_cookie', 'tracking_cookie') - ) + __tablename__ = "tapir_users" + __table_args__ = {"mysql_charset": "latin1"} user_id: Mapped[intpk] first_name: Mapped[Optional[str]] = mapped_column(String(50), index=True) @@ -1833,10 +1893,10 @@ class TapirUser(Base): suffix_name: Mapped[Optional[str]] = mapped_column(String(50)) share_first_name: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) share_last_name: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) - email: Mapped[str] = mapped_column(String(255), nullable=False, unique=True, server_default=text("''")) + email: Mapped[str] = mapped_column(String(255), nullable=False, unique=True, index=True, server_default=text("''")) share_email: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'8'")) email_bouncing: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) - policy_class: Mapped[int] = mapped_column(ForeignKey('tapir_policy_classes.class_id'), nullable=False, index=True, server_default=text("'0'")) + policy_class: Mapped[int] = mapped_column(ForeignKey("tapir_policy_classes.class_id"), nullable=False, index=True, server_default=text("'0'")) joined_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) joined_ip_num: Mapped[Optional[str]] = mapped_column(String(16), index=True) joined_remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=text("''")) @@ -1853,68 +1913,65 @@ class TapirUser(Base): flag_allow_tex_produced: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) flag_can_lock: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) - tapir_policy_classes = relationship('TapirPolicyClass', back_populates='tapir_users') - arXiv_control_holds = relationship('ControlHold', foreign_keys='[ControlHold.last_changed_by]', back_populates='tapir_users') - arXiv_control_holds_ = relationship('ControlHold', foreign_keys='[ControlHold.placed_by]', back_populates='tapir_users_') - arXiv_documents = relationship('Document', back_populates='submitter') - arXiv_moderator_api_keys = relationship('ModeratorApiKey', back_populates='user') - tapir_address = relationship('TapirAddress', back_populates='user') - tapir_email_change_tokens = relationship('TapirEmailChangeToken', back_populates='user') - tapir_email_templates = relationship('TapirEmailTemplate', foreign_keys='[TapirEmailTemplate.created_by]', back_populates='tapir_users') - tapir_email_templates_ = relationship('TapirEmailTemplate', foreign_keys='[TapirEmailTemplate.updated_by]', back_populates='tapir_users_') - tapir_email_tokens = relationship('TapirEmailToken', back_populates='user') - tapir_nicknames = relationship('TapirNickname', back_populates='user', uselist=False) - tapir_phone = relationship('TapirPhone', back_populates='user') - tapir_recovery_tokens = relationship('TapirRecoveryToken', back_populates='user') - tapir_sessions = relationship('TapirSession', back_populates='user') - arXiv_cross_controls = relationship('CrossControl', back_populates='user') - arXiv_endorsement_requests = relationship('EndorsementRequest', back_populates='endorsee') - arXiv_jref_controls = relationship('JrefControl', back_populates='user') - arXiv_metadata = relationship('Metadata', back_populates='submitter') - arXiv_show_email_requests = relationship('ShowEmailRequest', back_populates='user') - arXiv_submission_control = relationship('SubmissionControl', back_populates='user') - arXiv_submissions = relationship('Submission', back_populates='submitter') - tapir_admin_audit = relationship('TapirAdminAudit', foreign_keys='[TapirAdminAudit.admin_user]', back_populates='tapir_users') - tapir_admin_audit_ = relationship('TapirAdminAudit', foreign_keys='[TapirAdminAudit.affected_user]', back_populates='tapir_users_') - tapir_email_mailings = relationship('TapirEmailMailing', foreign_keys='[TapirEmailMailing.created_by]', back_populates='tapir_users') - tapir_email_mailings_ = relationship('TapirEmailMailing', foreign_keys='[TapirEmailMailing.sent_by]', back_populates='tapir_users_') - tapir_permanent_tokens = relationship('TapirPermanentToken', back_populates='user') - tapir_recovery_tokens_used = relationship('TapirRecoveryTokensUsed', back_populates='user') - - endorsee_of = relationship('Endorsement', foreign_keys='[Endorsement.endorsee_id]', back_populates='endorsee') - endorses = relationship('Endorsement', foreign_keys='[Endorsement.endorser_id]', back_populates='endorser') - - arXiv_ownership_requests = relationship('OwnershipRequest', back_populates='user') - arXiv_submission_category_proposal = relationship('SubmissionCategoryProposal', back_populates='user') - arXiv_submission_flag = relationship('SubmissionFlag', back_populates='user') - arXiv_submission_hold_reason = relationship('SubmissionHoldReason', back_populates='user') - arXiv_submission_view_flag = relationship('SubmissionViewFlag', back_populates='user') - - owned_papers = relationship("PaperOwner", foreign_keys="[PaperOwner.user_id]", back_populates="owner") - - demographics = relationship('Demographic', foreign_keys="[Demographic.user_id]", uselist=False, back_populates='user') + tapir_policy_classes: Mapped["TapirPolicyClass"] = relationship("TapirPolicyClass", back_populates="tapir_users") + arXiv_control_holds: Mapped[List["ControlHold"]] = relationship("ControlHold", foreign_keys="[ControlHold.last_changed_by]", back_populates="tapir_users") + arXiv_control_holds_: Mapped[List["ControlHold"]] = relationship("ControlHold", foreign_keys="[ControlHold.placed_by]", back_populates="tapir_users_") + arXiv_documents: Mapped[List["Document"]] = relationship("Document", back_populates="submitter") + arXiv_moderator_api_keys: Mapped[List["ModeratorApiKey"]] = relationship("ModeratorApiKey", back_populates="user") + tapir_address: Mapped[List["TapirAddress"]] = relationship("TapirAddress", back_populates="user") + tapir_email_change_tokens: Mapped[List["TapirEmailChangeToken"]] = relationship("TapirEmailChangeToken", back_populates="user") + tapir_email_templates: Mapped[List["TapirEmailTemplate"]] = relationship("TapirEmailTemplate", foreign_keys="[TapirEmailTemplate.created_by]", back_populates="tapir_users") + tapir_email_templates_: Mapped[List["TapirEmailTemplate"]] = relationship("TapirEmailTemplate", foreign_keys="[TapirEmailTemplate.updated_by]", back_populates="tapir_users_") + tapir_email_tokens: Mapped[List["TapirEmailToken"]] = relationship("TapirEmailToken", back_populates="user") + tapir_nicknames: Mapped[List["TapirNickname"]] = relationship("TapirNickname", back_populates="user") + tapir_phone: Mapped[List["TapirPhone"]] = relationship("TapirPhone", back_populates="user") + tapir_recovery_tokens: Mapped[List["TapirRecoveryToken"]] = relationship("TapirRecoveryToken", back_populates="user") + tapir_sessions: Mapped[List["TapirSession"]] = relationship("TapirSession", back_populates="user") + arXiv_cross_controls: Mapped[List["CrossControl"]] = relationship("CrossControl", back_populates="user") + arXiv_endorsement_requests: Mapped[List["EndorsementRequest"]] = relationship("EndorsementRequest", back_populates="endorsee") + arXiv_jref_controls: Mapped[List["JrefControl"]] = relationship("JrefControl", back_populates="user") + arXiv_metadata: Mapped[List["Metadata"]] = relationship("Metadata", back_populates="submitter") + arXiv_show_email_requests: Mapped[List["ShowEmailRequest"]] = relationship("ShowEmailRequest", back_populates="user") + arXiv_submission_control: Mapped[List["SubmissionControl"]] = relationship("SubmissionControl", back_populates="user") + arXiv_submissions: Mapped[List["Submission"]] = relationship("Submission", back_populates="submitter") + tapir_admin_audit: Mapped[List["TapirAdminAudit"]] = relationship("TapirAdminAudit", foreign_keys="[TapirAdminAudit.admin_user]", back_populates="tapir_users") + tapir_admin_audit_: Mapped[List["TapirAdminAudit"]] = relationship("TapirAdminAudit", foreign_keys="[TapirAdminAudit.affected_user]", back_populates="tapir_users_") + tapir_email_mailings: Mapped[List["TapirEmailMailing"]] = relationship("TapirEmailMailing", foreign_keys="[TapirEmailMailing.created_by]", back_populates="tapir_users") + tapir_email_mailings_: Mapped[List["TapirEmailMailing"]] = relationship("TapirEmailMailing", foreign_keys="[TapirEmailMailing.sent_by]", back_populates="tapir_users_") + tapir_permanent_tokens: Mapped[List["TapirPermanentToken"]] = relationship("TapirPermanentToken", back_populates="user") + tapir_recovery_tokens_used: Mapped[List["TapirRecoveryTokensUsed"]] = relationship("TapirRecoveryTokensUsed", back_populates="user") + endorsee_of: Mapped[List["Endorsement"]] = relationship("Endorsement", foreign_keys="[Endorsement.endorsee_id]", back_populates="endorsee") + endorses: Mapped[List["Endorsement"]] = relationship("Endorsement", foreign_keys="[Endorsement.endorser_id]", back_populates="endorser") + arXiv_ownership_requests: Mapped[List["OwnershipRequest"]] = relationship("OwnershipRequest", back_populates="user") + arXiv_submission_category_proposal: Mapped[List["SubmissionCategoryProposal"]] = relationship("SubmissionCategoryProposal", back_populates="user") + arXiv_submission_flag: Mapped[List["SubmissionFlag"]] = relationship("SubmissionFlag", back_populates="user") + arXiv_submission_hold_reason: Mapped[List["SubmissionHoldReason"]] = relationship("SubmissionHoldReason", back_populates="user") + arXiv_submission_locks: Mapped[List["SubmissionLocks"]] = relationship("SubmissionLocks", back_populates="user") + arXiv_submission_view_flag: Mapped[List["SubmissionViewFlag"]] = relationship("SubmissionViewFlag", back_populates="user") + arXiv_check_results: Mapped[List["CheckResults"]] = relationship("CheckResults", back_populates="user") + arXiv_check_responses: Mapped[List["CheckResponses"]] = relationship("CheckResponses", back_populates="user") + owned_papers: Mapped[List["PaperOwner"]] = relationship("PaperOwner", foreign_keys="[PaperOwner.user_id]", back_populates="owner") + demographics = relationship("Demographic", foreign_keys="[Demographic.user_id]", uselist=False, back_populates="user") class AuthorIds(Base): - __tablename__ = 'arXiv_author_ids' + __tablename__ = "arXiv_author_ids" + __table_args__ = {"mysql_charset": "latin1"} - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), primary_key=True) author_id: Mapped[str] = mapped_column(String(50), nullable=False, index=True) updated: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) class Demographic(Base): - __tablename__ = 'arXiv_demographics' - __table_args__ = ( - ForeignKeyConstraint(['archive', 'subject_class'], ['arXiv_categories.archive', 'arXiv_categories.subject_class']), - Index('dem_archive', 'archive', 'subject_class') - ) + __tablename__ = "arXiv_demographics" + __table_args__ = (ForeignKeyConstraint(["archive", "subject_class"], ["arXiv_categories.archive", "arXiv_categories.subject_class"]), {"mysql_charset": "latin1"}) - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), primary_key=True, server_default=FetchedValue()) country: Mapped[str] = mapped_column(String(2), nullable=False, index=True, server_default=FetchedValue()) affiliation: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) url: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) - type: Mapped[Optional[int]] = mapped_column(SmallInteger, index=True) + type: Mapped[Optional[int]] = mapped_column(Integer, index=True) archive: Mapped[Optional[str]] = mapped_column(String(16)) subject_class: Mapped[Optional[str]] = mapped_column(String(16)) original_subject_classes: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) @@ -1933,98 +1990,155 @@ class Demographic(Base): flag_group_stat: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) flag_group_eess: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) flag_group_econ: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) - veto_status: Mapped[Literal['ok', 'no-endorse', 'no-upload', 'no-replace']] = mapped_column(Enum('ok', 'no-endorse', 'no-upload', 'no-replace'), nullable=False, server_default=text("'ok'")) - - user = relationship('TapirUser', back_populates='demographics') - arXiv_category = relationship('Category', primaryjoin='and_(Demographic.archive == Category.archive, Demographic.subject_class == Category.subject_class)', backref='arXiv_demographics') + veto_status: Mapped[Literal["ok", "no-endorse", "no-upload", "no-replace"]] = mapped_column(Enum("ok", "no-endorse", "no-upload", "no-replace"), nullable=False, server_default=text("'ok'")) - GROUP_FLAGS = [ - ('grp_physics', 'flag_group_physics'), - ('grp_math', 'flag_group_math'), - ('grp_cs', 'flag_group_cs'), - ('grp_q-bio', 'flag_group_q_bio'), - ('grp_q-fin', 'flag_group_q_fin'), - ('grp_q-stat', 'flag_group_stat'), - ('grp_q-econ', 'flag_group_econ'), - ('grp_eess', 'flag_group_eess'), - ] + arXiv_category: Mapped["Category"] = relationship( + "Category", primaryjoin="and_(Demographic.archive == Category.archive, Demographic.subject_class == Category.subject_class)", back_populates="arXiv_demographics" + ) @property def groups(self) -> List[str]: """Active groups for this user profile.""" - return [group for group, column in self.GROUP_FLAGS - if getattr(self, column) == 1] + return [group for group, column in self.GROUP_FLAGS if getattr(self, column) == 1] + + # the original user + user = relationship("TapirUser", back_populates="demographics") + + GROUP_FLAGS = [ + ("grp_physics", "flag_group_physics"), + ("grp_math", "flag_group_math"), + ("grp_cs", "flag_group_cs"), + ("grp_q-bio", "flag_group_q_bio"), + ("grp_q-fin", "flag_group_q_fin"), + ("grp_q-stat", "flag_group_stat"), + ("grp_q-econ", "flag_group_econ"), + ("grp_eess", "flag_group_eess"), + ] class OrcidIds(Base): - __tablename__ = 'arXiv_orcid_ids' + __tablename__ = "arXiv_orcid_ids" + __table_args__ = {"mysql_charset": "utf8mb3"} - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), primary_key=True) orcid: Mapped[str] = mapped_column(String(19), nullable=False, index=True) authenticated: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) updated: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) class QueueView(Base): - __tablename__ = 'arXiv_queue_view' + __tablename__ = "arXiv_queue_view" + __table_args__ = {"mysql_charset": "utf8mb3"} - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id', ondelete='CASCADE'), primary_key=True, server_default=FetchedValue()) - last_view: Mapped[Optional[datetime]] - second_last_view: Mapped[Optional[datetime]] + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id", ondelete="CASCADE"), primary_key=True, server_default=FetchedValue()) + last_view: Mapped[Optional[datetime]] = mapped_column(DateTime) + second_last_view: Mapped[Optional[datetime]] = mapped_column(DateTime) total_views: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) class SuspiciousName(Base): - __tablename__ = 'arXiv_suspicious_names' + __tablename__ = "arXiv_suspicious_names" + __table_args__ = {"mysql_charset": "latin1"} - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), primary_key=True, server_default=FetchedValue()) full_name: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) class SwordLicense(Base): - __tablename__ = 'arXiv_sword_licenses' + __tablename__ = "arXiv_sword_licenses" + __table_args__ = {"mysql_charset": "latin1"} - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), primary_key=True) license: Mapped[Optional[str]] = mapped_column(String(127)) updated: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) class TapirDemographic(Base): - __tablename__ = 'tapir_demographics' + __tablename__ = "tapir_demographics" + __table_args__ = {"mysql_charset": "latin1"} - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), primary_key=True, server_default=FetchedValue()) gender: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) share_gender: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - birthday: Mapped[Optional[date]] = mapped_column(Date, index=True) + birthday: Mapped[Optional[dt.date]] = mapped_column(Date, index=True) share_birthday: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - country: Mapped[str] = mapped_column(ForeignKey('tapir_countries.digraph'), nullable=False, index=True, server_default=FetchedValue()) + country: Mapped[str] = mapped_column(ForeignKey("tapir_countries.digraph"), nullable=False, index=True, server_default=FetchedValue()) share_country: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) postal_code: Mapped[str] = mapped_column(String(16), nullable=False, index=True, server_default=FetchedValue()) - tapir_country = relationship('TapirCountry', primaryjoin='TapirDemographic.country == TapirCountry.digraph', backref='tapir_demographics') + tapir_country: Mapped["TapirCountry"] = relationship("TapirCountry", primaryjoin="TapirDemographic.country == TapirCountry.digraph", back_populates="tapir_demographics") class TapirUsersHot(Base): - __tablename__ = 'tapir_users_hot' + __tablename__ = "tapir_users_hot" + __table_args__ = {"mysql_charset": "latin1"} - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), primary_key=True, server_default=FetchedValue()) last_login: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) second_last_login: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) number_sessions: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) class TapirUsersPassword(Base): - __tablename__ = 'tapir_users_password' + __tablename__ = "tapir_users_password" + __table_args__ = {"mysql_charset": "latin1"} - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), primary_key=True, server_default=FetchedValue()) password_storage: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) password_enc: Mapped[str] = mapped_column(String(50), nullable=False, server_default=FetchedValue()) - user = relationship('TapirUser') + user = relationship("TapirUser") + + +class SubmissionLocks(Base): + __tablename__ = "arXiv_submission_locks" + __table_args__ = (Index("arxiv_submission_locks_sub_index", "submission_id", "lock_type", unique=True), {"mysql_charset": "latin1"}) + + submission_lock_id: Mapped[int] = mapped_column(Integer, primary_key=True) + submission_id: Mapped[int] = mapped_column(ForeignKey("arXiv_submissions.submission_id"), nullable=False) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), nullable=False, index=True) + lock_type: Mapped[str] = mapped_column(String(20), nullable=False) + expires: Mapped[datetime] = mapped_column(DateTime, nullable=False) + updated: Mapped[datetime] = mapped_column(DateTime, nullable=False) + released: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + + submission: Mapped["Submission"] = relationship("Submission", back_populates="arXiv_submission_locks") + user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_submission_locks") + + +######################################################################################################## +# Student-lead membership dashboard - supercedes "Subscription_UniversalInstitution" +class MembershipInstitutions(Base): + __tablename__ = "membership_institutions" + __table_args__ = {"mysql_charset": "latin1"} + + sid: Mapped[int] = mapped_column(Integer, primary_key=True) + is_active: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) + name: Mapped[Optional[str]] = mapped_column(String(256), index=True) + country: Mapped[Optional[str]] = mapped_column(String(40)) + country_code: Mapped[Optional[str]] = mapped_column(String(10)) + consortia_code: Mapped[Optional[str]] = mapped_column(String(20)) + member_type: Mapped[Optional[str]] = mapped_column(String(20)) + ror_id: Mapped[Optional[str]] = mapped_column(String(50)) + is_consortium: Mapped[Optional[int]] = mapped_column(Integer) + label: Mapped[Optional[str]] = mapped_column(String(256)) + comment: Mapped[Optional[str]] = mapped_column(Text) + + +# Student-lead membership dashboard +class MembershipUsers(Base): + __tablename__ = "membership_users" + __table_args__ = {"mysql_charset": "latin1"} + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + sid: Mapped[int] = mapped_column(Integer, nullable=False) + user_id: Mapped[Optional[int]] = mapped_column(Integer) +######################################################################################################## +# class DBLaTeXMLDocuments(LaTeXMLBase): - __tablename__ = 'arXiv_latexml_doc' + __tablename__ = "arXiv_latexml_doc" paper_id: Mapped[str] = mapped_column(String(20), primary_key=True) document_version: Mapped[intpk] @@ -2034,69 +2148,197 @@ class DBLaTeXMLDocuments(LaTeXMLBase): # - 2 = failure conversion_status: Mapped[int] = mapped_column(Integer, nullable=False) latexml_version: Mapped[str] = mapped_column(String(40), nullable=False) - tex_checksum: Mapped[Optional[str]] + tex_checksum: Mapped[Optional[str]] = mapped_column(String(255)) conversion_start_time: Mapped[Optional[int]] = mapped_column(Integer) conversion_end_time: Mapped[Optional[int]] = mapped_column(Integer) publish_dt: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True)) -class DBLaTeXMLSubmissions (LaTeXMLBase): - __tablename__ = 'arXiv_latexml_sub' + +class DBLaTeXMLSubmissions(LaTeXMLBase): + __tablename__ = "arXiv_latexml_sub" submission_id: Mapped[intpk] - # conversion_status codes: + # conversion_status codes: # - 0 = in progress # - 1 = success # - 2 = failure conversion_status: Mapped[int] = mapped_column(Integer, nullable=False) latexml_version: Mapped[str] = mapped_column(String(40), nullable=False) - tex_checksum: Mapped[Optional[str]] + tex_checksum: Mapped[Optional[str]] = mapped_column(String(255)) conversion_start_time: Mapped[Optional[int]] conversion_end_time: Mapped[Optional[int]] -class DBLaTeXMLFeedback (LaTeXMLBase): - __tablename__ = 'feedback' - + +class DBLaTeXMLFeedback(LaTeXMLBase): + __tablename__ = "feedback" + id: Mapped[str] = mapped_column(String(40), primary_key=True) - canonical_url: Mapped[Optional[str]] - conversion_url: Mapped[Optional[str]] + canonical_url: Mapped[Optional[str]] = mapped_column(String(255)) + conversion_url: Mapped[Optional[str]] = mapped_column(String(255)) report_time: Mapped[Optional[int]] = mapped_column(BigInteger) - browser_info: Mapped[Optional[str]] - location_low: Mapped[Optional[str]] - location_high: Mapped[Optional[str]] - description: Mapped[Optional[str]] - selected_html: Mapped[Optional[str]] - initiation_mode: Mapped[Optional[str]] + browser_info: Mapped[Optional[str]] = mapped_column(String(255)) + location_low: Mapped[Optional[str]] = mapped_column(String(255)) + location_high: Mapped[Optional[str]] = mapped_column(String(255)) + description: Mapped[Optional[str]] = mapped_column(String(255)) + selected_html: Mapped[Optional[str]] = mapped_column(String(255)) + initiation_mode: Mapped[Optional[str]] = mapped_column(String(255)) + + +# From modapi + + +class CheckRoles(Base): + """swimlanes: editor, student, moderator, qa""" + + __tablename__ = "arXiv_check_roles" + __table_args__ = {"mysql_charset": "latin1"} + + check_role_id: Mapped[int] = mapped_column(Integer, primary_key=True) + name: Mapped[str] = mapped_column(String(40), nullable=False) + description: Mapped[Optional[str]] = mapped_column(String(200)) + + def __repr__(self): + return f"{ type(self).__name__ }/{ self.check_role_id }:{self.name}" + + +class CheckResultViews(Base): + """A hint for how arxiv-check can parse and view check_results.data""" + + __tablename__ = "arXiv_check_result_views" + __table_args__ = {"mysql_charset": "latin1"} + + check_result_view_id: Mapped[int] = mapped_column(Integer, primary_key=True) + name: Mapped[str] = mapped_column(String(40), nullable=False) + description: Mapped[Optional[str]] = mapped_column(String(200)) + + def __repr__(self): + return f"{ type(self).__name__ }/{ self.check_result_view_id }:{self.name}" + + +class CheckTargets(Base): + """Will the QA check need to respond to updates to the file or the + database metadata.""" + + __tablename__ = "arXiv_check_targets" + __table_args__ = {"mysql_charset": "latin1"} + + check_target_id: Mapped[int] = mapped_column(Integer, primary_key=True) + name: Mapped[str] = mapped_column(String(40), nullable=False) + description: Mapped[Optional[str]] = mapped_column(String(200)) + + def __repr__(self): + return f"{ type(self).__name__ }/{ self.check_target_id }:{self.name}" + + +class Checks(Base): + __tablename__ = "arXiv_checks" + __table_args__ = {"mysql_charset": "latin1"} + + check_id: Mapped[int] = mapped_column(Integer, primary_key=True) + check_target_id: Mapped[int] = mapped_column(ForeignKey("arXiv_check_targets.check_target_id"), nullable=False, index=True) + # , ondelete='CASCADE', onupdate='CASCADE' + check_role_id = Column(ForeignKey("arXiv_check_roles.check_role_id"), index=False) + check_result_view_id: Mapped[int] = mapped_column(ForeignKey("arXiv_check_result_views.check_result_view_id"), nullable=False, index=True, server_default=text("'1'")) + name: Mapped[str] = mapped_column(String(40), nullable=False) + description: Mapped[Optional[str]] = mapped_column(String(200)) + enable_check: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + enable_hold: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + enable_queue: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + retry_minutes: Mapped[int] = mapped_column(SmallInteger, nullable=False, server_default=text("'0'")) + optional: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) + persist_response: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + target: Mapped["CheckTargets"] = relationship("CheckTargets") + role: Mapped["CheckRoles"] = relationship("CheckRoles") + + view: Mapped["CheckResultViews"] = relationship("CheckResultViews") + arXiv_check_results: Mapped[List["CheckResults"]] = relationship("CheckResults", back_populates="check") + + def __repr__(self): + return f"{ type(self).__name__ }/{ self.check_id }:{self.name};{'enabled' if self.enable_check else ''}" + + +class CheckResults(Base): + __tablename__ = "arXiv_check_results" + __table_args__ = {"mysql_charset": "latin1"} + + check_result_id: Mapped[int] = mapped_column(Integer, primary_key=True) + submission_id: Mapped[int] = mapped_column(ForeignKey("arXiv_submissions.submission_id"), nullable=False, index=True) + data_version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + metadata_version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + check_id: Mapped[int] = mapped_column(ForeignKey("arXiv_checks.check_id"), nullable=False, index=True) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), nullable=False, index=True) + ok: Mapped[int] = mapped_column(Integer, nullable=False) + created: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=func.now()) + message: Mapped[Optional[str]] = mapped_column(String(40)) + data: Mapped[Optional[str]] = mapped_column(String(2000)) + submission: Mapped["Submission"] = relationship("Submission", back_populates="arXiv_check_results") + + check: Mapped["Checks"] = relationship("Checks", back_populates="arXiv_check_results") + user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_check_results") + check_responses: Mapped[List["CheckResponses"]] = relationship("CheckResponses", back_populates="check_result") + """ + select max(length(logtext)) from arXiv_admin_log; #65535 + select length(logtext), count(*) from arXiv_admin_log where length(logtext)>200 and username like 'qaadmin' group by length(logtext) order by length(logtext) desc limit 200 + mysql max varchar length: 65,535 + """ + + def __repr__(self): + return f"{ type(self).__name__ }/{ self.check_result_id };check={self.check_id};s/{ self.submission_id };d={self.data_version};m={self.metadata_version};ok={ self.ok}" + + +class CheckResponses(Base): + __tablename__ = "arXiv_check_responses" + __table_args__ = {"mysql_charset": "latin1"} + + check_response_id: Mapped[int] = mapped_column(Integer, primary_key=True) + check_result_id: Mapped[int] = mapped_column(ForeignKey("arXiv_check_results.check_result_id"), nullable=False, index=True) + user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), nullable=False, index=True) + ok: Mapped[int] = mapped_column(Integer, nullable=False) + persist_response: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + created: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=func.now()) + message: Mapped[Optional[str]] = mapped_column(String(200)) + user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_check_responses") + + check_result: Mapped["CheckResults"] = relationship("CheckResults", back_populates="check_responses") + """If the related CheckResults ok==0, admin/mods respond with decision on whether that qa hold should stand or be dismissed.""" + """This admin/mod decision is accepted for future check_results, if the submission is updated. """ + + def __repr__(self): + return f"{ type(self).__name__ }/{ self.check_response_id };result={self.check_result_id};ok={ self.ok}" def configure_db_engine(classic_engine: Engine, latexml_engine: Optional[Engine]) -> Tuple[Engine, Optional[Engine]]: - session_factory.configure(binds={ - Base: classic_engine, - LaTeXMLBase: (latexml_engine if latexml_engine else classic_engine), - t_arXiv_stats_hourly: classic_engine, - t_arXiv_admin_state: classic_engine, - t_arXiv_bad_pw: classic_engine, - t_arXiv_black_email: classic_engine, - t_arXiv_block_email: classic_engine, - t_arXiv_bogus_subject_class: classic_engine, - t_arXiv_duplicates: classic_engine, - t_arXiv_in_category: classic_engine, - t_arXiv_moderators: classic_engine, - t_arXiv_ownership_requests_papers: classic_engine, - t_arXiv_refresh_list: classic_engine, - t_arXiv_updates_tmp: classic_engine, - t_arXiv_white_email: classic_engine, - t_arXiv_xml_notifications: classic_engine, - t_demographics_backup: classic_engine, - t_tapir_email_change_tokens_used: classic_engine, - t_tapir_email_tokens_used: classic_engine, - t_tapir_error_log: classic_engine, - t_tapir_no_cookies: classic_engine, - t_tapir_periodic_tasks_log: classic_engine, - t_tapir_periodic_tasks_log: classic_engine, - t_tapir_permanent_tokens_used: classic_engine, - t_tapir_save_post_variables: classic_engine - }) + session_factory.configure( + binds={ + Base: classic_engine, + LaTeXMLBase: (latexml_engine if latexml_engine else classic_engine), + t_arXiv_stats_hourly: classic_engine, + t_arXiv_admin_state: classic_engine, + t_arXiv_bad_pw: classic_engine, + t_arXiv_black_email: classic_engine, + t_arXiv_block_email: classic_engine, + t_arXiv_bogus_subject_class: classic_engine, + t_arXiv_duplicates: classic_engine, + t_arXiv_in_category: classic_engine, + t_arXiv_moderators: classic_engine, + t_arXiv_ownership_requests_papers: classic_engine, + t_arXiv_refresh_list: classic_engine, + t_arXiv_updates_tmp: classic_engine, + t_arXiv_white_email: classic_engine, + t_arXiv_xml_notifications: classic_engine, + t_demographics_backup: classic_engine, + t_tapir_email_change_tokens_used: classic_engine, + t_tapir_email_tokens_used: classic_engine, + t_tapir_error_log: classic_engine, + t_tapir_no_cookies: classic_engine, + t_tapir_periodic_tasks_log: classic_engine, + t_tapir_periodic_tasks_log: classic_engine, + t_tapir_permanent_tokens_used: classic_engine, + t_tapir_save_post_variables: classic_engine, + } + ) return classic_engine, latexml_engine + # Configure the models from env vars at package load time configure_db_engine(_classic_engine, _latexml_engine) diff --git a/arxiv/db/orig_models.py b/arxiv/db/orig_models.py new file mode 100644 index 000000000..4e216d2c6 --- /dev/null +++ b/arxiv/db/orig_models.py @@ -0,0 +1,2303 @@ +""" +************************************************* +DO NOT EDIT WITHOUT CONSULTING THE DOCUMENTATION! +************************************************* + +These models represent the entire arXiv DB and the LaTeXML DB. + +arxiv/db/models.py was generated by using arxiv/development/db_codegen.py along with arxiv/development/sqlacodegen. + +arxiv/db/orig_models.py, arxiv/db/arxiv-db-metadata.yaml are the inputs for the sqlacodegen. + +See development/README.md for the details. + +If you want to keep the model definition over time, add comment with the intention/reason. +Without it, it may be subjected to removal. + +""" + +from typing import Optional, Literal, Any, Tuple, List +import re +import hashlib +import datetime as dt +from datetime import datetime, date +from dateutil.tz import gettz, tzutc +from sqlalchemy.dialects.mysql import VARCHAR +from validators import url as is_valid_url + +from sqlalchemy import ( + BINARY, + BigInteger, + Column, + Date, + DateTime, + Engine, + Enum, + ForeignKey, + ForeignKeyConstraint, + Index, + Integer, + JSON, + Numeric, + PrimaryKeyConstraint, + SmallInteger, + String, + TIMESTAMP, + Table, + Text, + func, + text, +) +from sqlalchemy.schema import FetchedValue +from sqlalchemy.orm import ( + Mapped, + mapped_column, + relationship +) + +from ..config import settings +from . import Base, LaTeXMLBase, metadata, \ + session_factory, _classic_engine, _latexml_engine + +from .types import intpk +from ..document.version import SOURCE_FORMAT + +tb_secret = settings.TRACKBACK_SECRET +tz = gettz(settings.ARXIV_BUSINESS_TZ) + + +class MemberInstitution(Base): + """Deprecated - superceded by membership_institutions""" + __tablename__ = 'Subscription_UniversalInstitution' + + resolver_URL: Mapped[Optional[str]] = mapped_column(String(255)) + name: Mapped[str] = mapped_column(String(255), nullable=False, index=True) + label: Mapped[Optional[str]] = mapped_column(String(255)) + id: Mapped[intpk] + alt_text: Mapped[Optional[str]] = mapped_column(String(255)) + link_icon: Mapped[Optional[str]] = mapped_column(String(255)) + note: Mapped[Optional[str]] = mapped_column(String(255)) + + +class MemberInstitutionContact(Base): + """Deprecated - superceded by membership_institution_users""" + __tablename__ = 'Subscription_UniversalInstitutionContact' + + email: Mapped[Optional[str]] = mapped_column(String(255)) + sid: Mapped[int] = mapped_column(ForeignKey('Subscription_UniversalInstitution.id', ondelete='CASCADE'), nullable=False, index=True) + active: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + contact_name: Mapped[Optional[str]] = mapped_column(String(255)) + id: Mapped[intpk] + phone: Mapped[Optional[str]] = mapped_column(String(255)) + note: Mapped[Optional[str]] = mapped_column(String(2048)) + + Subscription_UniversalInstitution = relationship('MemberInstitution', primaryjoin='MemberInstitutionContact.sid == MemberInstitution.id') + + +class MemberInstitutionIP(Base): + __tablename__ = 'Subscription_UniversalInstitutionIP' + __table_args__ = ( + Index('ip', 'start', 'end'), + ) + + sid: Mapped[int] = mapped_column(ForeignKey('Subscription_UniversalInstitution.id', ondelete='CASCADE'), nullable=False, index=True) + id: Mapped[intpk] + exclude: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + end: Mapped[int] = mapped_column(BigInteger, nullable=False, index=True) + start: Mapped[int] = mapped_column(BigInteger, nullable=False, index=True) + + Subscription_UniversalInstitution = relationship('MemberInstitution', primaryjoin='MemberInstitutionIP.sid == MemberInstitution.id') + + + +class AdminLog(Base): + __tablename__ = 'arXiv_admin_log' + + id: Mapped[intpk] + logtime: Mapped[Optional[str]] = mapped_column(String(24)) + created: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=text('CURRENT_TIMESTAMP'), server_onupdate=text('CURRENT_TIMESTAMP')) + paper_id: Mapped[Optional[str]] = mapped_column(String(20), index=True) + username: Mapped[Optional[str]] = mapped_column(String(20), index=True) + host: Mapped[Optional[str]] = mapped_column(String(64)) + program: Mapped[Optional[str]] = mapped_column(String(20)) + command: Mapped[Optional[str]] = mapped_column(String(20), index=True) + logtext: Mapped[Optional[str]] = mapped_column(Text) + document_id: Mapped[Optional[int]] = mapped_column(Integer) + submission_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) + notify: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + + + +class AdminMetadata(Base): + __tablename__ = 'arXiv_admin_metadata' + __table_args__ = ( + Index('admin_metadata_pidv', 'paper_id', 'version'), + ) + + metadata_id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True) + document_id = mapped_column(ForeignKey('arXiv_documents.document_id', ondelete='CASCADE'), index=True) + paper_id: Mapped[Optional[str]] = mapped_column(String(64)) + created: Mapped[Optional[datetime]] + updated: Mapped[Optional[datetime]] + submitter_name: Mapped[Optional[str]] = mapped_column(String(64)) + submitter_email: Mapped[Optional[str]] = mapped_column(String(64)) + history: Mapped[Optional[str]] = mapped_column(Text) + source_size: Mapped[Optional[int]] = mapped_column(Integer) + source_type: Mapped[Optional[str]] = mapped_column(String(12)) + title: Mapped[Optional[str]] = mapped_column(Text) + authors: Mapped[Optional[str]] = mapped_column(Text) + category_string: Mapped[Optional[str]] = mapped_column(String(255)) + comments: Mapped[Optional[str]] = mapped_column(Text) + proxy: Mapped[Optional[str]] = mapped_column(String(255)) + report_num: Mapped[Optional[str]] = mapped_column(Text) + msc_class: Mapped[Optional[str]] = mapped_column(String(255)) + acm_class: Mapped[Optional[str]] = mapped_column(String(255)) + journal_ref: Mapped[Optional[str]] = mapped_column(Text) + doi: Mapped[Optional[str]] = mapped_column(String(255)) + abstract: Mapped[Optional[str]] = mapped_column(Text) + license: Mapped[Optional[str]] = mapped_column(String(255)) + version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + modtime: Mapped[Optional[int]] = mapped_column(Integer) + is_current: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + + document = relationship('Document', primaryjoin='AdminMetadata.document_id == Document.document_id', backref='arXiv_admin_metadata') + + + +t_arXiv_admin_state = Table( + 'arXiv_admin_state', metadata, + Column('document_id', Integer, unique=True), + Column('timestamp', DateTime, nullable=False, server_default=FetchedValue()), + Column('abs_timestamp', Integer), + Column('src_timestamp', Integer), + Column('state', Enum('pending', 'ok', 'bad'), nullable=False, server_default=FetchedValue()), + Column('admin', String(32)), + Column('comment', String(255)) +) + +class ArchiveCategory(Base): + __tablename__ = 'arXiv_archive_category' + + archive_id: Mapped[str] = mapped_column(String(16), primary_key=True, nullable=False, server_default=FetchedValue()) + category_id: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False) + + + +class ArchiveDef(Base): + __tablename__ = 'arXiv_archive_def' + + archive: Mapped[str] = mapped_column(String(16), primary_key=True, server_default=FetchedValue()) + name: Mapped[Optional[str]] = mapped_column(String(255)) + + + +class ArchiveGroup(Base): + __tablename__ = 'arXiv_archive_group' + + archive_id: Mapped[str] = mapped_column(String(16), primary_key=True, nullable=False, server_default=FetchedValue()) + group_id: Mapped[str] = mapped_column(String(16), primary_key=True, nullable=False, server_default=FetchedValue()) + + + +class Archive(Base): + __tablename__ = 'arXiv_archives' + + archive_id: Mapped[str] = mapped_column(String(16), primary_key=True, server_default=FetchedValue()) + in_group = mapped_column(ForeignKey('arXiv_groups.group_id'), nullable=False, index=True, server_default=FetchedValue()) + archive_name: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + start_date: Mapped[str] = mapped_column(String(4), nullable=False, server_default=FetchedValue()) + end_date: Mapped[str] = mapped_column(String(4), nullable=False, server_default=FetchedValue()) + subdivided: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + # additional relation + arXiv_group = relationship('Group', primaryjoin='Archive.in_group == Group.group_id', back_populates='arXiv_archives') + + + +class AwsConfig(Base): + __tablename__ = 'arXiv_aws_config' + + domain: Mapped[str] = mapped_column(String(75), primary_key=True, nullable=False) + keyname: Mapped[str] = mapped_column(String(60), primary_key=True, nullable=False) + value: Mapped[Optional[str]] = mapped_column(String(150)) + + + +class AwsFile(Base): + __tablename__ = 'arXiv_aws_files' + + type: Mapped[str] = mapped_column(String(10), nullable=False, index=True, server_default=FetchedValue()) + filename: Mapped[str] = mapped_column(String(100), primary_key=True, server_default=FetchedValue()) + md5sum: Mapped[Optional[str]] = mapped_column(String(50)) + content_md5sum: Mapped[Optional[str]] = mapped_column(String(50)) + size: Mapped[Optional[int]] = mapped_column(Integer) + timestamp: Mapped[Optional[datetime]] + yymm: Mapped[Optional[str]] = mapped_column(String(4)) + seq_num: Mapped[Optional[int]] = mapped_column(Integer) + first_item: Mapped[Optional[str]] = mapped_column(String(20)) + last_item: Mapped[Optional[str]] = mapped_column(String(20)) + num_items: Mapped[Optional[int]] = mapped_column(Integer) + + + +t_arXiv_bad_pw = Table( + 'arXiv_bad_pw', metadata, + Column('user_id', ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()) +) + + +class BibFeed(Base): + __tablename__ = 'arXiv_bib_feeds' + + bib_id: Mapped[intpk] + name: Mapped[str] = mapped_column(String(64), nullable=False, server_default=FetchedValue()) + priority: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + uri: Mapped[Optional[str]] = mapped_column(String(255)) + identifier: Mapped[Optional[str]] = mapped_column(String(255)) + version: Mapped[Optional[str]] = mapped_column(String(255)) + strip_journal_ref: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + concatenate_dupes: Mapped[Optional[int]] = mapped_column(Integer) + max_updates: Mapped[Optional[int]] = mapped_column(Integer) + email_errors: Mapped[Optional[str]] = mapped_column(String(255)) + prune_ids: Mapped[Optional[str]] = mapped_column(Text) + prune_regex: Mapped[Optional[str]] = mapped_column(Text) + enabled: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + + + +class BibUpdate(Base): + __tablename__ = 'arXiv_bib_updates' + + update_id: Mapped[intpk] + document_id: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + bib_id: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + updated: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) + journal_ref: Mapped[Optional[str]] = mapped_column(Text) + doi: Mapped[Optional[str]] = mapped_column(Text) + + + +t_arXiv_black_email = Table( + 'arXiv_black_email', metadata, + Column('pattern', String(64)) +) + + +t_arXiv_block_email = Table( + 'arXiv_block_email', metadata, + Column('pattern', String(64)) +) + + +class BogusCountries(Base): + __tablename__ = 'arXiv_bogus_countries' + + user_id: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) + country_name: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + + + +t_arXiv_bogus_subject_class = Table( + 'arXiv_bogus_subject_class', metadata, + Column('document_id', ForeignKey('arXiv_documents.document_id'), nullable=False, index=True, server_default=FetchedValue()), + Column('category_name', String(255), nullable=False, server_default=FetchedValue()) +) + + +class Category(Base): + __tablename__ = 'arXiv_categories' + + # link to arXiv_archive + archive: Mapped[str] = mapped_column(ForeignKey('arXiv_archives.archive_id'), primary_key=True, nullable=False, server_default=FetchedValue()) + subject_class: Mapped[str] = mapped_column(String(16), primary_key=True, nullable=False, server_default=FetchedValue()) + definitive: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + active: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + category_name: Mapped[Optional[str]] = mapped_column(String(255)) + endorse_all: Mapped[Literal['y', 'n', 'd']] = mapped_column(Enum('y', 'n', 'd'), nullable=False, server_default=text("'d'")) + endorse_email: Mapped[Literal['y', 'n', 'd']] = mapped_column(Enum('y', 'n', 'd'), nullable=False, server_default=text("'d'")) + papers_to_endorse: Mapped[int] = mapped_column(SmallInteger, nullable=False, server_default=text("'0'")) + endorsement_domain: Mapped[Optional[str]] = mapped_column(ForeignKey('arXiv_endorsement_domains.endorsement_domain'), index=True) + + # link to category + arXiv_archive = relationship('Archive', primaryjoin='Category.archive == Archive.archive_id', back_populates='arXiv_categories') + arXiv_endorsements = relationship('Endorsement', back_populates='arXiv_categories') + arXiv_endorsement_domain = relationship('EndorsementDomain', primaryjoin='Category.endorsement_domain == EndorsementDomain.endorsement_domain', back_populates='arXiv_categories') + arXiv_endorsement_requests = relationship('EndorsementRequest', back_populates='arXiv_categories') + +class QuestionableCategory(Category): + __tablename__ = 'arXiv_questionable_categories' + __table_args__ = ( + ForeignKeyConstraint(['archive', 'subject_class'], ['arXiv_categories.archive', 'arXiv_categories.subject_class']), + ) + + archive: Mapped[str] = mapped_column(String(16), primary_key=True, nullable=False, server_default=FetchedValue()) + subject_class: Mapped[str] = mapped_column(String(16), primary_key=True, nullable=False, server_default=FetchedValue()) + + + +class CategoryDef(Base): + __tablename__ = 'arXiv_category_def' + + category: Mapped[str] = mapped_column(String(32), primary_key=True) + name: Mapped[Optional[str]] = mapped_column(String(255)) + active: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + + + +class ControlHold(Base): + __tablename__ = 'arXiv_control_holds' + __table_args__ = ( + Index('control_id', 'hold_type'), + ) + + hold_id: Mapped[intpk] + control_id: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + hold_type: Mapped[Literal['submission', 'cross', 'jref']] = mapped_column(Enum('submission', 'cross', 'jref'), nullable=False, index=True, server_default=FetchedValue()) + hold_status: Mapped[Literal['held', 'extended', 'accepted', 'rejected']] = mapped_column(Enum('held', 'extended', 'accepted', 'rejected'), nullable=False, index=True, server_default=FetchedValue()) + hold_reason: Mapped[str] = mapped_column(String(255), nullable=False, index=True, server_default=FetchedValue()) + hold_data: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + origin: Mapped[Literal['auto', 'user', 'admin', 'moderator']] = mapped_column(Enum('auto', 'user', 'admin', 'moderator'), nullable=False, index=True, server_default=FetchedValue()) + placed_by: Mapped[Optional[int]] = mapped_column(ForeignKey('tapir_users.user_id'), index=True) + last_changed_by: Mapped[Optional[int]] = mapped_column(ForeignKey('tapir_users.user_id'), index=True) + + tapir_users = relationship('TapirUser', foreign_keys=[last_changed_by], back_populates='arXiv_control_holds') + tapir_users_ = relationship('TapirUser', foreign_keys=[placed_by], back_populates='arXiv_control_holds_') + + + +class CrossControl(Base): + __tablename__ = 'arXiv_cross_control' + __table_args__ = ( + ForeignKeyConstraint(['archive', 'subject_class'], ['arXiv_categories.archive', 'arXiv_categories.subject_class']), + Index('document_id', 'document_id', 'version'), + Index('archive', 'archive', 'subject_class') + ) + + control_id: Mapped[intpk] + document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id'), nullable=False, server_default=FetchedValue()) + version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + desired_order: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()) + status: Mapped[Literal['new', 'frozen', 'published', 'rejected']] = mapped_column(Enum('new', 'frozen', 'published', 'rejected'), nullable=False, index=True, server_default=FetchedValue()) + flag_must_notify: Mapped[Optional[Literal['0', '1']]] = mapped_column(Enum('0', '1'), server_default=FetchedValue()) + archive: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) + subject_class: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) + request_date: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + freeze_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + publish_date: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + arXiv_category = relationship('Category', primaryjoin='and_(CrossControl.archive == Category.archive, CrossControl.subject_class == Category.subject_class)', backref='arXiv_cross_controls') + document = relationship('Document', primaryjoin='CrossControl.document_id == Document.document_id', back_populates='arXiv_cross_controls') + user = relationship('TapirUser', primaryjoin='CrossControl.user_id == TapirUser.user_id', back_populates='arXiv_cross_controls') + + + +class DataciteDois(Base): + __tablename__ = 'arXiv_datacite_dois' + __table_args__ = ( + Index('account_paper_id', 'account', 'paper_id'), + ) + + doi: Mapped[str] = mapped_column(String(255), primary_key=True) + account: Mapped[Optional[Literal['test', 'prod']]] = mapped_column(Enum('test', 'prod')) + metadata_id: Mapped[int] = mapped_column(ForeignKey('arXiv_metadata.metadata_id'), nullable=False, index=True) + paper_id: Mapped[str] = mapped_column(String(64), nullable=False) + created: Mapped[Optional[datetime]] = mapped_column(DateTime, server_default=FetchedValue()) + updated: Mapped[Optional[datetime]] = mapped_column(DateTime, server_default=FetchedValue()) + + metadata_ = relationship('Metadata', primaryjoin='DataciteDois.metadata_id == Metadata.metadata_id', backref='arXiv_datacite_dois') + + + +class DBLPAuthor(Base): + __tablename__ = 'arXiv_dblp_authors' + + author_id: Mapped[int] = mapped_column(Integer, primary_key=True, unique=True) + name: Mapped[Optional[str]] = mapped_column(String(40), unique=True) + + + +class DBLPDocumentAuthor(Base): + __tablename__ = 'arXiv_dblp_document_authors' + + # join with document + document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id'), primary_key=True, nullable=False, index=True) + + # join with author + author_id: Mapped[int] = mapped_column(ForeignKey('arXiv_dblp_authors.author_id'), primary_key=True, nullable=False, index=True, server_default=FetchedValue()) + + position: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + # join with dblp author + author = relationship('DBLPAuthor', primaryjoin='DBLPDocumentAuthor.author_id == DBLPAuthor.author_id', backref='arXiv_dblp_document_authors') + + # join with document + document = relationship('Document', primaryjoin='DBLPDocumentAuthor.document_id == Document.document_id', backref='arXiv_dblp_document_authors') + + + +class DocumentCategory(Base): + __tablename__ = 'arXiv_document_category' + + document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id', ondelete='CASCADE'), primary_key=True, nullable=False, index=True, server_default=FetchedValue()) + category = mapped_column(ForeignKey('arXiv_category_def.category'), primary_key=True, nullable=False, index=True) + is_primary: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + arXiv_category_def: Mapped[Optional[str]] = relationship('CategoryDef', primaryjoin='DocumentCategory.category == CategoryDef.category', backref='arXiv_document_categories') + document = relationship('Document', primaryjoin='DocumentCategory.document_id == Document.document_id', backref='arXiv_document_categories') + + + +class Document(Base): + __tablename__ = 'arXiv_documents' + + document_id: Mapped[intpk] + paper_id: Mapped[str] = mapped_column(String(20), nullable=False, unique=True, server_default=FetchedValue()) + title: Mapped[str] = mapped_column(String(255), nullable=False, index=True, server_default=FetchedValue()) + authors: Mapped[Optional[str]] = mapped_column(Text) + submitter_email: Mapped[str] = mapped_column(String(64), nullable=False, index=True, server_default=FetchedValue()) + submitter_id: Mapped[Optional[int]] = mapped_column(ForeignKey('tapir_users.user_id'), index=True) + dated: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + primary_subject_class: Mapped[Optional[str]] = mapped_column(String(16)) + created: Mapped[Optional[datetime]] + + # join it with user to get the user info + submitter = relationship('TapirUser', primaryjoin='Document.submitter_id == TapirUser.user_id', back_populates='arXiv_documents') + owners = relationship("PaperOwner", back_populates="document") + arXiv_cross_controls = relationship('CrossControl', back_populates='document') + +class DBLP(Document): + __tablename__ = 'arXiv_dblp' + + document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id'), primary_key=True, server_default=FetchedValue()) + url: Mapped[Optional[str]] = mapped_column(String(80)) + + +class PaperPw(Document): + __tablename__ = 'arXiv_paper_pw' + + document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id'), primary_key=True, server_default=FetchedValue()) + password_storage: Mapped[Optional[int]] = mapped_column(Integer) + password_enc: Mapped[Optional[str]] = mapped_column(String(50)) + + + +t_arXiv_duplicates = Table( + 'arXiv_duplicates', metadata, + Column('user_id', ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()), + Column('email', String(255)), + Column('username', String(255)) +) + + +class EndorsementDomain(Base): + __tablename__ = 'arXiv_endorsement_domains' + + endorsement_domain: Mapped[str] = mapped_column(String(32), primary_key=True, server_default=FetchedValue()) + endorse_all: Mapped[Literal['y', 'n']] = mapped_column(Enum('y', 'n'), nullable=False, server_default=FetchedValue()) + mods_endorse_all: Mapped[Literal['y', 'n']] = mapped_column(Enum('y', 'n'), nullable=False, server_default=FetchedValue()) + endorse_email: Mapped[Literal['y', 'n']] = mapped_column(Enum('y', 'n'), nullable=False, server_default=FetchedValue()) + papers_to_endorse: Mapped[int] = mapped_column(SmallInteger, nullable=False, server_default=FetchedValue()) + + + +class EndorsementRequest(Base): + __tablename__ = 'arXiv_endorsement_requests' + __table_args__ = ( + ForeignKeyConstraint(['archive', 'subject_class'], ['arXiv_categories.archive', 'arXiv_categories.subject_class']), + Index('endorsee_id_2', 'endorsee_id', 'archive', 'subject_class') + ) + + request_id: Mapped[intpk] + endorsee_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()) + archive: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) + subject_class: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) + secret: Mapped[str] = mapped_column(String(16), nullable=False, unique=True, server_default=FetchedValue()) + flag_valid: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + issued_when: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + point_value: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + arXiv_categories = relationship('Category', primaryjoin='and_(EndorsementRequest.archive == Category.archive, EndorsementRequest.subject_class == Category.subject_class)', back_populates='arXiv_endorsement_requests') + endorsee = relationship('TapirUser', primaryjoin='EndorsementRequest.endorsee_id == TapirUser.user_id', back_populates='arXiv_endorsement_requests', uselist=False) + endorsement = relationship('Endorsement', back_populates='request', uselist=False) + audit = relationship('EndorsementRequestsAudit', uselist=False) + + +class EndorsementRequestsAudit(EndorsementRequest): + __tablename__ = 'arXiv_endorsement_requests_audit' + + request_id: Mapped[int] = mapped_column(ForeignKey('arXiv_endorsement_requests.request_id'), primary_key=True, server_default=FetchedValue()) + session_id: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + remote_addr: Mapped[Optional[str]] = mapped_column(String(16)) + remote_host: Mapped[Optional[str]] = mapped_column(String(255)) + tracking_cookie: Mapped[Optional[str]] = mapped_column(String(255)) + + + +class Endorsement(Base): + __tablename__ = 'arXiv_endorsements' + __table_args__ = ( + ForeignKeyConstraint(['archive', 'subject_class'], ['arXiv_categories.archive', 'arXiv_categories.subject_class']), + Index('endorsement_archive', 'archive', 'subject_class'), + Index('endorser_id_2', 'endorser_id', 'endorsee_id', 'archive', 'subject_class') + ) + + endorsement_id: Mapped[intpk] + endorser_id: Mapped[Optional[int]] = mapped_column(ForeignKey('tapir_users.user_id'), index=True) + endorsee_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()) + archive: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) + subject_class: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) + flag_valid: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + type: Mapped[Optional[Literal['user', 'admin', 'auto']]] = mapped_column(Enum('user', 'admin', 'auto')) + point_value: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + issued_when: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + request_id: Mapped[Optional[int]] = mapped_column(ForeignKey('arXiv_endorsement_requests.request_id'), index=True) + + arXiv_categories = relationship('Category', primaryjoin='and_(Endorsement.archive == Category.archive, Endorsement.subject_class == Category.subject_class)', back_populates='arXiv_endorsements') + endorsee = relationship('TapirUser', primaryjoin='Endorsement.endorsee_id == TapirUser.user_id', back_populates='endorsee_of') + endorser = relationship('TapirUser', primaryjoin='Endorsement.endorser_id == TapirUser.user_id', back_populates='endorses') + request = relationship('EndorsementRequest', primaryjoin='Endorsement.request_id == EndorsementRequest.request_id', back_populates='endorsement') + + +class EndorsementsAudit(Endorsement): + __tablename__ = 'arXiv_endorsements_audit' + + endorsement_id: Mapped[int] = mapped_column(ForeignKey('arXiv_endorsements.endorsement_id'), primary_key=True, server_default=FetchedValue()) + session_id: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + remote_addr: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) + remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + tracking_cookie: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + flag_knows_personally: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + flag_seen_paper: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + comment: Mapped[Optional[str]] = mapped_column(Text) + + + +class FreezeLog(Base): + __tablename__ = 'arXiv_freeze_log' + + date: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) + + + +class GroupDef(Base): + __tablename__ = 'arXiv_group_def' + + archive_group: Mapped[str] = mapped_column(String(16), primary_key=True, server_default=FetchedValue()) + name: Mapped[Optional[str]] = mapped_column(String(255)) + + + +class Group(Base): + __tablename__ = 'arXiv_groups' + + group_id: Mapped[str] = mapped_column(String(16), primary_key=True, server_default=FetchedValue()) + group_name: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + start_year: Mapped[str] = mapped_column(String(4), nullable=False, server_default=FetchedValue()) + + + +t_arXiv_in_category = Table( + 'arXiv_in_category', metadata, + Column('document_id', ForeignKey('arXiv_documents.document_id'), nullable=False, index=True, server_default=FetchedValue()), + Column('archive', String(16), nullable=False, server_default=FetchedValue()), + Column('subject_class', String(16), nullable=False, server_default=FetchedValue()), + Column('is_primary', Integer, nullable=False, server_default=FetchedValue()), + ForeignKeyConstraint(['archive', 'subject_class'], ['arXiv_categories.archive', 'arXiv_categories.subject_class']), + Index('in_cat_archive', 'archive', 'subject_class', 'document_id'), + Index('arXiv_in_category_mp', 'archive', 'subject_class') +) + + +class JrefControl(Base): + __tablename__ = 'arXiv_jref_control' + __table_args__ = ( + Index('jref_ctrl_document_id', 'document_id', 'version'), + ) + + control_id: Mapped[intpk] + document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id'), nullable=False, server_default=FetchedValue()) + version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()) + status: Mapped[Literal['new', 'frozen', 'published', 'rejected']] = mapped_column(Enum('new', 'frozen', 'published', 'rejected'), nullable=False, index=True, server_default=FetchedValue()) + flag_must_notify: Mapped[Optional[Literal['0', '1']]] = mapped_column(Enum('0', '1'), server_default=FetchedValue()) + jref: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + request_date: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + freeze_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + publish_date: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + document = relationship('Document', primaryjoin='JrefControl.document_id == Document.document_id', backref='arXiv_jref_controls') + user = relationship('TapirUser', primaryjoin='JrefControl.user_id == TapirUser.user_id', back_populates='arXiv_jref_controls') + + + +class License(Base): + __tablename__ = 'arXiv_licenses' + + name: Mapped[str] = mapped_column(String(255), primary_key=True) + label: Mapped[Optional[str]] = mapped_column(String(255)) + active: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + note: Mapped[Optional[str]] = mapped_column(String(400)) + sequence: Mapped[Optional[int]] = mapped_column(Integer) + + + +class LogPosition(Base): + __tablename__ = 'arXiv_log_positions' + + id: Mapped[str] = mapped_column(String(255), primary_key=True, server_default=FetchedValue()) + position: Mapped[Optional[int]] + date: Mapped[Optional[int]] + + + +class Metadata(Base): + __tablename__ = 'arXiv_metadata' + __table_args__ = ( + Index('pidv', 'paper_id', 'version'), + ) + + metadata_id: Mapped[intpk] + document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id', ondelete='CASCADE', onupdate='CASCADE'), nullable=False, index=True, server_default=FetchedValue()) + paper_id: Mapped[str] = mapped_column(String(64), nullable=False) + created: Mapped[Optional[datetime]] + updated: Mapped[Optional[datetime]] + submitter_id: Mapped[Optional[int]] = mapped_column(ForeignKey('tapir_users.user_id'), index=True) + submitter_name: Mapped[str] = mapped_column(String(64), nullable=False) + submitter_email: Mapped[str] = mapped_column(String(64), nullable=False) + source_size: Mapped[Optional[int]] = mapped_column(Integer) + source_format: Mapped[Optional[Literal['tex', 'ps', 'html', 'pdf', 'withdrawn', 'pdftex', 'docx']]] = mapped_column(String(12)) + source_flags: Mapped[Optional[str]] = mapped_column(String(12)) + title: Mapped[Optional[str]] = mapped_column(Text) + authors: Mapped[Optional[str]] = mapped_column(Text) + abs_categories: Mapped[Optional[str]] = mapped_column(String(255)) + comments: Mapped[Optional[str]] = mapped_column(Text) + proxy: Mapped[Optional[str]] = mapped_column(String(255)) + report_num: Mapped[Optional[str]] = mapped_column(Text) + msc_class: Mapped[Optional[str]] = mapped_column(String(255)) + acm_class: Mapped[Optional[str]] = mapped_column(String(255)) + journal_ref: Mapped[Optional[str]] = mapped_column(Text) + doi: Mapped[Optional[str]] = mapped_column(String(255)) + abstract: Mapped[Optional[str]] = mapped_column(Text) + license: Mapped[Optional[str]] = mapped_column(ForeignKey('arXiv_licenses.name'), index=True) + version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + modtime: Mapped[Optional[int]] = mapped_column(Integer) + is_current: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + is_withdrawn: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + document = relationship('Document', primaryjoin='Metadata.document_id == Document.document_id', backref='arXiv_metadata') + # Link to the license + arXiv_license = relationship('License', primaryjoin='Metadata.license == License.name', backref='arXiv_metadata') + submitter = relationship('TapirUser', primaryjoin='Metadata.submitter_id == TapirUser.user_id', back_populates='arXiv_metadata') + + + +class MirrorList(Base): + __tablename__ = 'arXiv_mirror_list' + + mirror_list_id: Mapped[intpk] + created: Mapped[Optional[datetime]] + updated: Mapped[Optional[datetime]] + document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id'), nullable=False, index=True, server_default=FetchedValue()) + version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + write_source: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + write_abs: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + is_written: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + document = relationship('Document', primaryjoin='MirrorList.document_id == Document.document_id', backref='arXiv_mirror_lists') + + + +class ModeratorApiKey(Base): + __tablename__ = 'arXiv_moderator_api_key' + + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, nullable=False, server_default=FetchedValue()) + secret: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False, server_default=FetchedValue()) + valid: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + issued_when: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + issued_to: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) + remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + + user = relationship('TapirUser', primaryjoin='ModeratorApiKey.user_id == TapirUser.user_id', back_populates='arXiv_moderator_api_keys') + + + +t_arXiv_moderators = Table( + 'arXiv_moderators', metadata, + Column('user_id', ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()), + Column('archive', ForeignKey('arXiv_archive_group.archive_id'), nullable=False, server_default=FetchedValue()), + Column('subject_class', String(16), nullable=False, server_default=FetchedValue()), + Column('is_public', Integer, nullable=False, server_default=FetchedValue()), + Column('no_email', Integer, index=True, server_default=FetchedValue()), + Column('no_web_email', Integer, index=True, server_default=FetchedValue()), + Column('no_reply_to', Integer, index=True, server_default=FetchedValue()), + Column('daily_update', Integer, server_default=FetchedValue()), + ForeignKeyConstraint(['archive', 'subject_class'], ['arXiv_categories.archive', 'arXiv_categories.subject_class']), + Index('mod_user_id', 'archive', 'subject_class', 'user_id') +) + + +class MonitorKlog(Base): + __tablename__ = 'arXiv_monitor_klog' + + t: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) + sent: Mapped[Optional[int]] = mapped_column(Integer) + + + +class MonitorMailq(Base): + __tablename__ = 'arXiv_monitor_mailq' + + t: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) + main_q: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + local_q: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + local_host_map: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + local_timeout: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + local_refused: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + local_in_flight: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + + +class MonitorMailsent(Base): + __tablename__ = 'arXiv_monitor_mailsent' + + t: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) + sent: Mapped[Optional[int]] = mapped_column(Integer) + + + +class NextMail(Base): + __tablename__ = 'arXiv_next_mail' + __table_args__ = ( + Index('arXiv_next_mail_idx_document_id_version', 'document_id', 'version'), + ) + + next_mail_id: Mapped[intpk] + submission_id: Mapped[int] = mapped_column(Integer, nullable=False) + document_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + paper_id: Mapped[Optional[str]] = mapped_column(String(20)) + version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + type: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + extra: Mapped[Optional[str]] = mapped_column(String(255)) + mail_id: Mapped[Optional[str]] = mapped_column(String(6)) + is_written: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + + +class OrcidConfig(Base): + __tablename__ = 'arXiv_orcid_config' + + domain: Mapped[str] = mapped_column(String(75), primary_key=True, nullable=False) + keyname: Mapped[str] = mapped_column(String(60), primary_key=True, nullable=False) + value: Mapped[Optional[str]] = mapped_column(String(150)) + + +t_arXiv_ownership_requests_papers = Table( + 'arXiv_ownership_requests_papers', metadata, + Column('request_id', ForeignKey('arXiv_ownership_requests.request_id'), nullable=False, server_default=FetchedValue()), + Column('document_id', ForeignKey('arXiv_documents.document_id'), nullable=False, index=True, server_default=FetchedValue()), + Index('request_id', 'request_id', 'document_id', unique=True) +) + +class OwnershipRequest(Base): + __tablename__ = 'arXiv_ownership_requests' + + request_id: Mapped[intpk] + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()) + endorsement_request_id: Mapped[Optional[int]] = mapped_column(ForeignKey('arXiv_endorsement_requests.request_id'), index=True) + workflow_status: Mapped[Literal['pending', 'accepted', 'rejected']] = mapped_column(Enum('pending', 'accepted', 'rejected'), nullable=False, server_default=FetchedValue()) + + request_audit = relationship('OwnershipRequestsAudit', back_populates='ownership_request', uselist=False) + endorsement_request = relationship('EndorsementRequest', primaryjoin='OwnershipRequest.endorsement_request_id == EndorsementRequest.request_id', backref='arXiv_ownership_requests') + user = relationship('TapirUser', primaryjoin='OwnershipRequest.user_id == TapirUser.user_id', back_populates='arXiv_ownership_requests') + documents = relationship("Document", secondary=t_arXiv_ownership_requests_papers) + +class OwnershipRequestsAudit(Base): + __tablename__ = 'arXiv_ownership_requests_audit' + + request_id: Mapped[int] = mapped_column(ForeignKey('arXiv_ownership_requests.request_id'), primary_key=True, server_default=FetchedValue()) + session_id: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + remote_addr: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) + remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + tracking_cookie: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + date: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + ownership_request = relationship('OwnershipRequest', primaryjoin='OwnershipRequestsAudit.request_id == OwnershipRequest.request_id', back_populates='request_audit', uselist=False) + + +class PaperOwner(Base): + __tablename__ = 'arXiv_paper_owners' + __table_args__ = ( + ForeignKeyConstraint(['added_by'], ['tapir_users.user_id'], name='0_595'), + ForeignKeyConstraint(['document_id'], ['arXiv_documents.document_id'], name='0_593'), + ForeignKeyConstraint(['user_id'], ['tapir_users.user_id'], name='0_594'), + Index('added_by', 'added_by'), + # Index('document_id', 'document_id', 'user_id', unique=True), + # Index('user_id', 'user_id'), + ) + + document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id'), primary_key=True) + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True) + date: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + added_by: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + remote_addr: Mapped[str] = mapped_column(String(16), nullable=False, server_default=text("''")) + remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=text("''")) + tracking_cookie: Mapped[str] = mapped_column(String(32), nullable=False, server_default=text("''")) + valid: Mapped[int] = mapped_column(SmallInteger, nullable=False, server_default=text("'0'")) + flag_author: Mapped[int] = mapped_column(SmallInteger, nullable=False, server_default=text("'0'")) + flag_auto: Mapped[int] = mapped_column(SmallInteger, nullable=False, server_default=text("'1'")) + + document = relationship('Document', back_populates='owners') + owner = relationship('TapirUser', foreign_keys="[PaperOwner.user_id]", back_populates='owned_papers') + + +class PaperSession(Base): + __tablename__ = 'arXiv_paper_sessions' + + paper_session_id: Mapped[intpk] + paper_id: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) + start_time: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + end_time: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + ip_name: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) + + + +class PilotFile(Base): + """arXiv_pilot is deprecated""" + __tablename__ = 'arXiv_pilot_files' + + file_id: Mapped[intpk] + submission_id: Mapped[int] = mapped_column(ForeignKey('arXiv_submissions.submission_id'), nullable=False, index=True) + filename: Mapped[Optional[str]] = mapped_column(String(256), server_default=FetchedValue()) + entity_url: Mapped[Optional[str]] = mapped_column(String(256)) + description: Mapped[Optional[str]] = mapped_column(String(80)) + byRef: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + + submission = relationship('Submission', primaryjoin='PilotFile.submission_id == Submission.submission_id', backref='arXiv_pilot_files') + + + +class PublishLog(Base): + __tablename__ = 'arXiv_publish_log' + + date: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) + + + +t_arXiv_refresh_list = Table( + 'arXiv_refresh_list', metadata, + Column('filename', String(255)), + Column('mtime', Integer, index=True) +) + + +class RejectSessionUsername(Base): + __tablename__ = 'arXiv_reject_session_usernames' + + username: Mapped[str] = mapped_column(String(64), primary_key=True, server_default=FetchedValue()) + + + +class SciencewisePing(Base): + __tablename__ = 'arXiv_sciencewise_pings' + + paper_id_v: Mapped[str] = mapped_column(String(32), primary_key=True) + updated: Mapped[Optional[datetime]] + + + +class ShowEmailRequest(Base): + __tablename__ = 'arXiv_show_email_requests' + __table_args__ = ( + Index('email_reqs_user_id', 'user_id', 'dated'), + ) + + document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id'), nullable=False, index=True, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, server_default=FetchedValue()) + session_id: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + dated: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + flag_allowed: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + remote_addr: Mapped[str] = mapped_column(String(16), nullable=False, index=True, server_default=FetchedValue()) + remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + tracking_cookie: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + request_id: Mapped[intpk] + + document = relationship('Document', primaryjoin='ShowEmailRequest.document_id == Document.document_id', backref='arXiv_show_email_requests') + user = relationship('TapirUser', primaryjoin='ShowEmailRequest.user_id == TapirUser.user_id', back_populates='arXiv_show_email_requests') + + + +class State(Base): + __tablename__ = 'arXiv_state' + + id: Mapped[intpk] + name: Mapped[Optional[str]] = mapped_column(String(24)) + value: Mapped[Optional[str]] = mapped_column(String(24)) + + + +t_arXiv_stats_hourly = Table( + 'arXiv_stats_hourly', metadata, + Column('ymd', Date, nullable=False, index=True), + Column('hour', Integer, nullable=False, index=True), + Column('node_num', Integer, nullable=False, index=True), + Column('access_type', String(1), nullable=False, index=True), + Column('connections', Integer, nullable=False) +) + + +class StatsMonthlyDownload(Base): + __tablename__ = 'arXiv_stats_monthly_downloads' + + ym: Mapped[date] = mapped_column(Date, primary_key=True) + downloads: Mapped[int] = mapped_column(Integer, nullable=False) + + + +class StatsMonthlySubmission(Base): + __tablename__ = 'arXiv_stats_monthly_submissions' + + ym: Mapped[date] = mapped_column(Date, primary_key=True, server_default=FetchedValue()) + num_submissions: Mapped[int] = mapped_column(SmallInteger, nullable=False) + historical_delta: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + + +class SubmissionAgreement(Base): + __tablename__ = 'arXiv_submission_agreements' + + agreement_id: Mapped[int] = mapped_column(SmallInteger, primary_key=True) + effective_date: Mapped[Optional[datetime]] = mapped_column(DateTime, server_default=FetchedValue()) + commit_ref: Mapped[str] = mapped_column(String(255), nullable=False) + content: Mapped[Optional[str]] = mapped_column(Text) + + + +class SubmissionCategory(Base): + __tablename__ = 'arXiv_submission_category' + + submission_id: Mapped[int] = mapped_column(ForeignKey('arXiv_submissions.submission_id', ondelete='CASCADE', onupdate='CASCADE'), primary_key=True, nullable=False, index=True) + category: Mapped[str] = mapped_column(ForeignKey('arXiv_category_def.category'), primary_key=True, nullable=False, index=True, server_default=FetchedValue()) + is_primary: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + is_published: Mapped[Optional[int]] = mapped_column(Integer, index=True, server_default=FetchedValue()) + + arXiv_category_def = relationship('CategoryDef', primaryjoin='SubmissionCategory.category == CategoryDef.category', backref='arXiv_submission_categories') + submission = relationship('Submission', primaryjoin='SubmissionCategory.submission_id == Submission.submission_id', backref='arXiv_submission_categories') + + + +class SubmissionCategoryProposal(Base): + __tablename__ = 'arXiv_submission_category_proposal' + + proposal_id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, index=True) + submission_id: Mapped[int] = mapped_column(ForeignKey('arXiv_submissions.submission_id', ondelete='CASCADE', onupdate='CASCADE'), primary_key=True, nullable=False, index=True) + category: Mapped[str] = mapped_column(ForeignKey('arXiv_category_def.category'), primary_key=True, nullable=False, index=True) + is_primary: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, index=True, server_default=FetchedValue()) + proposal_status: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, index=True) + updated: Mapped[Optional[datetime]] + proposal_comment_id: Mapped[Optional[int]] = mapped_column(ForeignKey('arXiv_admin_log.id'), index=True) + response_comment_id: Mapped[Optional[int]] = mapped_column(ForeignKey('arXiv_admin_log.id'), index=True) + + arXiv_category_def = relationship('CategoryDef', primaryjoin='SubmissionCategoryProposal.category == CategoryDef.category', backref='arXiv_submission_category_proposals') + proposal_comment = relationship('AdminLog', primaryjoin='SubmissionCategoryProposal.proposal_comment_id == AdminLog.id', backref='arxivadminlog_arXiv_submission_category_proposals') + response_comment = relationship('AdminLog', primaryjoin='SubmissionCategoryProposal.response_comment_id == AdminLog.id', backref='arxivadminlog_arXiv_submission_category_proposals_0') + submission = relationship('Submission', primaryjoin='SubmissionCategoryProposal.submission_id == Submission.submission_id', backref='arXiv_submission_category_proposals') + user = relationship('TapirUser', primaryjoin='SubmissionCategoryProposal.user_id == TapirUser.user_id', back_populates='arXiv_submission_category_proposal') + + + +class SubmissionControl(Base): + __tablename__ = 'arXiv_submission_control' + __table_args__ = ( + Index('sub_ctrl_document_id', 'document_id', 'version'), + ) + + control_id: Mapped[intpk] + document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id'), nullable=False, server_default=FetchedValue()) + version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + pending_paper_id: Mapped[str] = mapped_column(String(20), nullable=False, index=True, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()) + status: Mapped[Literal['new', 'frozen', 'published', 'rejected']] = mapped_column(Enum('new', 'frozen', 'published', 'rejected'), nullable=False, index=True, server_default=FetchedValue()) + flag_must_notify: Mapped[Optional[Literal['0', '1']]] = mapped_column(Enum('0', '1'), server_default=FetchedValue()) + request_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + freeze_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + publish_date: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + document = relationship('Document', primaryjoin='SubmissionControl.document_id == Document.document_id', backref='arXiv_submission_controls') + user = relationship('TapirUser', primaryjoin='SubmissionControl.user_id == TapirUser.user_id', back_populates='arXiv_submission_control') + + + +class SubmissionFlag(Base): + __tablename__ = 'arXiv_submission_flag' + __table_args__ = ( + Index('uniq_one_flag_per_mod', 'submission_id', 'user_id'), + ) + + flag_id: Mapped[intpk] + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id', ondelete='CASCADE'), nullable=False, index=True, server_default=FetchedValue()) + submission_id: Mapped[int] = mapped_column(ForeignKey('arXiv_submissions.submission_id', ondelete='CASCADE'), nullable=False) + flag: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + updated: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) + + submission = relationship('Submission', primaryjoin='SubmissionFlag.submission_id == Submission.submission_id', backref='arXiv_submission_flags') + user = relationship('TapirUser', primaryjoin='SubmissionFlag.user_id == TapirUser.user_id', back_populates='arXiv_submission_flag') + + + +class SubmissionHoldReason(Base): + __tablename__ = 'arXiv_submission_hold_reason' + + reason_id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False) + submission_id: Mapped[int] = mapped_column(ForeignKey('arXiv_submissions.submission_id', ondelete='CASCADE'), nullable=False, index=True) + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id', ondelete='CASCADE'), primary_key=True, nullable=False, index=True) + reason: Mapped[Optional[str]] = mapped_column(String(30)) + type: Mapped[Optional[str]] = mapped_column(String(30)) + comment_id: Mapped[Optional[int]] = mapped_column(ForeignKey('arXiv_admin_log.id'), index=True) + + comment = relationship('AdminLog', primaryjoin='SubmissionHoldReason.comment_id == AdminLog.id', backref='arXiv_submission_hold_reasons') + submission = relationship('Submission', primaryjoin='SubmissionHoldReason.submission_id == Submission.submission_id', backref='arXiv_submission_hold_reasons') + user = relationship('TapirUser', primaryjoin='SubmissionHoldReason.user_id == TapirUser.user_id', back_populates='arXiv_submission_hold_reason') + + + +class SubmissionNearDuplicate(Base): + __tablename__ = 'arXiv_submission_near_duplicates' + __table_args__ = ( + Index('match', 'submission_id', 'matching_id'), + ) + + submission_id: Mapped[int] = mapped_column(ForeignKey('arXiv_submissions.submission_id', ondelete='CASCADE'), primary_key=True, nullable=False, server_default=FetchedValue()) + matching_id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, server_default=FetchedValue()) + similarity: Mapped[float] = mapped_column(Numeric(2, 1), nullable=False) + last_update: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) + + submission = relationship('Submission', primaryjoin='SubmissionNearDuplicate.submission_id == Submission.submission_id', backref='arXiv_submission_near_duplicates') + + + +class SubmissionQaReport(Base): + __tablename__ = 'arXiv_submission_qa_reports' + + id: Mapped[intpk] + submission_id: Mapped[int] = mapped_column(ForeignKey('arXiv_submissions.submission_id'), nullable=False, index=True) + report_key_name: Mapped[str] = mapped_column(String(64), nullable=False, index=True) + created: Mapped[Optional[datetime]] = mapped_column(DateTime, server_default=FetchedValue()) + num_flags: Mapped[int] = mapped_column(SmallInteger, nullable=False, server_default=FetchedValue()) + report: Mapped[dict[str, Any]] = mapped_column(JSON, nullable=False) + report_uri: Mapped[Optional[str]] = mapped_column(String(256)) + + submission = relationship('Submission', primaryjoin='SubmissionQaReport.submission_id == Submission.submission_id', backref='arXiv_submission_qa_reports') + + + +class SubmissionViewFlag(Base): + __tablename__ = 'arXiv_submission_view_flag' + + submission_id: Mapped[int] = mapped_column(ForeignKey('arXiv_submissions.submission_id', ondelete='CASCADE'), primary_key=True, nullable=False) + flag: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id', ondelete='CASCADE'), primary_key=True, nullable=False, index=True) + updated: Mapped[Optional[datetime]] + + submission = relationship('Submission', primaryjoin='SubmissionViewFlag.submission_id == Submission.submission_id', backref='arXiv_submission_view_flags') + user = relationship('TapirUser', primaryjoin='SubmissionViewFlag.user_id == TapirUser.user_id', back_populates='arXiv_submission_view_flag') + + + +class Submission(Base): + __tablename__ = 'arXiv_submissions' + + submission_id: Mapped[intpk] + document_id: Mapped[Optional[int]] = mapped_column(ForeignKey('arXiv_documents.document_id', ondelete='CASCADE', onupdate='CASCADE'), index=True) + doc_paper_id: Mapped[Optional[str]] = mapped_column(String(20), index=True) + sword_id: Mapped[Optional[int]] = mapped_column(ForeignKey('arXiv_tracking.sword_id'), index=True) + userinfo: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + is_author: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + agree_policy: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + viewed: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + stage: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + submitter_id: Mapped[Optional[int]] = mapped_column(ForeignKey('tapir_users.user_id', ondelete='CASCADE', onupdate='CASCADE'), index=True) + submitter_name: Mapped[Optional[str]] = mapped_column(String(64)) + submitter_email: Mapped[Optional[str]] = mapped_column(String(64)) + created: Mapped[Optional[datetime]] + updated: Mapped[Optional[datetime]] + status: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + sticky_status: Mapped[Optional[int]] = mapped_column(Integer) + must_process: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + submit_time: Mapped[Optional[datetime]] + release_time: Mapped[Optional[datetime]] + source_size: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + source_format: Mapped[Optional[str]] = mapped_column(String(12)) + source_flags: Mapped[Optional[str]] = mapped_column(String(12)) + has_pilot_data: Mapped[Optional[int]] = mapped_column(Integer) + is_withdrawn: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + title: Mapped[Optional[str]] = mapped_column(Text) + authors: Mapped[Optional[str]] = mapped_column(Text) + comments: Mapped[Optional[str]] = mapped_column(Text) + proxy: Mapped[Optional[str]] = mapped_column(VARCHAR(255, charset="latin1")) + report_num: Mapped[Optional[str]] = mapped_column(Text) + msc_class: Mapped[Optional[str]] = mapped_column(String(255)) + acm_class: Mapped[Optional[str]] = mapped_column(String(255)) + journal_ref: Mapped[Optional[str]] = mapped_column(Text) + doi: Mapped[Optional[str]] = mapped_column(String(255)) + abstract: Mapped[Optional[str]] = mapped_column(Text) + license: Mapped[Optional[str]] = mapped_column(ForeignKey('arXiv_licenses.name', onupdate='CASCADE'), index=True) + version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) + type: Mapped[Optional[str]] = mapped_column(String(8), index=True) + is_ok: Mapped[Optional[int]] = mapped_column(Integer, index=True) + admin_ok: Mapped[Optional[int]] = mapped_column(Integer) + allow_tex_produced: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + is_oversize: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + remote_addr: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) + remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + package: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + rt_ticket_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) + auto_hold: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + is_locked: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + agreement_id = mapped_column(ForeignKey('arXiv_submission_agreements.agreement_id'), index=True) + + agreement = relationship('SubmissionAgreement', primaryjoin='Submission.agreement_id == SubmissionAgreement.agreement_id', backref='arXiv_submissions') + document = relationship('Document', primaryjoin='Submission.document_id == Document.document_id', backref='arXiv_submissions') + arXiv_license = relationship('License', primaryjoin='Submission.license == License.name', backref='arXiv_submissions') + submitter = relationship('TapirUser', primaryjoin='Submission.submitter_id == TapirUser.user_id', back_populates='arXiv_submissions') + sword = relationship('Tracking', primaryjoin='Submission.sword_id == Tracking.sword_id', backref='arXiv_submissions') + + # to arxiv check + arXiv_check_results: Mapped[List["CheckResults"]] = relationship("CheckResults", back_populates="submission") + # to submission locks + arXiv_submission_locks: Mapped[List["SubmissionLocks"]] = relationship("SubmissionLocks", back_populates="submission") + + +class PilotDataset(Submission): + """arXiv_pilot is deprecated""" + __tablename__ = 'arXiv_pilot_datasets' + + submission_id: Mapped[int] = mapped_column(ForeignKey('arXiv_submissions.submission_id'), primary_key=True) + numfiles: Mapped[Optional[int]] = mapped_column(SmallInteger, server_default=FetchedValue()) + feed_url: Mapped[Optional[str]] = mapped_column(String(256)) + manifestation: Mapped[Optional[str]] = mapped_column(String(256)) + published: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + # created: Mapped[datetime] = mapped_column(DateTime, nullable=False) + # ^This column is inherited + last_checked: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) + + +class SubmissionAbsClassifierDatum(Base): + __tablename__ = 'arXiv_submission_abs_classifier_data' + + submission_id: Mapped[int] = mapped_column(ForeignKey('arXiv_submissions.submission_id', ondelete='CASCADE'), primary_key=True, server_default=FetchedValue()) + json: Mapped[Optional[str]] = mapped_column(Text) + last_update: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) + status: Mapped[Optional[Literal['processing', 'success', 'failed', 'no connection']]] = mapped_column(Enum('processing', 'success', 'failed', 'no connection')) + message: Mapped[Optional[str]] = mapped_column(Text) + is_oversize: Mapped[Optional[int]] = mapped_column(Integer) + suggested_primary: Mapped[Optional[str]] = mapped_column(Text) + suggested_reason: Mapped[Optional[str]] = mapped_column(Text) + autoproposal_primary: Mapped[Optional[str]] = mapped_column(Text) + autoproposal_reason: Mapped[Optional[str]] = mapped_column(Text) + classifier_service_version: Mapped[Optional[str]] = mapped_column(Text) + classifier_model_version: Mapped[Optional[str]] = mapped_column(Text) + + +class SubmissionClassifierDatum(Base): + __tablename__ = 'arXiv_submission_classifier_data' + + submission_id: Mapped[int] = mapped_column(ForeignKey('arXiv_submissions.submission_id', ondelete='CASCADE'), primary_key=True, server_default=FetchedValue()) + json: Mapped[Optional[str]] = mapped_column(Text) + last_update: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) + status: Mapped[Optional[Literal['processing', 'success', 'failed', 'no connection']]] = mapped_column(Enum('processing', 'success', 'failed', 'no connection')) + message: Mapped[Optional[str]] = mapped_column(Text) + is_oversize: Mapped[Optional[int]] = mapped_column(Integer) + + +class SubmitterFlag(Base): + __tablename__ = 'arXiv_submitter_flags' + + flag_id: Mapped[intpk] + comment: Mapped[Optional[str]] = mapped_column(String(255)) + pattern: Mapped[Optional[str]] = mapped_column(String(255)) + + + +class SuspectEmail(Base): + __tablename__ = 'arXiv_suspect_emails' + + id: Mapped[intpk] + type: Mapped[str] = mapped_column(String(10), nullable=False) + pattern: Mapped[str] = mapped_column(Text, nullable=False) + comment: Mapped[str] = mapped_column(Text, nullable=False) + updated: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) + + + +class Title(Base): + __tablename__ = 'arXiv_titles' + + paper_id: Mapped[str] = mapped_column(String(64), primary_key=True) + title: Mapped[Optional[str]] = mapped_column(String(255), index=True) + report_num: Mapped[Optional[str]] = mapped_column(String(255), index=True) + date: Mapped[Optional[dt.date]] = mapped_column(Date) + + + +class TopPaper(Base): + __tablename__ = 'arXiv_top_papers' + + from_week: Mapped[date] = mapped_column(Date, primary_key=True, nullable=False, server_default=FetchedValue()) + _class: Mapped[str] = mapped_column('class', String(1), primary_key=True, nullable=False, server_default=FetchedValue()) + rank: Mapped[int] = mapped_column(SmallInteger, primary_key=True, nullable=False, server_default=FetchedValue()) + document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id'), nullable=False, index=True, server_default=FetchedValue()) + viewers: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + document = relationship('Document', primaryjoin='TopPaper.document_id == Document.document_id', backref='arXiv_top_papers') + + + +class TrackbackPing(Base): + __tablename__ = 'arXiv_trackback_pings' + + trackback_id: Mapped[intpk] + document_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) + title: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + excerpt: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + url: Mapped[str] = mapped_column(String(255), nullable=False, index=True, server_default=FetchedValue()) + blog_name: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + remote_addr: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) + posted_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + is_stale: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + approved_by_user: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + approved_time: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + status: Mapped[Literal['pending', 'pending2', 'accepted', 'rejected', 'spam']] = mapped_column(Enum('pending', 'pending2', 'accepted', 'rejected', 'spam'), nullable=False, index=True, server_default=FetchedValue()) + site_id: Mapped[Optional[int]] = mapped_column(Integer) + + @property + def posted_datetime(self) -> DateTime: + """Get posted_date as UTC datetime.""" + dt = datetime.fromtimestamp(self.posted_date, tz=tz) + return dt.astimezone(tz=tzutc()) + + @property + def display_url(self) -> str: + """Get the URL without the protocol, for display.""" + return str(re.sub(r"^[a-z]+:\/\/", "", self.url.strip(), flags=re.IGNORECASE,)) + + @property + def has_valid_url(self) -> bool: + """Determine whether the trackback URL is valid.""" + return bool(is_valid_url(self.url, public=False)) + + # TODO: Make settings for base so we can import them like everyone else does + # Then I'll include the trackback secret + @property + def hashed_document_id(self) -> str: + """Get the hashed document_id.""" + s = f"{self.document_id}{self.trackback_id}{tb_secret}" + return hashlib.md5(s.encode()).hexdigest()[0:9] + +class TrackbackSite(Base): + __tablename__ = 'arXiv_trackback_sites' + + pattern: Mapped[str] = mapped_column(String(255), nullable=False, index=True, server_default=FetchedValue()) + site_id: Mapped[intpk] + action: Mapped[Literal['neutral', 'accept', 'reject', 'spam']] = mapped_column(Enum('neutral', 'accept', 'reject', 'spam'), nullable=False, server_default=FetchedValue()) + + + +class Tracking(Base): + __tablename__ = 'arXiv_tracking' + + tracking_id: Mapped[intpk] + sword_id: Mapped[int] = mapped_column(Integer, nullable=False, unique=True, server_default=FetchedValue()) + paper_id: Mapped[str] = mapped_column(String(32), nullable=False) + submission_errors: Mapped[Optional[str]] = mapped_column(Text) + timestamp: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) + + + +class Updates(Base): + __tablename__ = "arXiv_updates" + __table_args__ = (PrimaryKeyConstraint('document_id', 'date', 'action', 'category'),) + + # primary key is foregn key + document_id: Mapped[Optional[int]] = mapped_column( + ForeignKey("arXiv_documents.document_id", ondelete="CASCADE", onupdate="CASCADE"), + index=True, + server_default=text("'0'"), + ) + version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) + date: Mapped[Optional[dt.date]] = mapped_column(Date, index=True) + action: Mapped[Optional[Literal['new', 'replace', 'absonly', 'cross', 'repcro']]] = mapped_column(Enum('new', 'replace', 'absonly', 'cross', 'repcro')) + archive: Mapped[Optional[str]] = mapped_column(String(20), index=True) + category: Mapped[Optional[int]] = mapped_column(String(20), index=True) + + def __repr__(self) -> str: + return f"Update(document_id={self.document_id}, version={self.version}, action={self.action}, date={self.date}, category={self.category}, archive={self.archive})" + + +t_arXiv_updates_tmp = Table( + 'arXiv_updates_tmp', metadata, + Column('document_id', Integer), + Column('date', Date), + Column('action', Enum('new', 'replace', 'absonly', 'cross', 'repcro')), + Column('category', String(20)), + Index('updates_temp_document_id', 'document_id', 'date', 'action', 'category') +) + + +class Version(Base): + __tablename__ = 'arXiv_versions' + + document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id'), primary_key=True, nullable=False, server_default=FetchedValue()) + version: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, server_default=FetchedValue()) + request_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + freeze_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + publish_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + flag_current: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + document = relationship('Document', primaryjoin='Version.document_id == Document.document_id', backref='arXiv_versions') + + +class VersionsChecksum(Version): + __tablename__ = 'arXiv_versions_checksum' + __table_args__ = ( + ForeignKeyConstraint(['document_id', 'version'], ['arXiv_versions.document_id', 'arXiv_versions.version']), + ) + + document_id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, server_default=FetchedValue()) + version: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, server_default=FetchedValue()) + flag_abs_present: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + abs_size: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + abs_md5sum: Mapped[Optional[str]] = mapped_column(BINARY(16), index=True) + flag_src_present: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + src_size: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + src_md5sum: Mapped[Optional[str]] = mapped_column(BINARY(16), index=True) + + + +t_arXiv_white_email = Table( + 'arXiv_white_email', metadata, + Column('pattern', String(64), unique=True) +) + + + +t_arXiv_xml_notifications = Table( + 'arXiv_xml_notifications', metadata, + Column('control_id', Integer, index=True), + Column('type', Enum('submission', 'cross', 'jref')), + Column('queued_date', Integer, nullable=False, server_default=FetchedValue()), + Column('sent_date', Integer, nullable=False, server_default=FetchedValue()), + Column('status', Enum('unsent', 'sent', 'failed'), index=True) +) + + + +class DbixClassSchemaVersion(Base): + __tablename__ = 'dbix_class_schema_versions' + + version: Mapped[str] = mapped_column(String(10), primary_key=True) + installed: Mapped[str] = mapped_column(String(20), nullable=False) + + + +t_demographics_backup = Table( + 'demographics_backup', metadata, + Column('user_id', Integer, nullable=False, server_default=FetchedValue()), + Column('country', String(2), nullable=False, server_default=FetchedValue()), + Column('affiliation', String(255), nullable=False, server_default=FetchedValue()), + Column('url', String(255), nullable=False, server_default=FetchedValue()), + Column('type', SmallInteger), + Column('os', SmallInteger), + Column('archive', String(16)), + Column('subject_class', String(16)), + Column('original_subject_classes', String(255), nullable=False, server_default=FetchedValue()), + Column('flag_group_physics', Integer), + Column('flag_group_math', Integer, nullable=False, server_default=FetchedValue()), + Column('flag_group_cs', Integer, nullable=False, server_default=FetchedValue()), + Column('flag_group_nlin', Integer, nullable=False, server_default=FetchedValue()), + Column('flag_proxy', Integer, nullable=False, server_default=FetchedValue()), + Column('flag_journal', Integer, nullable=False, server_default=FetchedValue()), + Column('flag_xml', Integer, nullable=False, server_default=FetchedValue()), + Column('dirty', Integer, nullable=False, server_default=FetchedValue()), + Column('flag_group_test', Integer, nullable=False, server_default=FetchedValue()), + Column('flag_suspect', Integer, nullable=False, server_default=FetchedValue()), + Column('flag_group_q_bio', Integer, nullable=False, server_default=FetchedValue()), + Column('flag_no_upload', Integer, nullable=False, server_default=FetchedValue()), + Column('flag_no_endorse', Integer, nullable=False, server_default=FetchedValue()), + Column('veto_status', Enum('ok', 'no-endorse', 'no-upload'), server_default=FetchedValue()) +) + + +class Session(Base): + __tablename__ = 'sessions' + + id: Mapped[str] = mapped_column(String(72), primary_key=True) + session_data: Mapped[Optional[str]] = mapped_column(Text) + expires: Mapped[Optional[int]] = mapped_column(Integer) + + + +class TapirAddress(Base): + __tablename__ = 'tapir_address' + + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, nullable=False, server_default=FetchedValue()) + address_type: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, index=True, server_default=FetchedValue()) + company: Mapped[str] = mapped_column(String(80), nullable=False, server_default=FetchedValue()) + line1: Mapped[str] = mapped_column(String(80), nullable=False, server_default=FetchedValue()) + line2: Mapped[str] = mapped_column(String(80), nullable=False, server_default=FetchedValue()) + city: Mapped[str] = mapped_column(String(50), nullable=False, index=True, server_default=FetchedValue()) + state: Mapped[str] = mapped_column(String(50), nullable=False, server_default=FetchedValue()) + postal_code: Mapped[str] = mapped_column(String(16), nullable=False, index=True, server_default=FetchedValue()) + country: Mapped[str] = mapped_column(ForeignKey('tapir_countries.digraph'), nullable=False, index=True, server_default=FetchedValue()) + share_addr: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + tapir_country = relationship('TapirCountry', primaryjoin='TapirAddress.country == TapirCountry.digraph', backref='tapir_address') + user = relationship('TapirUser', primaryjoin='TapirAddress.user_id == TapirUser.user_id', back_populates='tapir_address') + + + +class TapirAdminAudit(Base): + __tablename__ = 'tapir_admin_audit' + + log_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + session_id: Mapped[Optional[int]] = mapped_column(ForeignKey('tapir_sessions.session_id'), index=True) + ip_addr: Mapped[str] = mapped_column(String(16), nullable=False, index=True, server_default=FetchedValue()) + remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + admin_user: Mapped[Optional[int]] = mapped_column(ForeignKey('tapir_users.user_id'), index=True) + affected_user: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()) + tracking_cookie: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + action: Mapped[str] = mapped_column(String(32), nullable=False, server_default=FetchedValue()) + data: Mapped[str] = mapped_column(String(255), nullable=False, index=True) + comment: Mapped[str] = mapped_column(Text, nullable=False) + entry_id: Mapped[intpk] + + tapir_users = relationship('TapirUser', foreign_keys=[admin_user], back_populates='tapir_admin_audit') + tapir_users_ = relationship('TapirUser', foreign_keys=[affected_user], back_populates='tapir_admin_audit_') + session = relationship('TapirSession', primaryjoin='TapirAdminAudit.session_id == TapirSession.session_id', backref='tapir_admin_audits') + + + +class TapirCountry(Base): + __tablename__ = 'tapir_countries' + + digraph: Mapped[str] = mapped_column(String(2), primary_key=True, server_default=FetchedValue()) + country_name: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + rank: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + +class TapirEmailChangeToken(Base): + __tablename__ = 'tapir_email_change_tokens' + + user_id = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, nullable=False, server_default=FetchedValue()) + old_email: Mapped[Optional[str]] = mapped_column(String(255)) + new_email: Mapped[Optional[str]] = mapped_column(String(255)) + secret: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False, index=True, server_default=FetchedValue()) + tapir_dest: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + issued_when: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + issued_to: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) + remote_host: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) + tracking_cookie: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + used: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + session_id: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + consumed_when: Mapped[Optional[int]] = mapped_column(Integer) + consumed_from: Mapped[Optional[str]] = mapped_column(String(16)) + + user = relationship('TapirUser', primaryjoin='TapirEmailChangeToken.user_id == TapirUser.user_id', back_populates='tapir_email_change_tokens') + + +t_tapir_email_change_tokens_used = Table( + 'tapir_email_change_tokens_used', metadata, + Column('user_id', ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()), + Column('secret', String(32), nullable=False, server_default=FetchedValue()), + Column('used_when', Integer, nullable=False, server_default=FetchedValue()), + Column('used_from', String(16), nullable=False, server_default=FetchedValue()), + Column('remote_host', String(255), nullable=False, server_default=FetchedValue()), + Column('session_id', ForeignKey('tapir_sessions.session_id'), nullable=False, index=True, server_default=FetchedValue()) +) + + +class TapirEmailHeader(Base): + __tablename__ = 'tapir_email_headers' + + template_id: Mapped[int] = mapped_column(ForeignKey('tapir_email_templates.template_id'), primary_key=True, nullable=False, server_default=FetchedValue()) + header_name: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False, server_default=FetchedValue()) + header_content: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + + template = relationship('TapirEmailTemplate', primaryjoin='TapirEmailHeader.template_id == TapirEmailTemplate.template_id', backref='tapir_email_headers') + + + +class TapirEmailLog(Base): + __tablename__ = 'tapir_email_log' + + mail_id: Mapped[intpk] + reference_type: Mapped[Optional[str]] = mapped_column(String(1)) + reference_id: Mapped[Optional[int]] = mapped_column(Integer) + sent_date: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + email: Mapped[Optional[str]] = mapped_column(String(255)) + flag_bounced: Mapped[Optional[int]] = mapped_column(Integer) + mailing_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) + template_id: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + + +class TapirEmailMailing(Base): + __tablename__ = 'tapir_email_mailings' + + mailing_id: Mapped[intpk] + template_id: Mapped[Optional[int]] = mapped_column(ForeignKey('tapir_email_templates.template_id'), index=True) + created_by: Mapped[Optional[int]] = mapped_column(ForeignKey('tapir_users.user_id'), index=True) + sent_by: Mapped[Optional[int]] = mapped_column(ForeignKey('tapir_users.user_id'), index=True) + created_date: Mapped[Optional[int]] = mapped_column(Integer) + sent_date: Mapped[Optional[int]] = mapped_column(Integer) + complete_date: Mapped[Optional[int]] = mapped_column(Integer) + mailing_name: Mapped[Optional[str]] = mapped_column(String(255)) + comment: Mapped[Optional[str]] = mapped_column(Text) + + tapir_users = relationship('TapirUser', foreign_keys=[created_by], back_populates='tapir_email_mailings') + tapir_users_ = relationship('TapirUser', foreign_keys=[sent_by], back_populates='tapir_email_mailings_') + template = relationship('TapirEmailTemplate', primaryjoin='TapirEmailMailing.template_id == TapirEmailTemplate.template_id', backref='tapir_email_mailings') + + + +class TapirEmailTemplate(Base): + __tablename__ = 'tapir_email_templates' + __table_args__ = ( + Index('short_name', 'short_name', 'lang'), + ) + + template_id: Mapped[intpk] + short_name: Mapped[str] = mapped_column(String(32), nullable=False, server_default=FetchedValue()) + lang: Mapped[str] = mapped_column(String(2), nullable=False, server_default=FetchedValue()) + long_name: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + data: Mapped[str] = mapped_column(Text, nullable=False) + sql_statement: Mapped[str] = mapped_column(Text, nullable=False) + update_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + created_by: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()) + updated_by: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()) + workflow_status: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + flag_system: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + tapir_users = relationship('TapirUser', foreign_keys=[created_by], back_populates='tapir_email_templates') + tapir_users_ = relationship('TapirUser', foreign_keys=[updated_by], back_populates='tapir_email_templates_') + + + +class TapirEmailToken(Base): + __tablename__ = 'tapir_email_tokens' + + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, nullable=False, server_default=FetchedValue()) + secret: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False, index=True, server_default=FetchedValue()) + tapir_dest: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + issued_when: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + issued_to: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) + remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + tracking_cookie: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + wants_perm_token: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + user = relationship('TapirUser', primaryjoin='TapirEmailToken.user_id == TapirUser.user_id', back_populates='tapir_email_tokens') + + + +t_tapir_email_tokens_used = Table( + 'tapir_email_tokens_used', metadata, + Column('user_id', ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()), + Column('secret', String(32), nullable=False, server_default=FetchedValue()), + Column('used_when', Integer, nullable=False, server_default=FetchedValue()), + Column('used_from', String(16), nullable=False, server_default=FetchedValue()), + Column('remote_host', String(255), nullable=False, server_default=FetchedValue()), + Column('session_id', ForeignKey('tapir_sessions.session_id'), nullable=False, index=True, server_default=FetchedValue()) +) + + + +t_tapir_error_log = Table( + 'tapir_error_log', metadata, + Column('error_date', Integer, nullable=False, index=True, server_default=FetchedValue()), + Column('user_id', Integer, index=True), + Column('session_id', Integer, index=True), + Column('ip_addr', String(16), nullable=False, index=True, server_default=FetchedValue()), + Column('remote_host', String(255), nullable=False, server_default=FetchedValue()), + Column('tracking_cookie', String(32), nullable=False, index=True, server_default=FetchedValue()), + Column('message', String(32), nullable=False, index=True, server_default=FetchedValue()), + Column('url', String(255), nullable=False, server_default=FetchedValue()), + Column('error_url', String(255), nullable=False, server_default=FetchedValue()) +) + + + +class TapirIntegerVariable(Base): + __tablename__ = 'tapir_integer_variables' + + variable_id: Mapped[str] = mapped_column(String(32), primary_key=True, server_default=FetchedValue()) + value: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + + +class TapirNickname(Base): + __tablename__ = 'tapir_nicknames' + __table_args__ = ( + Index('user_id', 'user_id', 'user_seq'), + ) + + nick_id: Mapped[intpk] + nickname: Mapped[str] = mapped_column(String(20), nullable=False, unique=True, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, server_default=FetchedValue()) + user_seq: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + flag_valid: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + role: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + policy: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + flag_primary: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + + user = relationship('TapirUser', primaryjoin='TapirNickname.user_id == TapirUser.user_id', back_populates='tapir_nicknames') + + + +class TapirNicknamesAudit(Base): + __tablename__ = 'tapir_nicknames_audit' + + nick_id: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) + creation_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + creation_ip_num: Mapped[str] = mapped_column(String(16), nullable=False, index=True, server_default=FetchedValue()) + remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + tracking_cookie: Mapped[str] = mapped_column(String(255), nullable=False, index=True, server_default=FetchedValue()) + + + +t_tapir_no_cookies = Table( + 'tapir_no_cookies', metadata, + Column('log_date', Integer, nullable=False, server_default=FetchedValue()), + Column('ip_addr', String(16), nullable=False, server_default=FetchedValue()), + Column('remote_host', String(255), nullable=False, server_default=FetchedValue()), + Column('tracking_cookie', String(255), nullable=False, server_default=FetchedValue()), + Column('session_data', String(255), nullable=False, server_default=FetchedValue()), + Column('user_agent', String(255), nullable=False, server_default=FetchedValue()) +) + + + +t_tapir_periodic_tasks_log = Table( + 'tapir_periodic_tasks_log', metadata, + Column('t', Integer, nullable=False, index=True, server_default=FetchedValue()), + Column('entry', Text) +) + + + +class TapirPermanentToken(Base): + __tablename__ = 'tapir_permanent_tokens' + + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, nullable=False, server_default=FetchedValue()) + secret: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False, server_default=FetchedValue()) + valid: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + issued_when: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + issued_to: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) + remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + session_id: Mapped[int] = mapped_column(ForeignKey('tapir_sessions.session_id'), nullable=False, index=True, server_default=FetchedValue()) + + session = relationship('TapirSession', primaryjoin='TapirPermanentToken.session_id == TapirSession.session_id', backref='tapir_permanent_tokens') + user = relationship('TapirUser', primaryjoin='TapirPermanentToken.user_id == TapirUser.user_id', back_populates='tapir_permanent_tokens') + + + +t_tapir_permanent_tokens_used = Table( + 'tapir_permanent_tokens_used', metadata, + Column('user_id', ForeignKey('tapir_users.user_id'), index=True), + Column('secret', String(32), nullable=False, server_default=FetchedValue()), + Column('used_when', Integer), + Column('used_from', String(16)), + Column('remote_host', String(255), nullable=False, server_default=FetchedValue()), + Column('session_id', ForeignKey('tapir_sessions.session_id'), nullable=False, index=True, server_default=FetchedValue()) +) + + + +class TapirPhone(Base): + __tablename__ = 'tapir_phone' + + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, nullable=False, server_default=FetchedValue()) + phone_type: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, index=True, server_default=FetchedValue()) + phone_number: Mapped[Optional[str]] = mapped_column(String(32), index=True) + share_phone: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + user = relationship('TapirUser', primaryjoin='TapirPhone.user_id == TapirUser.user_id', back_populates='tapir_phone') + + + +class TapirPolicyClass(Base): + __tablename__ = 'tapir_policy_classes' + + ADMIN = 1 + PUBLIC_USER = 2 + LEGACY_USER = 3 + POLICY_CLASSES = [ + {"name": "Administrator", "class_id": ADMIN, "description": "", "password_storage": 2, "recovery_policy": 3, "permanent_login": 1}, + {"name": "Public user", "class_id": PUBLIC_USER, "description": "", "password_storage": 2, "recovery_policy": 3, "permanent_login": 1}, + {"name": "Legacy user", "class_id": LEGACY_USER, "description": "", "password_storage": 2, "recovery_policy": 3, "permanent_login": 1}, + ] + + class_id: Mapped[int] = mapped_column(SmallInteger, primary_key=True) + name: Mapped[str] = mapped_column(String(64), nullable=False, server_default=FetchedValue()) + description: Mapped[str] = mapped_column(Text, nullable=False) + password_storage: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + recovery_policy: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + permanent_login: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + tapir_users = relationship('TapirUser', back_populates='tapir_policy_classes') + +class TapirPresession(Base): + __tablename__ = 'tapir_presessions' + + presession_id: Mapped[intpk] + ip_num: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) + remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + tracking_cookie: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + created_at: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + + +class TapirRecoveryToken(Base): + __tablename__ = 'tapir_recovery_tokens' + + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, nullable=False, server_default=FetchedValue()) + secret: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False, index=True, server_default=FetchedValue()) + valid: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + tapir_dest: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + issued_when: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + issued_to: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) + remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + tracking_cookie: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + + user = relationship('TapirUser', primaryjoin='TapirRecoveryToken.user_id == TapirUser.user_id', back_populates='tapir_recovery_tokens') + + + +class TapirRecoveryTokensUsed(Base): + __tablename__ = 'tapir_recovery_tokens_used' + + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, nullable=False, server_default=FetchedValue()) + secret: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False, server_default=FetchedValue()) + used_when: Mapped[Optional[int]] = mapped_column(Integer) + used_from: Mapped[Optional[str]] = mapped_column(String(16)) + remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + session_id: Mapped[Optional[int]] = mapped_column(ForeignKey('tapir_sessions.session_id'), index=True) + + session = relationship('TapirSession', primaryjoin='TapirRecoveryTokensUsed.session_id == TapirSession.session_id', backref='tapir_recovery_tokens_useds') + user = relationship('TapirUser', primaryjoin='TapirRecoveryTokensUsed.user_id == TapirUser.user_id', back_populates='tapir_recovery_tokens_used') + + + +t_tapir_save_post_variables = Table( + 'tapir_save_post_variables', metadata, + Column('presession_id', ForeignKey('tapir_presessions.presession_id'), nullable=False, index=True, server_default=FetchedValue()), + Column('name', String(255)), + Column('value', Text, nullable=False), + Column('seq', Integer, nullable=False, server_default=FetchedValue()) +) + + +class TapirSession(Base): + __tablename__ = 'tapir_sessions' + + session_id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=text("'0'")) + last_reissue: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + start_time: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + end_time: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + + user = relationship('TapirUser', primaryjoin='TapirSession.user_id == TapirUser.user_id', back_populates='tapir_sessions') + + +class TapirSessionsAudit(Base): + __tablename__ = 'tapir_sessions_audit' + + session_id: Mapped[int] = mapped_column(ForeignKey('tapir_sessions.session_id'), primary_key=True, server_default=text("'0'"), autoincrement="false") + ip_addr: Mapped[str] = mapped_column(String(16), nullable=False, index=True, server_default=FetchedValue()) + remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + tracking_cookie: Mapped[str] = mapped_column(String(255), nullable=False, index=True, server_default=FetchedValue()) + + session = relationship('TapirSession') + + + +class TapirStringVariable(Base): + __tablename__ = 'tapir_string_variables' + + variable_id: Mapped[str] = mapped_column(String(32), primary_key=True, server_default=FetchedValue()) + value: Mapped[str] = mapped_column(Text, nullable=False) + + + +class TapirString(Base): + __tablename__ = 'tapir_strings' + + name: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False, server_default=FetchedValue()) + module: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False, server_default=FetchedValue()) + language: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False, server_default=FetchedValue()) + string: Mapped[str] = mapped_column(Text, nullable=False) + + + +class TapirUser(Base): + __tablename__ = 'tapir_users' + __table_args__ = ( + ForeignKeyConstraint(['policy_class'], ['tapir_policy_classes.class_id'], name='0_510'), + # When you define unique=True, it creates an index and no need to explicitly make one. And making one + # conflicts with the default-made index and schema creation fails. + # Index('email', 'email', unique=True), + Index('first_name', 'first_name'), + Index('flag_approved', 'flag_approved'), + Index('flag_banned', 'flag_banned'), + Index('flag_can_lock', 'flag_can_lock'), + Index('flag_deleted', 'flag_deleted'), + Index('flag_edit_users', 'flag_edit_users'), + Index('flag_internal', 'flag_internal'), + Index('joined_date', 'joined_date'), + Index('joined_ip_num', 'joined_ip_num'), + Index('last_name', 'last_name'), + Index('policy_class', 'policy_class'), + Index('tracking_cookie', 'tracking_cookie') + ) + + user_id: Mapped[intpk] + first_name: Mapped[Optional[str]] = mapped_column(String(50), index=True) + last_name: Mapped[Optional[str]] = mapped_column(String(50), index=True) + suffix_name: Mapped[Optional[str]] = mapped_column(String(50)) + share_first_name: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) + share_last_name: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) + email: Mapped[str] = mapped_column(String(255), nullable=False, unique=True, server_default=text("''")) + share_email: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'8'")) + email_bouncing: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + policy_class: Mapped[int] = mapped_column(ForeignKey('tapir_policy_classes.class_id'), nullable=False, index=True, server_default=text("'0'")) + joined_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + joined_ip_num: Mapped[Optional[str]] = mapped_column(String(16), index=True) + joined_remote_host: Mapped[str] = mapped_column(String(255), nullable=False, server_default=text("''")) + flag_internal: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + flag_edit_users: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + flag_edit_system: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + flag_email_verified: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + flag_approved: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'1'")) + flag_deleted: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + flag_banned: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + flag_wants_email: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + flag_html_email: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + tracking_cookie: Mapped[str] = mapped_column(String(255), nullable=False, index=True, server_default=text("''")) + flag_allow_tex_produced: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + flag_can_lock: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + + tapir_policy_classes = relationship('TapirPolicyClass', back_populates='tapir_users') + arXiv_control_holds = relationship('ControlHold', foreign_keys='[ControlHold.last_changed_by]', back_populates='tapir_users') + arXiv_control_holds_ = relationship('ControlHold', foreign_keys='[ControlHold.placed_by]', back_populates='tapir_users_') + arXiv_documents = relationship('Document', back_populates='submitter') + arXiv_moderator_api_keys = relationship('ModeratorApiKey', back_populates='user') + tapir_address = relationship('TapirAddress', back_populates='user') + tapir_email_change_tokens = relationship('TapirEmailChangeToken', back_populates='user') + tapir_email_templates = relationship('TapirEmailTemplate', foreign_keys='[TapirEmailTemplate.created_by]', back_populates='tapir_users') + tapir_email_templates_ = relationship('TapirEmailTemplate', foreign_keys='[TapirEmailTemplate.updated_by]', back_populates='tapir_users_') + tapir_email_tokens = relationship('TapirEmailToken', back_populates='user') + tapir_nicknames = relationship('TapirNickname', back_populates='user', uselist=False) + tapir_phone = relationship('TapirPhone', back_populates='user') + tapir_recovery_tokens = relationship('TapirRecoveryToken', back_populates='user') + tapir_sessions = relationship('TapirSession', back_populates='user') + arXiv_cross_controls = relationship('CrossControl', back_populates='user') + arXiv_endorsement_requests = relationship('EndorsementRequest', back_populates='endorsee') + arXiv_jref_controls = relationship('JrefControl', back_populates='user') + arXiv_metadata = relationship('Metadata', back_populates='submitter') + arXiv_show_email_requests = relationship('ShowEmailRequest', back_populates='user') + arXiv_submission_control = relationship('SubmissionControl', back_populates='user') + arXiv_submissions = relationship('Submission', back_populates='submitter') + tapir_admin_audit = relationship('TapirAdminAudit', foreign_keys='[TapirAdminAudit.admin_user]', back_populates='tapir_users') + tapir_admin_audit_ = relationship('TapirAdminAudit', foreign_keys='[TapirAdminAudit.affected_user]', back_populates='tapir_users_') + tapir_email_mailings = relationship('TapirEmailMailing', foreign_keys='[TapirEmailMailing.created_by]', back_populates='tapir_users') + tapir_email_mailings_ = relationship('TapirEmailMailing', foreign_keys='[TapirEmailMailing.sent_by]', back_populates='tapir_users_') + tapir_permanent_tokens = relationship('TapirPermanentToken', back_populates='user') + tapir_recovery_tokens_used = relationship('TapirRecoveryTokensUsed', back_populates='user') + + endorsee_of = relationship('Endorsement', foreign_keys='[Endorsement.endorsee_id]', back_populates='endorsee') + endorses = relationship('Endorsement', foreign_keys='[Endorsement.endorser_id]', back_populates='endorser') + + arXiv_ownership_requests = relationship('OwnershipRequest', back_populates='user') + arXiv_submission_category_proposal = relationship('SubmissionCategoryProposal', back_populates='user') + arXiv_submission_flag = relationship('SubmissionFlag', back_populates='user') + arXiv_submission_hold_reason = relationship('SubmissionHoldReason', back_populates='user') + arXiv_submission_locks: Mapped[List["SubmissionLocks"]] = relationship("SubmissionLocks", back_populates="user") + arXiv_submission_view_flag = relationship('SubmissionViewFlag', back_populates='user') + arXiv_check_results: Mapped[List["CheckResults"]] = relationship("CheckResults", back_populates="user") + arXiv_check_responses: Mapped[List["CheckResponses"]] = relationship("CheckResponses", back_populates="user") + + owned_papers = relationship("PaperOwner", foreign_keys="[PaperOwner.user_id]", back_populates="owner") + demographics = relationship('Demographic', foreign_keys="[Demographic.user_id]", uselist=False, back_populates='user') + + +class AuthorIds(Base): + __tablename__ = 'arXiv_author_ids' + + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True) + author_id: Mapped[str] = mapped_column(String(50), nullable=False, index=True) + updated: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) + + +class Demographic(Base): + __tablename__ = 'arXiv_demographics' + __table_args__ = ( + ForeignKeyConstraint(['archive', 'subject_class'], ['arXiv_categories.archive', 'arXiv_categories.subject_class']), + Index('dem_archive', 'archive', 'subject_class') + ) + + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, server_default=FetchedValue()) + country: Mapped[str] = mapped_column(String(2), nullable=False, index=True, server_default=FetchedValue()) + affiliation: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + url: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + type: Mapped[Optional[int]] = mapped_column(SmallInteger, index=True) + archive: Mapped[Optional[str]] = mapped_column(String(16)) + subject_class: Mapped[Optional[str]] = mapped_column(String(16)) + original_subject_classes: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + flag_group_physics: Mapped[Optional[int]] = mapped_column(Integer, index=True) + flag_group_math: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + flag_group_cs: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + flag_group_nlin: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + flag_proxy: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + flag_journal: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + flag_xml: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + dirty: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + flag_group_test: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + flag_suspect: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + flag_group_q_bio: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + flag_group_q_fin: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + flag_group_stat: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + flag_group_eess: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + flag_group_econ: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + veto_status: Mapped[Literal['ok', 'no-endorse', 'no-upload', 'no-replace']] = mapped_column(Enum('ok', 'no-endorse', 'no-upload', 'no-replace'), nullable=False, server_default=text("'ok'")) + + # the original user + user = relationship('TapirUser', back_populates='demographics') + + arXiv_category = relationship('Category', primaryjoin='and_(Demographic.archive == Category.archive, Demographic.subject_class == Category.subject_class)', backref='arXiv_demographics') + + GROUP_FLAGS = [ + ('grp_physics', 'flag_group_physics'), + ('grp_math', 'flag_group_math'), + ('grp_cs', 'flag_group_cs'), + ('grp_q-bio', 'flag_group_q_bio'), + ('grp_q-fin', 'flag_group_q_fin'), + ('grp_q-stat', 'flag_group_stat'), + ('grp_q-econ', 'flag_group_econ'), + ('grp_eess', 'flag_group_eess'), + ] + + @property + def groups(self) -> List[str]: + """Active groups for this user profile.""" + return [group for group, column in self.GROUP_FLAGS + if getattr(self, column) == 1] + + +class OrcidIds(Base): + __tablename__ = 'arXiv_orcid_ids' + + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True) + orcid: Mapped[str] = mapped_column(String(19), nullable=False, index=True) + authenticated: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + updated: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) + + +class QueueView(Base): + __tablename__ = 'arXiv_queue_view' + + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id', ondelete='CASCADE'), primary_key=True, server_default=FetchedValue()) + last_view: Mapped[Optional[datetime]] + second_last_view: Mapped[Optional[datetime]] + total_views: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + + +class SuspiciousName(Base): + __tablename__ = 'arXiv_suspicious_names' + + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, server_default=FetchedValue()) + full_name: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) + + +class SwordLicense(Base): + __tablename__ = 'arXiv_sword_licenses' + + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True) + license: Mapped[Optional[str]] = mapped_column(String(127)) + updated: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) + + +class TapirDemographic(Base): + __tablename__ = 'tapir_demographics' + + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, server_default=FetchedValue()) + gender: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + share_gender: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + birthday: Mapped[Optional[date]] = mapped_column(Date, index=True) + share_birthday: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + country: Mapped[str] = mapped_column(ForeignKey('tapir_countries.digraph'), nullable=False, index=True, server_default=FetchedValue()) + share_country: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + postal_code: Mapped[str] = mapped_column(String(16), nullable=False, index=True, server_default=FetchedValue()) + + tapir_country = relationship('TapirCountry', primaryjoin='TapirDemographic.country == TapirCountry.digraph', backref='tapir_demographics') + + +class TapirUsersHot(Base): + __tablename__ = 'tapir_users_hot' + + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, server_default=FetchedValue()) + last_login: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + second_last_login: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + number_sessions: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + + +class TapirUsersPassword(Base): + __tablename__ = 'tapir_users_password' + + user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, server_default=FetchedValue()) + password_storage: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + password_enc: Mapped[str] = mapped_column(String(50), nullable=False, server_default=FetchedValue()) + + user = relationship('TapirUser') + + +class SubmissionLocks(Base): + __tablename__ = 'arXiv_submission_locks' + __table_args__ = ( + ForeignKeyConstraint(['submission_id'], ['arXiv_submissions.submission_id'], name='arxiv_submission_locks_sub_fk'), + ForeignKeyConstraint(['user_id'], ['tapir_users.user_id'], name='arxiv_submission_locks_user_fk'), + Index('arxiv_submission_locks_sub_index', 'submission_id', 'lock_type', unique=True) + ) + + submission_lock_id: Mapped[int] = mapped_column(Integer, primary_key=True) + submission_id: Mapped[int] = mapped_column(Integer, nullable=False) + user_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) + lock_type: Mapped[str] = mapped_column(String(20), nullable=False) + expires: Mapped[datetime] = mapped_column(DateTime, nullable=False) + updated: Mapped[datetime] = mapped_column(DateTime, nullable=False) + released: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + + submission: Mapped['Submission'] = relationship('Submission', back_populates='arXiv_submission_locks') + user: Mapped['TapirUser'] = relationship('TapirUser', back_populates='arXiv_submission_locks') + + +######################################################################################################## +# Student-lead membership dashboard - supercedes "Subscription_UniversalInstitution" +class MembershipInstitutions(Base): + __tablename__ = 'membership_institutions' + + sid: Mapped[int] = mapped_column(Integer, primary_key=True) + is_active: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) + name: Mapped[Optional[str]] = mapped_column(String(256), index=True) + country: Mapped[Optional[str]] = mapped_column(String(40)) + country_code: Mapped[Optional[str]] = mapped_column(String(10)) + consortia_code: Mapped[Optional[str]] = mapped_column(String(20)) + member_type: Mapped[Optional[str]] = mapped_column(String(20)) + ror_id: Mapped[Optional[str]] = mapped_column(String(50)) + is_consortium: Mapped[Optional[int]] = mapped_column(Integer) + label: Mapped[Optional[str]] = mapped_column(String(256)) + comment: Mapped[Optional[str]] = mapped_column(Text) + + +# Student-lead membership dashboard +class MembershipUsers(Base): + __tablename__ = 'membership_users' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + sid: Mapped[int] = mapped_column(Integer, nullable=False) + user_id: Mapped[Optional[int]] = mapped_column(Integer) + + +######################################################################################################## +# +class DBLaTeXMLDocuments(LaTeXMLBase): + __tablename__ = 'arXiv_latexml_doc' + + paper_id: Mapped[str] = mapped_column(String(20), primary_key=True) + document_version: Mapped[intpk] + # conversion_status codes: + # - 0 = in progress + # - 1 = success + # - 2 = failure + conversion_status: Mapped[int] = mapped_column(Integer, nullable=False) + latexml_version: Mapped[str] = mapped_column(String(40), nullable=False) + tex_checksum: Mapped[Optional[str]] = mapped_column(String(255)) + conversion_start_time: Mapped[Optional[int]] = mapped_column(Integer) + conversion_end_time: Mapped[Optional[int]] = mapped_column(Integer) + publish_dt: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True)) + +class DBLaTeXMLSubmissions (LaTeXMLBase): + __tablename__ = 'arXiv_latexml_sub' + + submission_id: Mapped[intpk] + # conversion_status codes: + # - 0 = in progress + # - 1 = success + # - 2 = failure + conversion_status: Mapped[int] = mapped_column(Integer, nullable=False) + latexml_version: Mapped[str] = mapped_column(String(40), nullable=False) + tex_checksum: Mapped[Optional[str]] = mapped_column(String(255)) + conversion_start_time: Mapped[Optional[int]] + conversion_end_time: Mapped[Optional[int]] + +class DBLaTeXMLFeedback (LaTeXMLBase): + __tablename__ = 'feedback' + + id: Mapped[str] = mapped_column(String(40), primary_key=True) + canonical_url: Mapped[Optional[str]] = mapped_column(String(255)) + conversion_url: Mapped[Optional[str]] = mapped_column(String(255)) + report_time: Mapped[Optional[int]] = mapped_column(BigInteger) + browser_info: Mapped[Optional[str]] = mapped_column(String(255)) + location_low: Mapped[Optional[str]] = mapped_column(String(255)) + location_high: Mapped[Optional[str]] = mapped_column(String(255)) + description: Mapped[Optional[str]] = mapped_column(String(255)) + selected_html: Mapped[Optional[str]] = mapped_column(String(255)) + initiation_mode: Mapped[Optional[str]] = mapped_column(String(255)) + + +# From modapi + +class CheckRoles(Base): + """ swimlanes: editor, student, moderator, qa """ + __tablename__ = 'arXiv_check_roles' + + check_role_id = Column(INTEGER(11), primary_key=True) + name = Column(VARCHAR(40), nullable=False) + description = Column(VARCHAR(200), nullable=True, server_default=text("''")) + + def __repr__(self): + return f"{ type(self).__name__ }/{ self.check_role_id }:{self.name}" + + +class CheckResultViews(Base): + """ A hint for how arxiv-check can parse and view check_results.data """ + __tablename__ = 'arXiv_check_result_views' + + check_result_view_id = Column(INTEGER(11), primary_key=True) + name = Column(VARCHAR(40), nullable=False) + description = Column(VARCHAR(200), nullable=True, server_default=text("''")) + + def __repr__(self): + return f"{ type(self).__name__ }/{ self.check_result_view_id }:{self.name}" + + +class CheckTargets(Base): + """ Will the QA check need to respond to updates to the file or the + database metadata. """ + __tablename__ = 'arXiv_check_targets' + + check_target_id = Column(INTEGER(11), primary_key=True) + name = Column(VARCHAR(40), nullable=False) + description = Column(VARCHAR(200), nullable=True, server_default=text("''")) + + def __repr__(self): + return f"{ type(self).__name__ }/{ self.check_target_id }:{self.name}" + + +class Checks(Base): + __tablename__ = 'arXiv_checks' + + check_id = Column(INTEGER(11), primary_key=True) + check_target_id = Column(ForeignKey('arXiv_check_targets.check_target_id'), index=False) + #, ondelete='CASCADE', onupdate='CASCADE' + check_role_id = Column(ForeignKey('arXiv_check_roles.check_role_id'), index=False) + check_result_view_id = Column(ForeignKey('arXiv_check_result_views.check_result_view_id'), nullable=False, server_default=text("'1'"), index=False) + name = Column(VARCHAR(40), nullable=False) + description = Column(VARCHAR(200), nullable=True) + enable_check = Column(INTEGER(1), nullable=False, server_default=text("'0'")) + enable_hold = Column(INTEGER(1), nullable=False, server_default=text("'0'")) + enable_queue = Column(INTEGER(1), nullable=False, server_default=text("'0'")) + retry_minutes = Column(INTEGER(11), nullable=False, server_default=text("'0'")) + optional = Column(INTEGER(1), nullable=False, server_default=text("'1'")) + persist_response = Column(INTEGER(1), nullable=False, server_default=text("'0'")) + + target = relationship('CheckTargets') + role = relationship('CheckRoles') + view = relationship('CheckResultViews') + + def __repr__(self): + return f"{ type(self).__name__ }/{ self.check_id }:{self.name};{'enabled' if self.enable_check else ''}" + + +class CheckResults(Base): + __tablename__ = 'arXiv_check_results' + + check_result_id = Column(INTEGER(11), primary_key=True) + submission_id = Column(ForeignKey('arXiv_submissions.submission_id'), nullable=False, index=True) + data_version = Column(INTEGER(11), nullable=False, server_default=text("'0'")) + metadata_version = Column(INTEGER(11), nullable=False, server_default=text("'0'")) + check_id = Column(ForeignKey('arXiv_checks.check_id'), nullable=False, index=True) + user_id = Column(ForeignKey('tapir_users.user_id'), index=True) + ok = Column(INTEGER(1), nullable=False) + created = Column(DateTime, nullable=False, server_default=func.now()) + message = Column(VARCHAR(40), nullable=True) + data = Column(VARCHAR(4000), nullable=True) + """ + select max(length(logtext)) from arXiv_admin_log; #65535 + select length(logtext), count(*) from arXiv_admin_log where length(logtext)>200 and username like 'qaadmin' group by length(logtext) order by length(logtext) desc limit 200 + mysql max varchar length: 65,535 + """ + + submission = relationship('Submission') + check = relationship('Checks') + user = relationship('TapirUser') + + check_responses = relationship('CheckResponses') + + def __repr__(self): + return f"{ type(self).__name__ }/{ self.check_result_id };check={self.check_id};s/{ self.submission_id };d={self.data_version};m={self.metadata_version};ok={ self.ok}" + + +class CheckResponses(Base): + __tablename__ = 'arXiv_check_responses' + + check_response_id = Column(INTEGER(11), primary_key=True) + check_result_id= Column(ForeignKey('arXiv_check_results.check_result_id'), index=True) + user_id = Column(ForeignKey('tapir_users.user_id'), index=True) + ok = Column(INTEGER(1), nullable=False) + """If the related CheckResults ok==0, admin/mods respond with decision on whether that qa hold should stand or be dismissed.""" + + persist_response = Column(INTEGER(1), nullable=False, server_default=text("'0'")) + """This admin/mod decision is accepted for future check_results, if the submission is updated. """ + + created = Column(DateTime, nullable=False, server_default=func.now()) + message = Column(VARCHAR(200), nullable=True) + + user = relationship('TapirUser') + + def __repr__(self): + return f"{ type(self).__name__ }/{ self.check_response_id };result={self.check_result_id};ok={ self.ok}" + + +def configure_db_engine(classic_engine: Engine, latexml_engine: Optional[Engine]) -> Tuple[Engine, Optional[Engine]]: + session_factory.configure(binds={ + Base: classic_engine, + LaTeXMLBase: (latexml_engine if latexml_engine else classic_engine), + t_arXiv_stats_hourly: classic_engine, + t_arXiv_admin_state: classic_engine, + t_arXiv_bad_pw: classic_engine, + t_arXiv_black_email: classic_engine, + t_arXiv_block_email: classic_engine, + t_arXiv_bogus_subject_class: classic_engine, + t_arXiv_duplicates: classic_engine, + t_arXiv_in_category: classic_engine, + t_arXiv_moderators: classic_engine, + t_arXiv_ownership_requests_papers: classic_engine, + t_arXiv_refresh_list: classic_engine, + t_arXiv_updates_tmp: classic_engine, + t_arXiv_white_email: classic_engine, + t_arXiv_xml_notifications: classic_engine, + t_demographics_backup: classic_engine, + t_tapir_email_change_tokens_used: classic_engine, + t_tapir_email_tokens_used: classic_engine, + t_tapir_error_log: classic_engine, + t_tapir_no_cookies: classic_engine, + t_tapir_periodic_tasks_log: classic_engine, + t_tapir_periodic_tasks_log: classic_engine, + t_tapir_permanent_tokens_used: classic_engine, + t_tapir_save_post_variables: classic_engine + }) + return classic_engine, latexml_engine + +# Configure the models from env vars at package load time +configure_db_engine(_classic_engine, _latexml_engine) diff --git a/arxiv/db/tests/__init__.py b/arxiv/db/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/arxiv/db/tests/test_db_schema.py b/arxiv/db/tests/test_db_schema.py new file mode 100644 index 000000000..252d68dd6 --- /dev/null +++ b/arxiv/db/tests/test_db_schema.py @@ -0,0 +1,58 @@ +import os +from sqlalchemy import create_engine, text +from sqlalchemy.orm import sessionmaker +import tempfile +import sqlite3 + +# Without this import, Base.metadata does not get populated. So it may look doing nothing but do not remove this. +import arxiv.db.models + +from .. import Base, LaTeXMLBase, session_factory, _classic_engine as classic_engine + +def _make_schemas(db_uri: str): + db_engine = create_engine(db_uri) + + SessionLocal = sessionmaker(autocommit=False, autoflush=True) + SessionLocal.configure(bind=db_engine) + db_session = SessionLocal(autocommit=False, autoflush=True) + db_session.execute(text('select 1')) + + Base.metadata.drop_all(db_engine) + Base.metadata.create_all(db_engine) + LaTeXMLBase.metadata.drop_all(db_engine) + LaTeXMLBase.metadata.create_all(db_engine) + + db_session.commit() + + +def test_db_schema(): + """ + To test the MySQL and any other DB. + + Note that, it's not possible to create the accurate MySQL arXiv schema from python + model. This is because the model object is NOT accurate representation of schema + as it has to be able to create sqlite3 for testing. + """ + db_uri = os.environ.get('TEST_ARXIV_DB_URI') + if db_uri is None: + print("db_uri is not defined. Bypassing the test") + return + _make_schemas(db_uri) + + +def test_db_schema_sqlite3(): + with tempfile.NamedTemporaryFile(suffix='.sqlite3', delete=False) as tmp: + filename = tmp.name + # TIL - you need 4 slashes as the hostname is between 2nd and 3rd slashes + _make_schemas("sqlite:///" + filename) + conn = sqlite3.connect(filename) + cur = conn.cursor() + cur.execute("SELECT sql FROM sqlite_master WHERE type='table'") + n_tables = 0 + for row in cur.fetchall(): + # print(row[0]) + n_tables += 1 + conn.close() + # There are 145 tables on arxiv-production, and 3 LaTexML tables in the db/model.py + assert n_tables == (145 + 3) + os.unlink(filename) diff --git a/arxiv/db/tests/testdb.sh b/arxiv/db/tests/testdb.sh new file mode 100755 index 000000000..7a421d292 --- /dev/null +++ b/arxiv/db/tests/testdb.sh @@ -0,0 +1,5 @@ +#!/bin/sh +sudo mysql -e "CREATE DATABASE testdb;" +sudo mysql -e "CREATE USER 'testuser'@'localhost' IDENTIFIED BY 'testpassword';" +sudo mysql -e "GRANT ALL PRIVILEGES ON testdb.* TO 'testuser'@'localhost';" +sudo mysql -e "FLUSH PRIVILEGES;" \ No newline at end of file diff --git a/arxiv/integration/tests/test_fastly.py b/arxiv/integration/tests/test_fastly.py index 2c5836d09..76179fa1d 100644 --- a/arxiv/integration/tests/test_fastly.py +++ b/arxiv/integration/tests/test_fastly.py @@ -215,7 +215,7 @@ def test_purge_cache_for_paper(mockToday,mockPurge, mockDBQuery): actual_keys = mockPurge.call_args[0][0] assert sorted(actual_keys) == sorted (expected_keys) -def test_get_category_and_date_nonexstant_ids(): +def test_get_category_and_date_nonexstant_ids(db_configed): #there is no paper with this id #also base has no test db so any paper would return none, but this will work even if it gets data bad_id=Identifier("0807.9999") diff --git a/conftest.py b/conftest.py new file mode 100644 index 000000000..4465ae7dd --- /dev/null +++ b/conftest.py @@ -0,0 +1,296 @@ +import logging +import os +import shutil +import subprocess +import tempfile +from datetime import datetime, UTC + +import pytest +from flask import Flask +from sqlalchemy import create_engine, NullPool, text, CursorResult +from sqlalchemy.orm import Session + +from arxiv.auth.auth import Auth +from arxiv.auth.auth.middleware import AuthMiddleware + +from arxiv.auth.legacy import util +from arxiv.auth.legacy.passwords import hash_password +from arxiv.base import Base +from arxiv.base.middleware import wrap +from arxiv.db import models, Session as arXiv_session +from arxiv.db.models import configure_db_engine + +PYTHON_EXE = "python" +DB_PORT = 25336 +DB_NAME = "testdb" +ROOT_PASSWORD = "rootpassword" +my_sql_cmd = ["mysql", f"--port={DB_PORT}", "-h", "127.0.0.1", "-u", "root", f"--password={ROOT_PASSWORD}"] + + +def arxiv_base_dir() -> str: + """ + Returns: + "arxiv-base" directory abs path + """ + return os.path.dirname(os.path.abspath(__file__)) + + +@pytest.fixture(scope="session") +def db_uri(request): + db_type = request.config.getoption("--db") + + if db_type == "sqlite": + # db_path = tempfile.mkdtemp() + # uri = f'sqlite:///{db_path}/test.db' + uri = f'sqlite' + elif db_type == "mysql": + # load_arxiv_db_schema.py sets up the docker and load the db schema + loader_py = os.path.join(arxiv_base_dir(), "development", "load_arxiv_db_schema.py") + subprocess.run(["poetry", "run", PYTHON_EXE, loader_py, f"--db_name={DB_NAME}", f"--db_port={DB_PORT}", + f"--root_password={ROOT_PASSWORD}"], encoding="utf-8", check=True) + uri = f"mysql://testuser:testpassword@127.0.0.1:{DB_PORT}/{DB_NAME}" + else: + raise ValueError(f"Unsupported database dialect: {db_type}") + + yield uri + + +@pytest.fixture(scope="function") +def classic_db_engine(db_uri): + logger = logging.getLogger() + db_path = None + use_ssl = False + if db_uri.startswith("sqlite"): + db_path = tempfile.mkdtemp() + uri = f'sqlite:///{db_path}/test.db' + db_engine = create_engine(uri) + util.create_arxiv_db_schema(db_engine) + else: + conn_args = {} + if not use_ssl: + conn_args["ssl"] = None + db_engine = create_engine(db_uri, connect_args=conn_args, poolclass=NullPool) + + # Clean up the tables to real fresh + targets = [] + with db_engine.connect() as connection: + tables = [row[0] for row in connection.execute(text("SHOW TABLES"))] + for table_name in tables: + counter: CursorResult = connection.execute(text(f"select count(*) from {table_name}")) + count = counter.first()[0] + if count and int(count): + targets.append(table_name) + connection.invalidate() + + if targets: + if len(targets) > 20 or "arXiv_metadata" in targets: + logger.error("Too many tables used in the database. Suspect this is not the intended test database.\n" + "Make sure you are not using any of production or even development database.") + exit(1) + statements = [ "SET FOREIGN_KEY_CHECKS = 0;"] + [f"TRUNCATE TABLE {table_name};" for table_name in targets] + ["SET FOREIGN_KEY_CHECKS = 1;"] + # debug_sql = "SHOW PROCESSLIST;\nSELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;\n" + sql = "\n".join(statements) + cmd = my_sql_cmd + if not use_ssl: + cmd = my_sql_cmd + ["--ssl-mode=DISABLED"] + cmd = cmd + [DB_NAME] + mysql = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, encoding="utf-8") + try: + # logger.info(sql) + out, err = mysql.communicate(sql, timeout=9999) + if out: + logger.info(out) + if err and not err.startswith("[Warning] Using a password on the command line interface can be insecure"): + logger.info(err) + except Exception as exc: + logger.error(f"BOO: {str(exc)}", exc_info=True) + + util.bootstrap_arxiv_db(db_engine) + + yield db_engine + + if db_path: + shutil.rmtree(db_path) + # else: + # # This is to shut down the client connection from the database side. Get the list of processes used by + # # the testuser and kill them all. + # with db_engine.connect() as connection: + # danglings: CursorResult = connection.execute(text("select id from information_schema.processlist where user = 'testuser';")).all() + # connection.invalidate() + # if danglings: + # kill_conn = "\n".join([ f"kill {id[0]};" for id in danglings ]) + # cmd = my_sql_cmd + # if not use_ssl: + # cmd = cmd + ["--ssl-mode=DISABLED"] + # cmd = cmd + [DB_NAME] + # mysql = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, encoding="utf-8") + # mysql.communicate(kill_conn) + db_engine.dispose() + + +@pytest.fixture +def foouser(mocker): + user_id = '15830' + email = 'first@last.iv' + # Why does this use a mock for the use and not a models.TapirUser? + # Using an ORM obj caused problems when outside a session, but it seems + # like there should be a way to do that. + user = mocker.MagicMock( + user_id=user_id, + first_name='first', + last_name='last', + suffix_name='iv', + email=email, + policy_class=2, + flag_edit_users=1, + flag_email_verified=1, + flag_edit_system=0, + flag_approved=1, + flag_deleted=0, + flag_banned=0, + tracking_cookie='foocookie', + ) + nick = mocker.MagicMock( + nickname='foouser', + user_id=user_id, + user_seq=1, + flag_valid=1, + role=0, + policy=0, + flag_primary=1 + ) + password = 'thepassword' + hashed = hash_password(password) + password = mocker.MagicMock( + user_id=user_id, + password_storage=2, + password_enc=hashed, + test_only_password=password, # this is not on the real obj, just used so tests have access to it + ) + n = util.epoch(datetime.now(tz=UTC)) + secret = 'foosecret' + token = mocker.MagicMock( + user_id=user_id, + secret=secret, + valid=1, + issued_when=n, + issued_to='127.0.0.1', + remote_host='foohost.foo.com', + session_id=1 + ) + user.tapir_nicknames = nick + user.tapir_passwords = password + user.tapir_tokens = token + + return user + + +@pytest.fixture +def db_with_user(classic_db_engine, foouser): + try: + _load_test_user(classic_db_engine, foouser) + except Exception as e: + pass + yield classic_db_engine + + +def _load_test_user(db_engine, foouser): + # just combines db_engine and foouser + with Session(db_engine) as session: + + user = models.TapirUser( + user_id=foouser.user_id, + first_name=foouser.first_name, + last_name=foouser.last_name, + suffix_name=foouser.suffix_name, + email=foouser.email, + policy_class=foouser.policy_class, + flag_edit_users=foouser.flag_edit_users, + flag_email_verified=foouser.flag_email_verified, + flag_edit_system=foouser.flag_edit_system, + flag_approved=foouser.flag_approved, + flag_deleted=foouser.flag_deleted, + flag_banned=foouser.flag_banned, + tracking_cookie=foouser.tracking_cookie, + ) + session.add(user) + session.commit() + + # Make sure the ID is correct. If you are using mysql with different auto-increment. you may get an different id + # However, domain.User's user_id is str, and the db/models User model user_id is int. + # wish they match but since tapir's user id came from auto-increment id which has to be int, I guess + # "it is what it is". + assert str(foouser.user_id) == str(user.user_id) + + nick = models.TapirNickname( + nickname=foouser.tapir_nicknames.nickname, + user_id=foouser.tapir_nicknames.user_id, + user_seq=foouser.tapir_nicknames.user_seq, + flag_valid=foouser.tapir_nicknames.flag_valid, + role=foouser.tapir_nicknames.role, + policy=foouser.tapir_nicknames.policy, + flag_primary=foouser.tapir_nicknames.flag_primary, + ) + session.add(nick) + session.commit() + + password = models.TapirUsersPassword( + user_id=foouser.user_id, + password_storage=foouser.tapir_passwords.password_storage, + password_enc=foouser.tapir_passwords.password_enc, + ) + session.add(password) + session.commit() + + with Session(db_engine) as session: + tapir_session_1 = models.TapirSession( + session_id = foouser.tapir_tokens.session_id, + user_id = foouser.user_id, + last_reissue = 0, + start_time = 0, + end_time = 0 + ) + session.add(tapir_session_1) + session.commit() + assert foouser.tapir_tokens.session_id == tapir_session_1.session_id + + with Session(db_engine) as session: + token = models.TapirPermanentToken( + user_id=foouser.user_id, + secret=foouser.tapir_tokens.secret, + valid=foouser.tapir_tokens.valid, + issued_when=foouser.tapir_tokens.issued_when, + issued_to=foouser.tapir_tokens.issued_to, + remote_host=foouser.tapir_tokens.remote_host, + session_id=foouser.tapir_tokens.session_id, + ) + session.add(token) + session.commit() + + +@pytest.fixture +def db_configed(db_with_user): + db_engine, _ = configure_db_engine(db_with_user,None) + yield None + arXiv_session.remove() + + +@pytest.fixture +def app(db_with_user): + app = Flask('test_auth_app') + + engine, _ = configure_db_engine(db_with_user, None) + Base(app) + Auth(app) + wrap(app, [AuthMiddleware]) + yield app + + +@pytest.fixture +def request_context(app): + yield app.test_request_context() + + +def pytest_addoption(parser): + parser.addoption("--db", action="store", default="sqlite", + help="Database type to test against (sqlite/mysql)") diff --git a/development/Makefile b/development/Makefile new file mode 100644 index 000000000..e23caa73e --- /dev/null +++ b/development/Makefile @@ -0,0 +1,17 @@ +PROD_DB_PROXY_PORT := 2021 +DEV_DB_PROXY_PORT := 6201 + +.PHONY: default hello proxy dev-proxy + +default: hello + +hello: + echo "Hello" + + +proxy: + /usr/local/bin/cloud-sql-proxy --address 0.0.0.0 --port ${PROD_DB_PROXY_PORT} arxiv-production:us-central1:arxiv-production-rep9 > /dev/null 2>&1 & + +dev-proxy: + /usr/local/bin/cloud-sql-proxy --address 0.0.0.0 --port ${DEV_DB_PROXY_PORT} arxiv-development:us-east4:arxiv-db-dev > /dev/null 2>&1 & + diff --git a/development/README.md b/development/README.md new file mode 100644 index 000000000..5c678d605 --- /dev/null +++ b/development/README.md @@ -0,0 +1,137 @@ +# Generating arxiv/db/models.py + +**DO NOT EDIT db/models.py.** + +## Ingredients + +* MySQL database access in order to get the database schema from +* The original arxiv-base's arxiv/db/orig_models.py. +* arxiv/db/arxiv-db-metadata.yaml +* Modified version of sqlacodegen in arxiv-base/development/sqlacodegen +* The steps are driven by development/db_codegen.py which does the merge. + +This will generate arxiv/db/models.py + + arXiv database (mysql) -----------\ + > sqlacodegen --> arxiv/db/autogen_models.py + arxiv/db/arxiv-db-metadata.yaml --/ + + arxiv/db/orig_models.py -----\ + + merge --> arxiv/db//models.py + arxiv/db/autogen_models.py --/ + +TL;DR - If you need to add to db/models.py, you either add it to db/orig_models.py or to db/arxiv-db-metadata.yaml. + +**DO NOT EDIT db/models.py.** + +## Steps + +First, you need a venv with poetry. Set it up with arxiv-base's pyproject.toml as usual. + +Second, you need one of two: + +* docker to run the mysql +* local mysql + +If you do not have local mysql, docker mysql is used. development/db_codegen pulls and +starts the docker, if you just run it, the docker mysql is used. + +so once + + . venv/bin/activate + python development/db_codegen.py + +generates `arxiv/db/models.py` + +**DO NOT EDIT db/models.py.** + +## Anatomy of db_codegen.py + +does following steps. + +1. start mysql docker if no MySQL running +2. load arxiv/db/arxiv_db_schema.sql to the local mysql +3. runs the modified development/sqlacodegen with the codegen metadata. This generates arxiv/db/autogen_models.py +4. merges arxiv/db/autogen_models.py and arxiv/db/orig_models.py and creates arxiv/db/models.py + +### Modified sqlacodegen + +In order to accomate the existing changes made to arxiv/db/models.py in the past, unmodified sqlacodegen cannot +generate the code we need from the database schema. +The details of sqlacodegen modification is in development/sqlacodegen/ARXIV-README.md. + +Here is the TL;DR of changes made to it: + +1. Overriding the class name of model class +2. Overriding the TableModel / Table selection +3. Manipulate the __table_args__ +4. Set the index/primary key attribute to the column definition from the table args. +5. Override the column definition +6. Override the relationship definition +7. Append the extra relationship + +With these changes, auto-generated models (autogen_models.py) becomes somewhat close to what we need, but +it cannot be used as is. db_codegen.py post-processes the autogen .py. + +For more details of sqlacodegen changes from the original, see +[development/sqlacodegen/ARXIV-README.md](sqlacodegen/ARXIV-README.md). + + +### Merge autogen_models.py and orig_models.py + +In order to maintain the hand-edited portion of arxiv/db/models.py, it is renamed as `orig_models.py`, and used +as an input of merge source. + +This is how merge works: + +1. Parse orig_models.py. This is usually named `existing_` in the code +2. Parse autogen_models.py. This is usually prefixed with `latest_` in the code +3. Catalogs the classes in "latest". +4. Traverse the parse tree of "existing" +5. While traversing existing parsed tree, if it finds the matching class in latest, replace the assignments in the class. +6. Also update the simple assignments if it is "FOO = Table()" +7. Print the updated tree + +Parsing, traversing and updating the Python code uses [CST](https://github.com/Instagram/LibCST). +[AST](https://docs.python.org/3/library/ast.html) cannot be used as it removes the comments. + +**IMPORTANT** + +Because of this, if you add a new table, **it does not show up in the db/models.py. You need to manually add the +class to arxiv/db/orig_models.py**. + +When you run the db_models.py, it leaves the db/autogen_models.py. You copy&paste to db/orig_models.py and run +the db_codegen.py again. It will show up. + +### Merging rules of SchemaTransformer + +CST provides a tree traversing method that takes an object of Transformer (cst.CSTTransformer). + +The tree traversing invokes the member functions prefixed by "enter" and "leave". Using this, the transformer +visits the classes and assignments in the `orig_models.py` and replaces the class members with the latest +members. + +#### leave_ClassDef + +This is where the latest model object is merged to existing model. + +#### leave_Assign + +This is where the latest table def is replaced. + +### Running db_codegen.py under debugger + +Generally, you don't need any special set-up other than running MySQL/arxiv database. + + +## Helpers + +`extract_class_n_table.py` parses a model python file and prints out the table and class name map. +This is the first thing you have to do to start the `arxiv-db-metadata.yaml` file. + +`dump-schema.sh` unloads the schema from database and writes to arxiv_db_schemas.sql. +You need to provide the database access credential to run the mysqldump command. +For this to run, you'd need to run a db access proxy on port 2021. + + +I repeat **DO NOT EDIT db/models.py.** diff --git a/development/__init__.py b/development/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/development/arxiv_db_schema.sql b/development/arxiv_db_schema.sql new file mode 100644 index 000000000..893d0a261 --- /dev/null +++ b/development/arxiv_db_schema.sql @@ -0,0 +1,3067 @@ +-- MySQL dump 10.13 Distrib 5.7.20, for Linux (x86_64) +-- +-- Host: localhost Database: arXiv +-- ------------------------------------------------------ +-- Server version 5.7.20 + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +SET @MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN; +SET @@SESSION.SQL_LOG_BIN= 0; + +-- +-- GTID state at the beginning of the backup +-- + +-- SET @@GLOBAL.GTID_PURGED='2d19f914-b050-11e7-95e6-005056a34791:1-572482257'; + +-- +-- Table structure for table `Subscription_UniversalInstitution` +-- + +DROP TABLE IF EXISTS `Subscription_UniversalInstitution`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `Subscription_UniversalInstitution` ( + `resolver_URL` varchar(255) DEFAULT NULL, + `name` varchar(255) NOT NULL, + `label` varchar(255) DEFAULT NULL, + `id` int(11) NOT NULL AUTO_INCREMENT, + `alt_text` varchar(255) DEFAULT NULL, + `link_icon` varchar(255) DEFAULT NULL, + `note` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `name` (`name`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `Subscription_UniversalInstitutionContact` +-- + +DROP TABLE IF EXISTS `Subscription_UniversalInstitutionContact`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `Subscription_UniversalInstitutionContact` ( + `email` varchar(255) DEFAULT NULL, + `sid` int(11) NOT NULL, + `active` tinyint(4) DEFAULT '0', + `contact_name` varchar(255) DEFAULT NULL, + `id` int(11) NOT NULL AUTO_INCREMENT, + `phone` varchar(255) DEFAULT NULL, + `note` varchar(2048) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `sid` (`sid`), + CONSTRAINT `Subscription_Institution_Contact_Universal` FOREIGN KEY (`sid`) REFERENCES `Subscription_UniversalInstitution` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `Subscription_UniversalInstitutionIP` +-- + +DROP TABLE IF EXISTS `Subscription_UniversalInstitutionIP`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `Subscription_UniversalInstitutionIP` ( + `sid` int(11) NOT NULL, + `id` int(11) NOT NULL AUTO_INCREMENT, + `exclude` tinyint(4) DEFAULT '0', + `end` bigint(20) NOT NULL, + `start` bigint(20) NOT NULL, + PRIMARY KEY (`id`), + KEY `sid` (`sid`), + KEY `ip` (`start`,`end`), + KEY `end` (`end`), + KEY `start` (`start`), + CONSTRAINT `Subscription_Institution_IP_Universal` FOREIGN KEY (`sid`) REFERENCES `Subscription_UniversalInstitution` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_admin_log` +-- + +DROP TABLE IF EXISTS `arXiv_admin_log`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_admin_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `logtime` varchar(24) DEFAULT NULL, + `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `paper_id` varchar(20) DEFAULT NULL, + `username` varchar(20) DEFAULT NULL, + `host` varchar(64) DEFAULT NULL, + `program` varchar(20) DEFAULT NULL, + `command` varchar(20) DEFAULT NULL, + `logtext` text, + `document_id` mediumint(8) unsigned DEFAULT NULL, + `submission_id` int(11) DEFAULT NULL, + `notify` tinyint(1) DEFAULT '0', + PRIMARY KEY (`id`), + KEY `arXiv_admin_log_idx_submission_id` (`submission_id`), + KEY `arXiv_admin_log_idx_command` (`command`), + KEY `arXiv_admin_log_idx_paper_id` (`paper_id`), + KEY `arXiv_admin_log_idx_username` (`username`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_admin_metadata` +-- + +DROP TABLE IF EXISTS `arXiv_admin_metadata`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_admin_metadata` ( + `metadata_id` int(11) NOT NULL AUTO_INCREMENT, + `document_id` mediumint(8) unsigned DEFAULT NULL, + `paper_id` varchar(64) DEFAULT NULL, + `created` datetime DEFAULT NULL, + `updated` datetime DEFAULT NULL, + `submitter_name` varchar(64) DEFAULT NULL, + `submitter_email` varchar(64) DEFAULT NULL, + `history` text, + `source_size` int(11) DEFAULT NULL, + `source_type` varchar(12) DEFAULT NULL, + `title` text, + `authors` text, + `category_string` varchar(255) DEFAULT NULL, + `comments` text, + `proxy` varchar(255) DEFAULT NULL, + `report_num` text, + `msc_class` varchar(255) DEFAULT NULL, + `acm_class` varchar(255) DEFAULT NULL, + `journal_ref` text, + `doi` varchar(255) DEFAULT NULL, + `abstract` text, + `license` varchar(255) DEFAULT NULL, + `version` int(11) NOT NULL DEFAULT '1', + `modtime` int(10) DEFAULT NULL, + `is_current` tinyint(1) DEFAULT '0', + PRIMARY KEY (`metadata_id`), + UNIQUE KEY `pidv` (`paper_id`,`version`), + KEY `id` (`metadata_id`), + KEY `document_id` (`document_id`), + CONSTRAINT `meta_doc_fk` FOREIGN KEY (`document_id`) REFERENCES `arXiv_documents` (`document_id`) ON DELETE CASCADE +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_admin_state` +-- + +DROP TABLE IF EXISTS `arXiv_admin_state`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_admin_state` ( + `document_id` int(11) DEFAULT NULL, + `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `abs_timestamp` int(11) DEFAULT NULL, + `src_timestamp` int(11) DEFAULT NULL, + `state` enum('pending','ok','bad') NOT NULL DEFAULT 'pending', + `admin` varchar(32) DEFAULT NULL, + `comment` varchar(255) DEFAULT NULL, + UNIQUE KEY `document_id` (`document_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_archive_category` +-- + +DROP TABLE IF EXISTS `arXiv_archive_category`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_archive_category` ( + `archive_id` varchar(16) NOT NULL DEFAULT '', + `category_id` varchar(32) NOT NULL, + PRIMARY KEY (`archive_id`,`category_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_archive_def` +-- + +DROP TABLE IF EXISTS `arXiv_archive_def`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_archive_def` ( + `archive` varchar(16) NOT NULL DEFAULT '', + `name` varchar(255) DEFAULT NULL, + PRIMARY KEY (`archive`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_archive_group` +-- + +DROP TABLE IF EXISTS `arXiv_archive_group`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_archive_group` ( + `archive_id` varchar(16) NOT NULL DEFAULT '', + `group_id` varchar(16) NOT NULL DEFAULT '', + PRIMARY KEY (`archive_id`,`group_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_archives` +-- + +DROP TABLE IF EXISTS `arXiv_archives`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_archives` ( + `archive_id` varchar(16) NOT NULL DEFAULT '', + `in_group` varchar(16) NOT NULL DEFAULT '', + `archive_name` varchar(255) NOT NULL DEFAULT '', + `start_date` varchar(4) NOT NULL DEFAULT '', + `end_date` varchar(4) NOT NULL DEFAULT '', + `subdivided` int(1) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`archive_id`), + KEY `in_group` (`in_group`), + CONSTRAINT `0_576` FOREIGN KEY (`in_group`) REFERENCES `arXiv_groups` (`group_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_author_ids` +-- + +DROP TABLE IF EXISTS `arXiv_author_ids`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_author_ids` ( + `user_id` int(4) unsigned NOT NULL, + `author_id` varchar(50) NOT NULL, + `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`user_id`), + KEY `author_id` (`author_id`), + CONSTRAINT `arXiv_author_ids_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_aws_config` +-- + +DROP TABLE IF EXISTS `arXiv_aws_config`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_aws_config` ( + `domain` varchar(75) NOT NULL, + `keyname` varchar(60) NOT NULL, + `value` varchar(150) DEFAULT NULL, + PRIMARY KEY (`domain`,`keyname`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_aws_files` +-- + +DROP TABLE IF EXISTS `arXiv_aws_files`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_aws_files` ( + `type` varchar(10) NOT NULL DEFAULT '', + `filename` varchar(100) NOT NULL DEFAULT '', + `md5sum` varchar(50) DEFAULT NULL, + `content_md5sum` varchar(50) DEFAULT NULL, + `size` int(11) DEFAULT NULL, + `timestamp` datetime DEFAULT NULL, + `yymm` varchar(4) DEFAULT NULL, + `seq_num` int(11) DEFAULT NULL, + `first_item` varchar(20) DEFAULT NULL, + `last_item` varchar(20) DEFAULT NULL, + `num_items` int(11) DEFAULT NULL, + PRIMARY KEY (`filename`), + KEY `type` (`type`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_bad_pw` +-- + +DROP TABLE IF EXISTS `arXiv_bad_pw`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_bad_pw` ( + `user_id` int(10) unsigned NOT NULL DEFAULT '0', + KEY `user_id` (`user_id`), + CONSTRAINT `0_601` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_bib_feeds` +-- + +DROP TABLE IF EXISTS `arXiv_bib_feeds`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_bib_feeds` ( + `bib_id` mediumint(8) NOT NULL AUTO_INCREMENT, + `name` varchar(64) NOT NULL DEFAULT '', + `priority` tinyint(1) NOT NULL DEFAULT '0', + `uri` varchar(255) DEFAULT NULL, + `identifier` varchar(255) DEFAULT NULL, + `version` varchar(255) DEFAULT NULL, + `strip_journal_ref` tinyint(1) NOT NULL DEFAULT '0', + `concatenate_dupes` int(11) DEFAULT NULL, + `max_updates` int(11) DEFAULT NULL, + `email_errors` varchar(255) DEFAULT NULL, + `prune_ids` text, + `prune_regex` text, + `enabled` tinyint(1) DEFAULT '0', + PRIMARY KEY (`bib_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_bib_updates` +-- + +DROP TABLE IF EXISTS `arXiv_bib_updates`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_bib_updates` ( + `update_id` mediumint(8) NOT NULL AUTO_INCREMENT, + `document_id` mediumint(8) NOT NULL DEFAULT '0', + `bib_id` mediumint(8) NOT NULL DEFAULT '0', + `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `journal_ref` text, + `doi` text, + PRIMARY KEY (`update_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_black_email` +-- + +DROP TABLE IF EXISTS `arXiv_black_email`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_black_email` ( + `pattern` varchar(64) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_block_email` +-- + +DROP TABLE IF EXISTS `arXiv_block_email`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_block_email` ( + `pattern` varchar(64) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_bogus_countries` +-- + +DROP TABLE IF EXISTS `arXiv_bogus_countries`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_bogus_countries` ( + `user_id` int(10) unsigned NOT NULL DEFAULT '0', + `country_name` varchar(255) NOT NULL DEFAULT '', + PRIMARY KEY (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_bogus_subject_class` +-- + +DROP TABLE IF EXISTS `arXiv_bogus_subject_class`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_bogus_subject_class` ( + `document_id` mediumint(8) unsigned NOT NULL DEFAULT '0', + `category_name` varchar(255) NOT NULL DEFAULT '', + KEY `document_id` (`document_id`), + CONSTRAINT `0_604` FOREIGN KEY (`document_id`) REFERENCES `arXiv_documents` (`document_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_categories` +-- + +DROP TABLE IF EXISTS `arXiv_categories`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_categories` ( + `archive` varchar(16) NOT NULL DEFAULT '', + `subject_class` varchar(16) NOT NULL DEFAULT '', + `definitive` int(1) NOT NULL DEFAULT '0', + `active` int(1) NOT NULL DEFAULT '0', + `category_name` varchar(255) DEFAULT NULL, + `endorse_all` enum('y','n','d') NOT NULL DEFAULT 'd', + `endorse_email` enum('y','n','d') NOT NULL DEFAULT 'd', + `papers_to_endorse` smallint(5) unsigned NOT NULL DEFAULT '0', + `endorsement_domain` varchar(32) DEFAULT NULL, + PRIMARY KEY (`archive`,`subject_class`), + KEY `endorsement_domain` (`endorsement_domain`), + CONSTRAINT `0_578` FOREIGN KEY (`archive`) REFERENCES `arXiv_archives` (`archive_id`), + CONSTRAINT `0_753` FOREIGN KEY (`endorsement_domain`) REFERENCES `arXiv_endorsement_domains` (`endorsement_domain`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_category_def` +-- + +DROP TABLE IF EXISTS `arXiv_category_def`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_category_def` ( + `category` varchar(32) NOT NULL, + `name` varchar(255) DEFAULT NULL, + `active` tinyint(1) DEFAULT '1', + PRIMARY KEY (`category`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_check_responses` +-- + +DROP TABLE IF EXISTS `arXiv_check_responses`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_check_responses` ( + `check_response_id` int(11) NOT NULL AUTO_INCREMENT, + `check_result_id` int(11) NOT NULL, + `user_id` int(10) unsigned NOT NULL, + `ok` tinyint(1) NOT NULL, + `persist_response` tinyint(1) NOT NULL DEFAULT '0', + `created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `message` varchar(200) DEFAULT NULL, + PRIMARY KEY (`check_response_id`), + KEY `check_responses_result_index` (`check_result_id`), + KEY `check_responses_user_index` (`user_id`), + CONSTRAINT `check_responses_results_fk` FOREIGN KEY (`check_result_id`) REFERENCES `arXiv_check_results` (`check_result_id`), + CONSTRAINT `check_responses_user_fk` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_check_result_views` +-- + +DROP TABLE IF EXISTS `arXiv_check_result_views`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_check_result_views` ( + `check_result_view_id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(40) NOT NULL, + `description` varchar(200) DEFAULT NULL, + PRIMARY KEY (`check_result_view_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_check_results` +-- + +DROP TABLE IF EXISTS `arXiv_check_results`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_check_results` ( + `check_result_id` int(11) NOT NULL AUTO_INCREMENT, + `submission_id` int(11) NOT NULL, + `data_version` int(11) NOT NULL DEFAULT '0', + `metadata_version` int(11) NOT NULL DEFAULT '0', + `check_id` int(11) NOT NULL, + `user_id` int(10) unsigned NOT NULL, + `ok` tinyint(1) NOT NULL, + `created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `message` varchar(40) DEFAULT NULL, + `data` varchar(2000) DEFAULT NULL, + PRIMARY KEY (`check_result_id`), + KEY `check_results_submission_index` (`submission_id`), + KEY `check_results_check_index` (`check_id`), + KEY `check_results_user_index` (`user_id`), + CONSTRAINT `check_results_checks_fk` FOREIGN KEY (`check_id`) REFERENCES `arXiv_checks` (`check_id`), + CONSTRAINT `check_results_sub_fk` FOREIGN KEY (`submission_id`) REFERENCES `arXiv_submissions` (`submission_id`), + CONSTRAINT `check_results_user_fk` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_check_roles` +-- + +DROP TABLE IF EXISTS `arXiv_check_roles`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_check_roles` ( + `check_role_id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(40) NOT NULL, + `description` varchar(200) DEFAULT NULL, + PRIMARY KEY (`check_role_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_check_targets` +-- + +DROP TABLE IF EXISTS `arXiv_check_targets`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_check_targets` ( + `check_target_id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(40) NOT NULL, + `description` varchar(200) DEFAULT NULL, + PRIMARY KEY (`check_target_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_checks` +-- + +DROP TABLE IF EXISTS `arXiv_checks`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_checks` ( + `check_id` int(11) NOT NULL AUTO_INCREMENT, + `check_target_id` int(11) NOT NULL, + `check_role_id` int(11) NOT NULL, + `check_result_view_id` int(11) NOT NULL DEFAULT '1', + `name` varchar(40) NOT NULL, + `description` varchar(200) DEFAULT NULL, + `enable_check` tinyint(1) NOT NULL DEFAULT '0', + `enable_hold` tinyint(1) NOT NULL DEFAULT '0', + `enable_queue` tinyint(1) NOT NULL DEFAULT '0', + `retry_minutes` smallint(6) NOT NULL DEFAULT '0', + `optional` tinyint(1) NOT NULL DEFAULT '1', + `persist_response` tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`check_id`), + KEY `checks_content_fk` (`check_target_id`), + KEY `checks_roles_fk` (`check_role_id`), + KEY `checks_result_views_fk` (`check_result_view_id`), + CONSTRAINT `checks_content_fk` FOREIGN KEY (`check_target_id`) REFERENCES `arXiv_check_targets` (`check_target_id`), + CONSTRAINT `checks_result_views_fk` FOREIGN KEY (`check_result_view_id`) REFERENCES `arXiv_check_result_views` (`check_result_view_id`), + CONSTRAINT `checks_roles_fk` FOREIGN KEY (`check_role_id`) REFERENCES `arXiv_check_roles` (`check_role_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_control_holds` +-- + +DROP TABLE IF EXISTS `arXiv_control_holds`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_control_holds` ( + `hold_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `control_id` int(10) unsigned NOT NULL DEFAULT '0', + `hold_type` enum('submission','cross','jref') NOT NULL DEFAULT 'submission', + `hold_status` enum('held','extended','accepted','rejected') NOT NULL DEFAULT 'held', + `hold_reason` varchar(255) NOT NULL DEFAULT '', + `hold_data` varchar(255) NOT NULL DEFAULT '', + `origin` enum('auto','user','admin','moderator') NOT NULL DEFAULT 'auto', + `placed_by` int(10) unsigned DEFAULT NULL, + `last_changed_by` int(10) unsigned DEFAULT NULL, + PRIMARY KEY (`hold_id`), + UNIQUE KEY `control_id` (`control_id`,`hold_type`), + KEY `hold_type` (`hold_type`), + KEY `hold_status` (`hold_status`), + KEY `hold_reason` (`hold_reason`), + KEY `origin` (`origin`), + KEY `placed_by` (`placed_by`), + KEY `last_changed_by` (`last_changed_by`), + CONSTRAINT `arXiv_control_holds_ibfk_1` FOREIGN KEY (`placed_by`) REFERENCES `tapir_users` (`user_id`), + CONSTRAINT `arXiv_control_holds_ibfk_2` FOREIGN KEY (`last_changed_by`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_cross_control` +-- + +DROP TABLE IF EXISTS `arXiv_cross_control`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_cross_control` ( + `control_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `document_id` mediumint(8) unsigned NOT NULL DEFAULT '0', + `version` tinyint(3) unsigned NOT NULL DEFAULT '0', + `desired_order` tinyint(3) unsigned NOT NULL DEFAULT '0', + `user_id` int(10) unsigned NOT NULL DEFAULT '0', + `status` enum('new','frozen','published','rejected') NOT NULL DEFAULT 'new', + `flag_must_notify` enum('0','1') DEFAULT '1', + `archive` varchar(16) NOT NULL DEFAULT '', + `subject_class` varchar(16) NOT NULL DEFAULT '', + `request_date` int(10) unsigned NOT NULL DEFAULT '0', + `freeze_date` int(10) unsigned NOT NULL DEFAULT '0', + `publish_date` int(10) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`control_id`), + KEY `status` (`status`), + KEY `freeze_date` (`freeze_date`), + KEY `document_id` (`document_id`,`version`), + KEY `archive` (`archive`,`subject_class`), + KEY `user_id` (`user_id`), + CONSTRAINT `arXiv_cross_control_ibfk_1` FOREIGN KEY (`document_id`) REFERENCES `arXiv_documents` (`document_id`), + CONSTRAINT `arXiv_cross_control_ibfk_2` FOREIGN KEY (`archive`, `subject_class`) REFERENCES `arXiv_categories` (`archive`, `subject_class`), + CONSTRAINT `arXiv_cross_control_ibfk_3` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_datacite_dois` +-- + +DROP TABLE IF EXISTS `arXiv_datacite_dois`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_datacite_dois` ( + `doi` varchar(255) NOT NULL, + `account` enum('test','prod') DEFAULT NULL, + `metadata_id` int(11) NOT NULL, + `paper_id` varchar(64) NOT NULL, + `created` datetime DEFAULT CURRENT_TIMESTAMP, + `updated` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`doi`), + UNIQUE KEY `account_paper_id` (`account`,`paper_id`), + KEY `metadata_id` (`metadata_id`), + CONSTRAINT `arXiv_datacite_dois_ibfk_1` FOREIGN KEY (`metadata_id`) REFERENCES `arXiv_metadata` (`metadata_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_dblp` +-- + +DROP TABLE IF EXISTS `arXiv_dblp`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_dblp` ( + `document_id` mediumint(8) unsigned NOT NULL DEFAULT '0', + `url` varchar(80) DEFAULT NULL, + PRIMARY KEY (`document_id`), + CONSTRAINT `arXiv_DBLP_cdfk1` FOREIGN KEY (`document_id`) REFERENCES `arXiv_documents` (`document_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_dblp_authors` +-- + +DROP TABLE IF EXISTS `arXiv_dblp_authors`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_dblp_authors` ( + `author_id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(40) DEFAULT NULL, + PRIMARY KEY (`author_id`), + UNIQUE KEY `author_id` (`author_id`), + UNIQUE KEY `name` (`name`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_dblp_document_authors` +-- + +DROP TABLE IF EXISTS `arXiv_dblp_document_authors`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_dblp_document_authors` ( + `document_id` mediumint(8) unsigned NOT NULL, + `author_id` mediumint(8) unsigned NOT NULL DEFAULT '0', + `position` tinyint(4) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`document_id`,`author_id`), + KEY `document_id` (`document_id`), + KEY `author_id` (`author_id`), + CONSTRAINT `arXiv_DBLP_abfk1` FOREIGN KEY (`document_id`) REFERENCES `arXiv_documents` (`document_id`), + CONSTRAINT `arXiv_DBLP_ibfk2` FOREIGN KEY (`author_id`) REFERENCES `arXiv_dblp_authors` (`author_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_demographics` +-- + +DROP TABLE IF EXISTS `arXiv_demographics`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_demographics` ( + `user_id` int(10) unsigned NOT NULL DEFAULT '0', + `country` char(2) NOT NULL DEFAULT '', + `affiliation` varchar(255) NOT NULL DEFAULT '', + `url` varchar(255) NOT NULL DEFAULT '', + `type` smallint(5) unsigned DEFAULT NULL, + `archive` varchar(16) DEFAULT NULL, + `subject_class` varchar(16) DEFAULT NULL, + `original_subject_classes` varchar(255) NOT NULL DEFAULT '', + `flag_group_physics` int(1) unsigned DEFAULT NULL, + `flag_group_math` int(1) unsigned NOT NULL DEFAULT '0', + `flag_group_cs` int(1) unsigned NOT NULL DEFAULT '0', + `flag_group_nlin` int(1) unsigned NOT NULL DEFAULT '0', + `flag_proxy` int(1) unsigned NOT NULL DEFAULT '0', + `flag_journal` int(1) unsigned NOT NULL DEFAULT '0', + `flag_xml` int(1) unsigned NOT NULL DEFAULT '0', + `dirty` int(1) unsigned NOT NULL DEFAULT '2', + `flag_group_test` int(1) unsigned NOT NULL DEFAULT '0', + `flag_suspect` int(1) unsigned NOT NULL DEFAULT '0', + `flag_group_q_bio` int(1) unsigned NOT NULL DEFAULT '0', + `flag_group_q_fin` int(1) unsigned NOT NULL DEFAULT '0', + `flag_group_stat` int(1) unsigned NOT NULL DEFAULT '0', + `flag_group_eess` int(1) unsigned NOT NULL DEFAULT '0', + `flag_group_econ` int(1) unsigned NOT NULL DEFAULT '0', + `veto_status` enum('ok','no-endorse','no-upload','no-replace') NOT NULL DEFAULT 'ok', + PRIMARY KEY (`user_id`), + KEY `country` (`country`), + KEY `type` (`type`), + KEY `archive` (`archive`,`subject_class`), + KEY `flag_group_physics` (`flag_group_physics`), + KEY `flag_group_math` (`flag_group_math`), + KEY `flag_group_cs` (`flag_group_cs`), + KEY `flag_group_nlin` (`flag_group_nlin`), + KEY `flag_proxy` (`flag_proxy`), + KEY `flag_journal` (`flag_journal`), + KEY `flag_xml` (`flag_xml`), + KEY `flag_group_stat` (`flag_group_stat`), + KEY `flag_group_q_bio` (`flag_group_q_bio`), + KEY `flag_group_q_fin` (`flag_group_q_fin`), + KEY `flag_suspect` (`flag_suspect`), + KEY `flag_group_eess` (`flag_group_eess`), + KEY `flag_group_econ` (`flag_group_econ`), + CONSTRAINT `0_587` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`), + CONSTRAINT `0_588` FOREIGN KEY (`archive`, `subject_class`) REFERENCES `arXiv_categories` (`archive`, `subject_class`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_document_category` +-- + +DROP TABLE IF EXISTS `arXiv_document_category`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_document_category` ( + `document_id` mediumint(8) unsigned NOT NULL DEFAULT '0', + `category` varchar(32) NOT NULL, + `is_primary` tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`document_id`,`category`), + KEY `document_id` (`document_id`), + KEY `category` (`category`), + CONSTRAINT `doc_cat_cat` FOREIGN KEY (`category`) REFERENCES `arXiv_category_def` (`category`), + CONSTRAINT `doc_cat_doc` FOREIGN KEY (`document_id`) REFERENCES `arXiv_documents` (`document_id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_documents` +-- + +DROP TABLE IF EXISTS `arXiv_documents`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_documents` ( + `document_id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, + `paper_id` varchar(20) NOT NULL DEFAULT '', + `title` varchar(255) NOT NULL DEFAULT '', + `authors` text, + `submitter_email` varchar(64) NOT NULL DEFAULT '', + `submitter_id` int(10) unsigned DEFAULT NULL, + `dated` int(10) unsigned NOT NULL DEFAULT '0', + `primary_subject_class` varchar(16) DEFAULT NULL, + `created` datetime DEFAULT NULL, + PRIMARY KEY (`document_id`), + UNIQUE KEY `paper_id` (`paper_id`), + KEY `dated` (`dated`), + KEY `title` (`title`), + KEY `submitter_id` (`submitter_id`), + KEY `submitter_email` (`submitter_email`), + CONSTRAINT `0_580` FOREIGN KEY (`submitter_id`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_duplicates` +-- + +DROP TABLE IF EXISTS `arXiv_duplicates`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_duplicates` ( + `user_id` int(10) unsigned NOT NULL DEFAULT '0', + `email` varchar(255) DEFAULT NULL, + `username` varchar(255) DEFAULT NULL, + KEY `user_id` (`user_id`), + CONSTRAINT `0_599` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_endorsement_domains` +-- + +DROP TABLE IF EXISTS `arXiv_endorsement_domains`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_endorsement_domains` ( + `endorsement_domain` varchar(32) NOT NULL DEFAULT '', + `endorse_all` enum('y','n') NOT NULL DEFAULT 'n', + `mods_endorse_all` enum('y','n') NOT NULL DEFAULT 'n', + `endorse_email` enum('y','n') NOT NULL DEFAULT 'y', + `papers_to_endorse` smallint(5) unsigned NOT NULL DEFAULT '4', + PRIMARY KEY (`endorsement_domain`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_endorsement_requests` +-- + +DROP TABLE IF EXISTS `arXiv_endorsement_requests`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_endorsement_requests` ( + `request_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `endorsee_id` int(10) unsigned NOT NULL DEFAULT '0', + `archive` varchar(16) NOT NULL DEFAULT '', + `subject_class` varchar(16) NOT NULL DEFAULT '', + `secret` varchar(16) NOT NULL DEFAULT '', + `flag_valid` int(1) unsigned NOT NULL DEFAULT '0', + `issued_when` int(10) unsigned NOT NULL DEFAULT '0', + `point_value` int(10) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`request_id`), + UNIQUE KEY `secret` (`secret`), + UNIQUE KEY `endorsee_id_2` (`endorsee_id`,`archive`,`subject_class`), + KEY `endorsee_id` (`endorsee_id`), + KEY `archive` (`archive`,`subject_class`), + CONSTRAINT `0_722` FOREIGN KEY (`endorsee_id`) REFERENCES `tapir_users` (`user_id`), + CONSTRAINT `0_723` FOREIGN KEY (`archive`, `subject_class`) REFERENCES `arXiv_categories` (`archive`, `subject_class`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_endorsement_requests_audit` +-- + +DROP TABLE IF EXISTS `arXiv_endorsement_requests_audit`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_endorsement_requests_audit` ( + `request_id` int(10) unsigned NOT NULL DEFAULT '0', + `session_id` int(10) unsigned NOT NULL DEFAULT '0', + `remote_addr` varchar(16) DEFAULT NULL, + `remote_host` varchar(255) DEFAULT NULL, + `tracking_cookie` varchar(255) DEFAULT NULL, + PRIMARY KEY (`request_id`), + CONSTRAINT `0_725` FOREIGN KEY (`request_id`) REFERENCES `arXiv_endorsement_requests` (`request_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_endorsements` +-- + +DROP TABLE IF EXISTS `arXiv_endorsements`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_endorsements` ( + `endorsement_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `endorser_id` int(10) unsigned DEFAULT NULL, + `endorsee_id` int(10) unsigned NOT NULL DEFAULT '0', + `archive` varchar(16) NOT NULL DEFAULT '', + `subject_class` varchar(16) NOT NULL DEFAULT '', + `flag_valid` int(1) unsigned NOT NULL DEFAULT '0', + `type` enum('user','admin','auto') DEFAULT NULL, + `point_value` int(1) unsigned NOT NULL DEFAULT '0', + `issued_when` int(10) unsigned NOT NULL DEFAULT '0', + `request_id` int(10) unsigned DEFAULT NULL, + PRIMARY KEY (`endorsement_id`), + UNIQUE KEY `endorser_id_2` (`endorser_id`,`endorsee_id`,`archive`,`subject_class`), + KEY `endorser_id` (`endorser_id`), + KEY `endorsee_id` (`endorsee_id`), + KEY `archive` (`archive`,`subject_class`), + KEY `request_id` (`request_id`), + CONSTRAINT `0_727` FOREIGN KEY (`endorser_id`) REFERENCES `tapir_users` (`user_id`), + CONSTRAINT `0_728` FOREIGN KEY (`endorsee_id`) REFERENCES `tapir_users` (`user_id`), + CONSTRAINT `0_729` FOREIGN KEY (`archive`, `subject_class`) REFERENCES `arXiv_categories` (`archive`, `subject_class`), + CONSTRAINT `0_730` FOREIGN KEY (`request_id`) REFERENCES `arXiv_endorsement_requests` (`request_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_endorsements_audit` +-- + +DROP TABLE IF EXISTS `arXiv_endorsements_audit`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_endorsements_audit` ( + `endorsement_id` int(10) unsigned NOT NULL DEFAULT '0', + `session_id` int(10) unsigned NOT NULL DEFAULT '0', + `remote_addr` varchar(16) NOT NULL DEFAULT '', + `remote_host` varchar(255) NOT NULL DEFAULT '', + `tracking_cookie` varchar(255) NOT NULL DEFAULT '', + `flag_knows_personally` int(1) unsigned NOT NULL DEFAULT '0', + `flag_seen_paper` int(1) unsigned NOT NULL DEFAULT '0', + `comment` text, + PRIMARY KEY (`endorsement_id`), + CONSTRAINT `0_732` FOREIGN KEY (`endorsement_id`) REFERENCES `arXiv_endorsements` (`endorsement_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_freeze_log` +-- + +DROP TABLE IF EXISTS `arXiv_freeze_log`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_freeze_log` ( + `date` int(10) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`date`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_group_def` +-- + +DROP TABLE IF EXISTS `arXiv_group_def`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_group_def` ( + `archive_group` varchar(16) NOT NULL DEFAULT '', + `name` varchar(255) DEFAULT NULL, + PRIMARY KEY (`archive_group`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_groups` +-- + +DROP TABLE IF EXISTS `arXiv_groups`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_groups` ( + `group_id` varchar(16) NOT NULL DEFAULT '', + `group_name` varchar(255) NOT NULL DEFAULT '', + `start_year` varchar(4) NOT NULL DEFAULT '', + PRIMARY KEY (`group_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_in_category` +-- + +DROP TABLE IF EXISTS `arXiv_in_category`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_in_category` ( + `document_id` mediumint(8) unsigned NOT NULL DEFAULT '0', + `archive` varchar(16) NOT NULL DEFAULT '', + `subject_class` varchar(16) NOT NULL DEFAULT '', + `is_primary` tinyint(1) NOT NULL DEFAULT '0', + UNIQUE KEY `archive` (`archive`,`subject_class`,`document_id`), + KEY `document_id` (`document_id`), + KEY `arXiv_in_category_mp` (`archive`,`subject_class`), + CONSTRAINT `0_582` FOREIGN KEY (`document_id`) REFERENCES `arXiv_documents` (`document_id`), + CONSTRAINT `0_583` FOREIGN KEY (`archive`, `subject_class`) REFERENCES `arXiv_categories` (`archive`, `subject_class`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_jref_control` +-- + +DROP TABLE IF EXISTS `arXiv_jref_control`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_jref_control` ( + `control_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `document_id` mediumint(8) unsigned NOT NULL DEFAULT '0', + `version` tinyint(3) unsigned NOT NULL DEFAULT '0', + `user_id` int(10) unsigned NOT NULL DEFAULT '0', + `status` enum('new','frozen','published','rejected') NOT NULL DEFAULT 'new', + `flag_must_notify` enum('0','1') DEFAULT '1', + `jref` varchar(255) NOT NULL DEFAULT '', + `request_date` int(10) unsigned NOT NULL DEFAULT '0', + `freeze_date` int(10) unsigned NOT NULL DEFAULT '0', + `publish_date` int(10) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`control_id`), + UNIQUE KEY `document_id` (`document_id`,`version`), + KEY `freeze_date` (`freeze_date`), + KEY `status` (`status`), + KEY `user_id` (`user_id`), + CONSTRAINT `arXiv_jref_control_ibfk_1` FOREIGN KEY (`document_id`) REFERENCES `arXiv_documents` (`document_id`), + CONSTRAINT `arXiv_jref_control_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_licenses` +-- + +DROP TABLE IF EXISTS `arXiv_licenses`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_licenses` ( + `name` varchar(255) NOT NULL, + `label` varchar(255) DEFAULT NULL, + `active` tinyint(1) DEFAULT '1', + `note` varchar(400) DEFAULT NULL, + `sequence` tinyint(4) DEFAULT NULL, + PRIMARY KEY (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_log_positions` +-- + +DROP TABLE IF EXISTS `arXiv_log_positions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_log_positions` ( + `id` varchar(255) NOT NULL DEFAULT '', + `position` int(10) unsigned DEFAULT NULL, + `date` int(10) unsigned DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_metadata` +-- + +DROP TABLE IF EXISTS `arXiv_metadata`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_metadata` ( + `metadata_id` int(11) NOT NULL AUTO_INCREMENT, + `document_id` mediumint(8) unsigned NOT NULL DEFAULT '0', + `paper_id` varchar(64) NOT NULL, + `created` datetime DEFAULT NULL, + `updated` datetime DEFAULT NULL, + `submitter_id` int(4) unsigned DEFAULT NULL, + `submitter_name` varchar(64) NOT NULL, + `submitter_email` varchar(64) NOT NULL, + `source_size` int(11) DEFAULT NULL, + `source_format` varchar(12) DEFAULT NULL, + `source_flags` varchar(12) DEFAULT NULL, + `title` text, + `authors` text, + `abs_categories` varchar(255) DEFAULT NULL, + `comments` text, + `proxy` varchar(255) DEFAULT NULL, + `report_num` text, + `msc_class` varchar(255) DEFAULT NULL, + `acm_class` varchar(255) DEFAULT NULL, + `journal_ref` text, + `doi` varchar(255) DEFAULT NULL, + `abstract` text, + `license` varchar(255) DEFAULT NULL, + `version` int(4) NOT NULL DEFAULT '1', + `modtime` int(11) DEFAULT NULL, + `is_current` tinyint(1) DEFAULT '1', + `is_withdrawn` tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`metadata_id`), + UNIQUE KEY `pidv` (`paper_id`,`version`), + KEY `arXiv_metadata_idx_document_id` (`document_id`), + KEY `arXiv_metadata_idx_license` (`license`), + KEY `arXiv_metadata_idx_submitter_id` (`submitter_id`), + CONSTRAINT `arXiv_metadata_fk_document_id` FOREIGN KEY (`document_id`) REFERENCES `arXiv_documents` (`document_id`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `arXiv_metadata_fk_license` FOREIGN KEY (`license`) REFERENCES `arXiv_licenses` (`name`), + CONSTRAINT `arXiv_metadata_fk_submitter_id` FOREIGN KEY (`submitter_id`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_mirror_list` +-- + +DROP TABLE IF EXISTS `arXiv_mirror_list`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_mirror_list` ( + `mirror_list_id` int(11) NOT NULL AUTO_INCREMENT, + `created` datetime DEFAULT NULL, + `updated` datetime DEFAULT NULL, + `document_id` mediumint(8) unsigned NOT NULL DEFAULT '0', + `version` int(4) NOT NULL DEFAULT '1', + `write_source` tinyint(1) NOT NULL DEFAULT '0', + `write_abs` tinyint(1) NOT NULL DEFAULT '0', + `is_written` tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`mirror_list_id`), + KEY `arXiv_mirror_list_idx_document_id` (`document_id`), + CONSTRAINT `arXiv_mirror_list_fk_document_id` FOREIGN KEY (`document_id`) REFERENCES `arXiv_documents` (`document_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_moderator_api_key` +-- + +DROP TABLE IF EXISTS `arXiv_moderator_api_key`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_moderator_api_key` ( + `user_id` int(4) unsigned NOT NULL DEFAULT '0', + `secret` varchar(32) NOT NULL DEFAULT '', + `valid` int(1) NOT NULL DEFAULT '1', + `issued_when` int(4) unsigned NOT NULL DEFAULT '0', + `issued_to` varchar(16) NOT NULL DEFAULT '', + `remote_host` varchar(255) NOT NULL DEFAULT '', + PRIMARY KEY (`user_id`,`secret`), + CONSTRAINT `arXiv_moderator_api_key_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_moderators` +-- + +DROP TABLE IF EXISTS `arXiv_moderators`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_moderators` ( + `user_id` int(10) unsigned NOT NULL DEFAULT '0', + `archive` varchar(16) NOT NULL DEFAULT '', + `subject_class` varchar(16) NOT NULL DEFAULT '', + `is_public` tinyint(4) NOT NULL DEFAULT '0', + `no_email` tinyint(1) DEFAULT '0', + `no_web_email` tinyint(1) DEFAULT '0', + `no_reply_to` tinyint(1) DEFAULT '0', + `daily_update` tinyint(1) DEFAULT '0', + UNIQUE KEY `user_id` (`archive`,`subject_class`,`user_id`), + KEY `user_id_2` (`user_id`), + KEY `arXiv_moderators_idx_no_email` (`no_email`), + KEY `arXiv_moderators_idx_no_web_email` (`no_web_email`), + KEY `arXiv_moderators_idx_no_reply_to` (`no_reply_to`), + CONSTRAINT `0_590` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`), + CONSTRAINT `0_591` FOREIGN KEY (`archive`, `subject_class`) REFERENCES `arXiv_categories` (`archive`, `subject_class`), + CONSTRAINT `fk_archive_id` FOREIGN KEY (`archive`) REFERENCES `arXiv_archive_group` (`archive_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_monitor_klog` +-- + +DROP TABLE IF EXISTS `arXiv_monitor_klog`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_monitor_klog` ( + `t` int(10) unsigned NOT NULL DEFAULT '0', + `sent` int(10) unsigned DEFAULT NULL, + PRIMARY KEY (`t`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_monitor_mailq` +-- + +DROP TABLE IF EXISTS `arXiv_monitor_mailq`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_monitor_mailq` ( + `t` int(10) unsigned NOT NULL DEFAULT '0', + `main_q` int(10) unsigned NOT NULL DEFAULT '0', + `local_q` int(10) unsigned NOT NULL DEFAULT '0', + `local_host_map` int(10) unsigned NOT NULL DEFAULT '0', + `local_timeout` int(10) unsigned NOT NULL DEFAULT '0', + `local_refused` int(10) unsigned NOT NULL DEFAULT '0', + `local_in_flight` int(10) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`t`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_monitor_mailsent` +-- + +DROP TABLE IF EXISTS `arXiv_monitor_mailsent`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_monitor_mailsent` ( + `t` int(10) unsigned NOT NULL DEFAULT '0', + `sent` int(10) unsigned DEFAULT NULL, + PRIMARY KEY (`t`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_next_mail` +-- + +DROP TABLE IF EXISTS `arXiv_next_mail`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_next_mail` ( + `next_mail_id` int(11) NOT NULL AUTO_INCREMENT, + `submission_id` int(11) NOT NULL, + `document_id` mediumint(8) unsigned NOT NULL DEFAULT '0', + `paper_id` varchar(20) DEFAULT NULL, + `version` int(4) NOT NULL DEFAULT '1', + `type` varchar(255) NOT NULL DEFAULT 'new', + `extra` varchar(255) DEFAULT NULL, + `mail_id` char(6) DEFAULT NULL, + `is_written` tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`next_mail_id`), + KEY `arXiv_next_mail_idx_document_id` (`document_id`), + KEY `arXiv_next_mail_idx_document_id_version` (`document_id`,`version`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_orcid_config` +-- + +DROP TABLE IF EXISTS `arXiv_orcid_config`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_orcid_config` ( + `domain` varchar(75) NOT NULL, + `keyname` varchar(60) NOT NULL, + `value` varchar(150) DEFAULT NULL, + PRIMARY KEY (`domain`,`keyname`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_orcid_ids` +-- + +DROP TABLE IF EXISTS `arXiv_orcid_ids`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_orcid_ids` ( + `user_id` int(4) unsigned NOT NULL, + `orcid` varchar(19) NOT NULL, + `authenticated` tinyint(1) NOT NULL DEFAULT '0', + `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`user_id`), + KEY `orcid` (`orcid`), + CONSTRAINT `arXiv_orcid_ids_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_ownership_requests` +-- + +DROP TABLE IF EXISTS `arXiv_ownership_requests`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_ownership_requests` ( + `request_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `user_id` int(10) unsigned NOT NULL DEFAULT '0', + `endorsement_request_id` int(10) unsigned DEFAULT NULL, + `workflow_status` enum('pending','accepted','rejected') NOT NULL DEFAULT 'pending', + PRIMARY KEY (`request_id`), + KEY `user_id` (`user_id`), + KEY `endorsement_request_id` (`endorsement_request_id`), + CONSTRAINT `0_734` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`), + CONSTRAINT `0_735` FOREIGN KEY (`endorsement_request_id`) REFERENCES `arXiv_endorsement_requests` (`request_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_ownership_requests_audit` +-- + +DROP TABLE IF EXISTS `arXiv_ownership_requests_audit`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_ownership_requests_audit` ( + `request_id` int(10) unsigned NOT NULL DEFAULT '0', + `session_id` int(10) unsigned NOT NULL DEFAULT '0', + `remote_addr` varchar(16) NOT NULL DEFAULT '', + `remote_host` varchar(255) NOT NULL DEFAULT '', + `tracking_cookie` varchar(255) NOT NULL DEFAULT '', + `date` int(10) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`request_id`), + CONSTRAINT `0_737` FOREIGN KEY (`request_id`) REFERENCES `arXiv_ownership_requests` (`request_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_ownership_requests_papers` +-- + +DROP TABLE IF EXISTS `arXiv_ownership_requests_papers`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_ownership_requests_papers` ( + `request_id` int(10) unsigned NOT NULL DEFAULT '0', + `document_id` int(10) unsigned NOT NULL DEFAULT '0', + UNIQUE KEY `request_id` (`request_id`,`document_id`), + KEY `document_id` (`document_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_paper_owners` +-- + +DROP TABLE IF EXISTS `arXiv_paper_owners`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_paper_owners` ( + `document_id` mediumint(8) unsigned NOT NULL DEFAULT '0', + `user_id` int(10) unsigned NOT NULL DEFAULT '0', + `date` int(10) unsigned NOT NULL DEFAULT '0', + `added_by` int(10) unsigned NOT NULL DEFAULT '0', + `remote_addr` varchar(16) NOT NULL DEFAULT '', + `remote_host` varchar(255) NOT NULL DEFAULT '', + `tracking_cookie` varchar(32) NOT NULL DEFAULT '', + `valid` int(1) unsigned NOT NULL DEFAULT '0', + `flag_author` int(1) unsigned NOT NULL DEFAULT '0', + `flag_auto` int(1) unsigned NOT NULL DEFAULT '1', + UNIQUE KEY `document_id` (`document_id`,`user_id`), + KEY `user_id` (`user_id`), + KEY `added_by` (`added_by`), + CONSTRAINT `0_593` FOREIGN KEY (`document_id`) REFERENCES `arXiv_documents` (`document_id`), + CONSTRAINT `0_594` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`), + CONSTRAINT `0_595` FOREIGN KEY (`added_by`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_paper_pw` +-- + +DROP TABLE IF EXISTS `arXiv_paper_pw`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_paper_pw` ( + `document_id` mediumint(8) unsigned NOT NULL DEFAULT '0', + `password_storage` int(1) unsigned DEFAULT NULL, + `password_enc` varchar(50) DEFAULT NULL, + PRIMARY KEY (`document_id`), + CONSTRAINT `0_585` FOREIGN KEY (`document_id`) REFERENCES `arXiv_documents` (`document_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_paper_sessions` +-- + +DROP TABLE IF EXISTS `arXiv_paper_sessions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_paper_sessions` ( + `paper_session_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `paper_id` varchar(16) NOT NULL DEFAULT '', + `start_time` int(10) unsigned NOT NULL DEFAULT '0', + `end_time` int(10) unsigned NOT NULL DEFAULT '0', + `ip_name` varchar(16) NOT NULL DEFAULT '', + PRIMARY KEY (`paper_session_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_pilot_datasets` +-- + +DROP TABLE IF EXISTS `arXiv_pilot_datasets`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_pilot_datasets` ( + `submission_id` int(11) NOT NULL, + `numfiles` smallint(4) unsigned DEFAULT '0', + `feed_url` varchar(256) DEFAULT NULL, + `manifestation` varchar(256) DEFAULT NULL, + `published` tinyint(1) DEFAULT '0', + `created` datetime NOT NULL, + `last_checked` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`submission_id`), + CONSTRAINT `arXiv_pilot_datasets_cdfk3` FOREIGN KEY (`submission_id`) REFERENCES `arXiv_submissions` (`submission_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_pilot_files` +-- + +DROP TABLE IF EXISTS `arXiv_pilot_files`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_pilot_files` ( + `file_id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `submission_id` int(11) NOT NULL, + `filename` varchar(256) DEFAULT '', + `entity_url` varchar(256) DEFAULT NULL, + `description` varchar(80) DEFAULT NULL, + `byRef` tinyint(1) DEFAULT '1', + PRIMARY KEY (`file_id`), + KEY `arXiv_pilot_files_cdfk3` (`submission_id`), + CONSTRAINT `arXiv_pilot_files_cdfk3` FOREIGN KEY (`submission_id`) REFERENCES `arXiv_submissions` (`submission_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_publish_log` +-- + +DROP TABLE IF EXISTS `arXiv_publish_log`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_publish_log` ( + `date` int(10) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`date`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_questionable_categories` +-- + +DROP TABLE IF EXISTS `arXiv_questionable_categories`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_questionable_categories` ( + `archive` varchar(16) NOT NULL DEFAULT '', + `subject_class` varchar(16) NOT NULL DEFAULT '', + PRIMARY KEY (`archive`,`subject_class`), + CONSTRAINT `0_756` FOREIGN KEY (`archive`, `subject_class`) REFERENCES `arXiv_categories` (`archive`, `subject_class`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_queue_view` +-- + +DROP TABLE IF EXISTS `arXiv_queue_view`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_queue_view` ( + `user_id` int(4) unsigned NOT NULL DEFAULT '0', + `last_view` datetime DEFAULT NULL, + `second_last_view` datetime DEFAULT NULL, + `total_views` int(3) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`user_id`), + CONSTRAINT `arXiv_queue_view_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_refresh_list` +-- + +DROP TABLE IF EXISTS `arXiv_refresh_list`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_refresh_list` ( + `filename` varchar(255) DEFAULT NULL, + `mtime` int(10) unsigned DEFAULT NULL, + KEY `arXiv_refresh_list_mtime` (`mtime`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_reject_session_usernames` +-- + +DROP TABLE IF EXISTS `arXiv_reject_session_usernames`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_reject_session_usernames` ( + `username` varchar(64) NOT NULL DEFAULT '', + PRIMARY KEY (`username`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_sciencewise_pings` +-- + +DROP TABLE IF EXISTS `arXiv_sciencewise_pings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_sciencewise_pings` ( + `paper_id_v` varchar(32) NOT NULL, + `updated` datetime DEFAULT NULL, + PRIMARY KEY (`paper_id_v`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_show_email_requests` +-- + +DROP TABLE IF EXISTS `arXiv_show_email_requests`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_show_email_requests` ( + `document_id` mediumint(8) unsigned NOT NULL DEFAULT '0', + `user_id` int(10) unsigned NOT NULL DEFAULT '0', + `session_id` int(10) unsigned NOT NULL DEFAULT '0', + `dated` int(10) unsigned NOT NULL DEFAULT '0', + `flag_allowed` tinyint(3) unsigned NOT NULL DEFAULT '0', + `remote_addr` varchar(16) NOT NULL DEFAULT '', + `remote_host` varchar(255) NOT NULL DEFAULT '', + `tracking_cookie` varchar(255) NOT NULL DEFAULT '', + `request_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`request_id`), + KEY `document_id` (`document_id`), + KEY `user_id` (`user_id`,`dated`), + KEY `dated` (`dated`), + KEY `remote_addr` (`remote_addr`), + CONSTRAINT `arXiv_show_email_requests_ibfk_1` FOREIGN KEY (`document_id`) REFERENCES `arXiv_documents` (`document_id`), + CONSTRAINT `arXiv_show_email_requests_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_state` +-- + +DROP TABLE IF EXISTS `arXiv_state`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_state` ( + `id` int(11) NOT NULL, + `name` varchar(24) DEFAULT NULL, + `value` varchar(24) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_stats_hourly` +-- + +DROP TABLE IF EXISTS `arXiv_stats_hourly`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_stats_hourly` ( + `ymd` date NOT NULL, + `hour` tinyint(3) unsigned NOT NULL, + `node_num` tinyint(3) unsigned NOT NULL, + `access_type` char(1) NOT NULL, + `connections` int(4) unsigned NOT NULL, + KEY `arXiv_stats_hourly_idx_ymd` (`ymd`), + KEY `arXiv_stats_hourly_idx_hour` (`hour`), + KEY `arXiv_stats_hourly_idx_node_num` (`node_num`), + KEY `arXiv_stats_hourly_idx_access_type` (`access_type`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_stats_monthly_downloads` +-- + +DROP TABLE IF EXISTS `arXiv_stats_monthly_downloads`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_stats_monthly_downloads` ( + `ym` date NOT NULL, + `downloads` int(10) unsigned NOT NULL, + PRIMARY KEY (`ym`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_stats_monthly_submissions` +-- + +DROP TABLE IF EXISTS `arXiv_stats_monthly_submissions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_stats_monthly_submissions` ( + `ym` date NOT NULL DEFAULT '0000-00-00', + `num_submissions` smallint(5) unsigned NOT NULL, + `historical_delta` tinyint(4) NOT NULL DEFAULT '0', + PRIMARY KEY (`ym`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_submission_abs_classifier_data` +-- + +DROP TABLE IF EXISTS `arXiv_submission_abs_classifier_data`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_submission_abs_classifier_data` ( + `submission_id` int(11) NOT NULL DEFAULT '0', + `json` text, + `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `status` enum('processing','success','failed','no connection') DEFAULT NULL, + `message` text, + `is_oversize` tinyint(1) DEFAULT '0', + `suggested_primary` text, + `suggested_reason` text, + `autoproposal_primary` text, + `autoproposal_reason` text, + `classifier_service_version` text, + `classifier_model_version` text, + PRIMARY KEY (`submission_id`), + CONSTRAINT `arXiv_submission_abs_classifier_data_ibfk_1` FOREIGN KEY (`submission_id`) REFERENCES `arXiv_submissions` (`submission_id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_submission_agreements` +-- + +DROP TABLE IF EXISTS `arXiv_submission_agreements`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_submission_agreements` ( + `agreement_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT, + `effective_date` datetime DEFAULT CURRENT_TIMESTAMP, + `commit_ref` varchar(255) NOT NULL, + `content` text, + PRIMARY KEY (`agreement_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_submission_category` +-- + +DROP TABLE IF EXISTS `arXiv_submission_category`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_submission_category` ( + `submission_id` int(11) NOT NULL, + `category` varchar(32) NOT NULL DEFAULT '', + `is_primary` tinyint(1) NOT NULL DEFAULT '0', + `is_published` tinyint(1) DEFAULT '0', + PRIMARY KEY (`submission_id`,`category`), + KEY `arXiv_submission_category_idx_category` (`category`), + KEY `arXiv_submission_category_idx_submission_id` (`submission_id`), + KEY `arXiv_submission_category_idx_is_primary` (`is_primary`), + KEY `arXiv_submission_category_idx_is_published` (`is_published`), + CONSTRAINT `arXiv_submission_category_fk_category` FOREIGN KEY (`category`) REFERENCES `arXiv_category_def` (`category`), + CONSTRAINT `arXiv_submission_category_fk_submission_id` FOREIGN KEY (`submission_id`) REFERENCES `arXiv_submissions` (`submission_id`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_submission_category_proposal` +-- + +DROP TABLE IF EXISTS `arXiv_submission_category_proposal`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_submission_category_proposal` ( + `proposal_id` int(11) NOT NULL AUTO_INCREMENT, + `submission_id` int(11) NOT NULL, + `category` varchar(32) CHARACTER SET latin1 NOT NULL, + `is_primary` tinyint(1) NOT NULL DEFAULT '0', + `proposal_status` int(11) DEFAULT '0', + `user_id` int(4) unsigned NOT NULL, + `updated` datetime DEFAULT NULL, + `proposal_comment_id` int(11) DEFAULT NULL, + `response_comment_id` int(11) DEFAULT NULL, + PRIMARY KEY (`proposal_id`,`submission_id`,`category`,`is_primary`), + KEY `arXiv_submission_category_proposal_idx_key` (`proposal_id`), + KEY `arXiv_submission_category_proposal_idx_category` (`category`), + KEY `arXiv_submission_category_proposal_idx_submission_id` (`submission_id`), + KEY `arXiv_submission_category_proposal_idx_is_primary` (`is_primary`), + KEY `arXiv_submission_category_proposal_fk_user_id` (`user_id`), + KEY `arXiv_submission_category_proposal_fk_prop_comment_id` (`proposal_comment_id`), + KEY `arXiv_submission_category_proposal_fk_resp_comment_id` (`response_comment_id`), + CONSTRAINT `arXiv_submission_category_proposal_fk_category` FOREIGN KEY (`category`) REFERENCES `arXiv_category_def` (`category`), + CONSTRAINT `arXiv_submission_category_proposal_fk_prop_comment_id` FOREIGN KEY (`proposal_comment_id`) REFERENCES `arXiv_admin_log` (`id`), + CONSTRAINT `arXiv_submission_category_proposal_fk_resp_comment_id` FOREIGN KEY (`response_comment_id`) REFERENCES `arXiv_admin_log` (`id`), + CONSTRAINT `arXiv_submission_category_proposal_fk_submission_id` FOREIGN KEY (`submission_id`) REFERENCES `arXiv_submissions` (`submission_id`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `arXiv_submission_category_proposal_fk_user_id` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_submission_classifier_data` +-- + +DROP TABLE IF EXISTS `arXiv_submission_classifier_data`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_submission_classifier_data` ( + `submission_id` int(11) NOT NULL DEFAULT '0', + `json` text, + `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `status` enum('processing','success','failed','no connection') DEFAULT NULL, + `message` text, + `is_oversize` tinyint(1) DEFAULT '0', + PRIMARY KEY (`submission_id`), + CONSTRAINT `arXiv_submission_classifier_data_ibfk_1` FOREIGN KEY (`submission_id`) REFERENCES `arXiv_submissions` (`submission_id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_submission_control` +-- + +DROP TABLE IF EXISTS `arXiv_submission_control`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_submission_control` ( + `control_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `document_id` mediumint(8) unsigned NOT NULL DEFAULT '0', + `version` tinyint(3) unsigned NOT NULL DEFAULT '0', + `pending_paper_id` varchar(20) NOT NULL DEFAULT '', + `user_id` int(10) unsigned NOT NULL DEFAULT '0', + `status` enum('new','frozen','published','rejected') NOT NULL DEFAULT 'new', + `flag_must_notify` enum('0','1') DEFAULT '1', + `request_date` int(10) unsigned NOT NULL DEFAULT '0', + `freeze_date` int(10) unsigned NOT NULL DEFAULT '0', + `publish_date` int(10) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`control_id`), + UNIQUE KEY `document_id` (`document_id`,`version`), + KEY `pending_paper_id` (`pending_paper_id`), + KEY `status` (`status`), + KEY `request_date` (`request_date`), + KEY `freeze_date` (`freeze_date`), + KEY `user_id` (`user_id`), + CONSTRAINT `arXiv_submission_control_ibfk_1` FOREIGN KEY (`document_id`) REFERENCES `arXiv_documents` (`document_id`), + CONSTRAINT `arXiv_submission_control_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_submission_flag` +-- + +DROP TABLE IF EXISTS `arXiv_submission_flag`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_submission_flag` ( + `flag_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(4) unsigned NOT NULL DEFAULT '0', + `submission_id` int(11) NOT NULL, + `flag` tinyint(4) NOT NULL DEFAULT '0', + `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `flag_pdf_opened` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`flag_id`), + UNIQUE KEY `uniq_one_flag_per_mod` (`submission_id`,`user_id`), + KEY `user_id` (`user_id`), + CONSTRAINT `arXiv_submission_flag_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) ON DELETE CASCADE, + CONSTRAINT `arXiv_submission_flag_ibfk_2` FOREIGN KEY (`submission_id`) REFERENCES `arXiv_submissions` (`submission_id`) ON DELETE CASCADE +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_submission_hold_reason` +-- + +DROP TABLE IF EXISTS `arXiv_submission_hold_reason`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_submission_hold_reason` ( + `reason_id` int(11) NOT NULL AUTO_INCREMENT, + `submission_id` int(11) NOT NULL, + `user_id` int(4) unsigned NOT NULL, + `reason` varchar(30) DEFAULT NULL, + `type` varchar(30) DEFAULT NULL, + `comment_id` int(11) DEFAULT NULL, + PRIMARY KEY (`reason_id`,`user_id`), + KEY `submission_id` (`submission_id`), + KEY `user_id` (`user_id`), + KEY `comment_id` (`comment_id`), + CONSTRAINT `arXiv_submission_hold_reason_ibfk_1` FOREIGN KEY (`submission_id`) REFERENCES `arXiv_submissions` (`submission_id`) ON DELETE CASCADE, + CONSTRAINT `arXiv_submission_hold_reason_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) ON DELETE CASCADE, + CONSTRAINT `arXiv_submission_hold_reason_ibfk_3` FOREIGN KEY (`comment_id`) REFERENCES `arXiv_admin_log` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_submission_locks` +-- + +DROP TABLE IF EXISTS `arXiv_submission_locks`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_submission_locks` ( + `submission_lock_id` int(11) NOT NULL AUTO_INCREMENT, + `submission_id` int(11) NOT NULL, + `user_id` int(4) unsigned NOT NULL, + `lock_type` varchar(20) NOT NULL, + `expires` datetime NOT NULL, + `updated` datetime NOT NULL, + `released` tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`submission_lock_id`), + UNIQUE KEY `arxiv_submission_locks_sub_index` (`submission_id`,`lock_type`), + KEY `arxiv_submission_locks_user_index` (`user_id`), + CONSTRAINT `arxiv_submission_locks_sub_fk` FOREIGN KEY (`submission_id`) REFERENCES `arXiv_submissions` (`submission_id`), + CONSTRAINT `arxiv_submission_locks_user_fk` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_submission_near_duplicates` +-- + +DROP TABLE IF EXISTS `arXiv_submission_near_duplicates`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_submission_near_duplicates` ( + `submission_id` int(11) NOT NULL DEFAULT '0', + `matching_id` int(11) NOT NULL DEFAULT '0', + `similarity` decimal(2,1) unsigned NOT NULL, + `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`submission_id`,`matching_id`), + UNIQUE KEY `match` (`submission_id`,`matching_id`), + CONSTRAINT `arXiv_submission_near_duplicates_ibfk_1` FOREIGN KEY (`submission_id`) REFERENCES `arXiv_submissions` (`submission_id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_submission_qa_reports` +-- + +DROP TABLE IF EXISTS `arXiv_submission_qa_reports`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_submission_qa_reports` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `submission_id` int(11) NOT NULL, + `report_key_name` varchar(64) NOT NULL, + `created` datetime DEFAULT CURRENT_TIMESTAMP, + `num_flags` smallint(6) NOT NULL DEFAULT '0', + `report` json NOT NULL, + `report_uri` varchar(256) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `submission_id` (`submission_id`), + KEY `report_key_name` (`report_key_name`), + CONSTRAINT `arXiv_submission_qa_reports_ibfk_1` FOREIGN KEY (`submission_id`) REFERENCES `arXiv_submissions` (`submission_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_submission_view_flag` +-- + +DROP TABLE IF EXISTS `arXiv_submission_view_flag`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_submission_view_flag` ( + `submission_id` int(11) NOT NULL, + `flag` tinyint(1) DEFAULT '0', + `user_id` int(4) unsigned NOT NULL, + `updated` datetime DEFAULT NULL, + PRIMARY KEY (`submission_id`,`user_id`), + KEY `user_id` (`user_id`), + CONSTRAINT `arXiv_submission_view_flag_ibfk_1` FOREIGN KEY (`submission_id`) REFERENCES `arXiv_submissions` (`submission_id`) ON DELETE CASCADE, + CONSTRAINT `arXiv_submission_view_flag_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_submissions` +-- + +DROP TABLE IF EXISTS `arXiv_submissions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_submissions` ( + `submission_id` int(11) NOT NULL AUTO_INCREMENT, + `document_id` mediumint(8) unsigned DEFAULT NULL, + `doc_paper_id` varchar(20) CHARACTER SET latin1 DEFAULT NULL, + `sword_id` int(8) unsigned DEFAULT NULL, + `userinfo` tinyint(4) DEFAULT '0', + `is_author` tinyint(1) NOT NULL DEFAULT '0', + `agree_policy` tinyint(1) DEFAULT '0', + `viewed` tinyint(1) DEFAULT '0', + `stage` int(11) DEFAULT '0', + `submitter_id` int(4) unsigned DEFAULT NULL, + `submitter_name` varchar(64) DEFAULT NULL, + `submitter_email` varchar(64) DEFAULT NULL, + `created` datetime DEFAULT NULL, + `updated` datetime DEFAULT NULL, + `status` int(11) NOT NULL DEFAULT '0', + `sticky_status` int(11) DEFAULT NULL, + `must_process` tinyint(1) DEFAULT '1', + `submit_time` datetime DEFAULT NULL, + `release_time` datetime DEFAULT NULL, + `source_size` int(11) DEFAULT '0', + `source_format` varchar(12) CHARACTER SET latin1 DEFAULT NULL, + `source_flags` varchar(12) CHARACTER SET latin1 DEFAULT NULL, + `has_pilot_data` tinyint(1) DEFAULT NULL, + `is_withdrawn` tinyint(1) NOT NULL DEFAULT '0', + `title` text, + `authors` text, + `comments` text, + `proxy` varchar(255) CHARACTER SET latin1 DEFAULT NULL, + `report_num` text, + `msc_class` varchar(255) DEFAULT NULL, + `acm_class` varchar(255) DEFAULT NULL, + `journal_ref` text, + `doi` varchar(255) DEFAULT NULL, + `abstract` text, + `license` varchar(255) CHARACTER SET latin1 DEFAULT NULL, + `version` int(4) NOT NULL DEFAULT '1', + `type` char(8) CHARACTER SET latin1 DEFAULT NULL, + `is_ok` tinyint(1) DEFAULT NULL, + `admin_ok` tinyint(1) DEFAULT NULL, + `allow_tex_produced` tinyint(1) DEFAULT '0', + `is_oversize` tinyint(1) DEFAULT '0', + `remote_addr` varchar(16) CHARACTER SET latin1 NOT NULL DEFAULT '', + `remote_host` varchar(255) CHARACTER SET latin1 NOT NULL DEFAULT '', + `package` varchar(255) CHARACTER SET latin1 NOT NULL DEFAULT '', + `rt_ticket_id` int(8) unsigned DEFAULT NULL, + `auto_hold` tinyint(1) DEFAULT '0', + `is_locked` int(1) unsigned NOT NULL DEFAULT '0', + `agreement_id` smallint(5) unsigned DEFAULT NULL, + `data_version` smallint(6) NOT NULL DEFAULT '1', + `metadata_version` smallint(6) NOT NULL DEFAULT '1', + `data_needed` smallint(6) NOT NULL DEFAULT '0', + `data_version_queued` smallint(6) NOT NULL DEFAULT '0', + `metadata_version_queued` smallint(6) NOT NULL DEFAULT '0', + `data_queued_time` datetime DEFAULT NULL, + `metadata_queued_time` datetime DEFAULT NULL, + PRIMARY KEY (`submission_id`), + KEY `arXiv_submissions_idx_document_id` (`document_id`), + KEY `arXiv_submissions_idx_license` (`license`), + KEY `arXiv_submissions_idx_submitter_id` (`submitter_id`), + KEY `arXiv_submissions_idx_sword_id` (`sword_id`), + KEY `arXiv_submissions_idx_status` (`status`), + KEY `arXiv_submissions_idx_type` (`type`), + KEY `arXiv_submissions_idx_is_ok` (`is_ok`), + KEY `arXiv_submissions_idx_doc_paper_id` (`doc_paper_id`), + KEY `arXiv_submissions_idx_rt_ticket_id` (`rt_ticket_id`), + KEY `arXiv_submissions_idx_is_locked` (`is_locked`), + KEY `agreement_fk` (`agreement_id`), + CONSTRAINT `agreement_fk` FOREIGN KEY (`agreement_id`) REFERENCES `arXiv_submission_agreements` (`agreement_id`), + CONSTRAINT `arXiv_submissions_fk_document_id` FOREIGN KEY (`document_id`) REFERENCES `arXiv_documents` (`document_id`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `arXiv_submissions_fk_license` FOREIGN KEY (`license`) REFERENCES `arXiv_licenses` (`name`) ON UPDATE CASCADE, + CONSTRAINT `arXiv_submissions_fk_submitter_id` FOREIGN KEY (`submitter_id`) REFERENCES `tapir_users` (`user_id`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `arXiv_submissions_fk_sword_id` FOREIGN KEY (`sword_id`) REFERENCES `arXiv_tracking` (`sword_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_submitter_flags` +-- + +DROP TABLE IF EXISTS `arXiv_submitter_flags`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_submitter_flags` ( + `flag_id` int(11) NOT NULL, + `comment` varchar(255) DEFAULT NULL, + `pattern` varchar(255) DEFAULT NULL, + PRIMARY KEY (`flag_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_suspect_emails` +-- + +DROP TABLE IF EXISTS `arXiv_suspect_emails`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_suspect_emails` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `type` varchar(10) NOT NULL, + `pattern` text NOT NULL, + `comment` text NOT NULL, + `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_suspicious_names` +-- + +DROP TABLE IF EXISTS `arXiv_suspicious_names`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_suspicious_names` ( + `user_id` int(10) unsigned NOT NULL DEFAULT '0', + `full_name` varchar(255) NOT NULL DEFAULT '', + PRIMARY KEY (`user_id`), + CONSTRAINT `0_606` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_sword_licenses` +-- + +DROP TABLE IF EXISTS `arXiv_sword_licenses`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_sword_licenses` ( + `user_id` int(4) unsigned NOT NULL, + `license` varchar(127) DEFAULT NULL, + `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`user_id`), + CONSTRAINT `user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_titles` +-- + +DROP TABLE IF EXISTS `arXiv_titles`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_titles` ( + `paper_id` varchar(64) NOT NULL, + `title` varchar(255) DEFAULT NULL, + `report_num` varchar(255) DEFAULT NULL, + `date` date DEFAULT NULL, + PRIMARY KEY (`paper_id`), + KEY `arXiv_titles_idx` (`title`), + KEY `arXiv_repno_idx` (`report_num`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_top_papers` +-- + +DROP TABLE IF EXISTS `arXiv_top_papers`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_top_papers` ( + `from_week` date NOT NULL DEFAULT '0000-00-00', + `class` char(1) NOT NULL DEFAULT '', + `rank` smallint(5) unsigned NOT NULL DEFAULT '0', + `document_id` mediumint(8) unsigned NOT NULL DEFAULT '0', + `viewers` mediumint(8) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`from_week`,`class`,`rank`), + KEY `document_id` (`document_id`), + CONSTRAINT `arXiv_top_papers_ibfk_1` FOREIGN KEY (`document_id`) REFERENCES `arXiv_documents` (`document_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_trackback_pings` +-- + +DROP TABLE IF EXISTS `arXiv_trackback_pings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_trackback_pings` ( + `trackback_id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, + `document_id` mediumint(8) unsigned DEFAULT NULL, + `title` varchar(255) NOT NULL DEFAULT '', + `excerpt` varchar(255) NOT NULL DEFAULT '', + `url` varchar(255) NOT NULL DEFAULT '', + `blog_name` varchar(255) NOT NULL DEFAULT '', + `remote_host` varchar(255) NOT NULL DEFAULT '', + `remote_addr` varchar(16) NOT NULL DEFAULT '', + `posted_date` int(10) unsigned NOT NULL DEFAULT '0', + `is_stale` tinyint(4) NOT NULL DEFAULT '0', + `approved_by_user` mediumint(9) NOT NULL DEFAULT '0', + `approved_time` int(11) NOT NULL DEFAULT '0', + `status` enum('pending','pending2','accepted','rejected','spam') NOT NULL DEFAULT 'pending', + `site_id` int(10) unsigned DEFAULT NULL, + PRIMARY KEY (`trackback_id`), + KEY `arXiv_trackback_pings__document_id` (`document_id`), + KEY `arXiv_trackback_pings__url` (`url`), + KEY `arXiv_trackback_pings__posted_date` (`posted_date`), + KEY `arXiv_trackback_pings__status` (`status`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_trackback_sites` +-- + +DROP TABLE IF EXISTS `arXiv_trackback_sites`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_trackback_sites` ( + `pattern` varchar(255) NOT NULL DEFAULT '', + `site_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `action` enum('neutral','accept','reject','spam') NOT NULL DEFAULT 'neutral', + PRIMARY KEY (`site_id`), + KEY `arXiv_trackback_sites__pattern` (`pattern`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_tracking` +-- + +DROP TABLE IF EXISTS `arXiv_tracking`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_tracking` ( + `tracking_id` int(11) NOT NULL AUTO_INCREMENT, + `sword_id` int(8) unsigned zerofill NOT NULL DEFAULT '00000000', + `paper_id` varchar(32) NOT NULL, + `submission_errors` text, + `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`tracking_id`), + UNIQUE KEY `sword_id` (`sword_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_updates` +-- + +DROP TABLE IF EXISTS `arXiv_updates`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_updates` ( + `document_id` int(11) DEFAULT NULL, + `version` int(4) NOT NULL DEFAULT '1', + `date` date DEFAULT NULL, + `action` enum('new','replace','absonly','cross','repcro') DEFAULT NULL, + `archive` varchar(20) DEFAULT NULL, + `category` varchar(20) DEFAULT NULL, + UNIQUE KEY `document_id` (`document_id`,`date`,`action`,`category`), + KEY `date_index` (`date`), + KEY `archive_index` (`archive`), + KEY `category_index` (`category`), + KEY `document_id_index` (`document_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_updates_tmp` +-- + +DROP TABLE IF EXISTS `arXiv_updates_tmp`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_updates_tmp` ( + `document_id` int(11) DEFAULT NULL, + `date` date DEFAULT NULL, + `action` enum('new','replace','absonly','cross','repcro') DEFAULT NULL, + `category` varchar(20) DEFAULT NULL, + UNIQUE KEY `document_id` (`document_id`,`date`,`action`,`category`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_versions` +-- + +DROP TABLE IF EXISTS `arXiv_versions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_versions` ( + `document_id` mediumint(8) unsigned NOT NULL DEFAULT '0', + `version` tinyint(3) unsigned NOT NULL DEFAULT '0', + `request_date` int(10) unsigned NOT NULL DEFAULT '0', + `freeze_date` int(10) unsigned NOT NULL DEFAULT '0', + `publish_date` int(10) unsigned NOT NULL DEFAULT '0', + `flag_current` mediumint(8) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`document_id`,`version`), + KEY `request_date` (`request_date`), + KEY `freeze_date` (`freeze_date`), + KEY `publish_date` (`publish_date`), + CONSTRAINT `arXiv_versions_ibfk_1` FOREIGN KEY (`document_id`) REFERENCES `arXiv_documents` (`document_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_versions_checksum` +-- + +DROP TABLE IF EXISTS `arXiv_versions_checksum`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_versions_checksum` ( + `document_id` mediumint(8) unsigned NOT NULL DEFAULT '0', + `version` tinyint(3) unsigned NOT NULL DEFAULT '0', + `flag_abs_present` int(10) unsigned NOT NULL DEFAULT '0', + `abs_size` int(10) unsigned NOT NULL DEFAULT '0', + `abs_md5sum` binary(16) DEFAULT NULL, + `flag_src_present` tinyint(3) unsigned NOT NULL DEFAULT '0', + `src_size` int(10) unsigned NOT NULL DEFAULT '0', + `src_md5sum` binary(16) DEFAULT NULL, + PRIMARY KEY (`document_id`,`version`), + KEY `abs_size` (`abs_size`), + KEY `abs_md5sum` (`abs_md5sum`), + KEY `src_size` (`src_size`), + KEY `src_md5sum` (`src_md5sum`), + CONSTRAINT `arXiv_versions_checksum_ibfk_1` FOREIGN KEY (`document_id`, `version`) REFERENCES `arXiv_versions` (`document_id`, `version`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_white_email` +-- + +DROP TABLE IF EXISTS `arXiv_white_email`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_white_email` ( + `pattern` varchar(64) DEFAULT NULL, + UNIQUE KEY `uc_pattern` (`pattern`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `arXiv_xml_notifications` +-- + +DROP TABLE IF EXISTS `arXiv_xml_notifications`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `arXiv_xml_notifications` ( + `control_id` int(10) unsigned DEFAULT NULL, + `type` enum('submission','cross','jref') DEFAULT NULL, + `queued_date` int(10) unsigned NOT NULL DEFAULT '0', + `sent_date` int(10) unsigned NOT NULL DEFAULT '0', + `status` enum('unsent','sent','failed') DEFAULT NULL, + KEY `control_id` (`control_id`), + KEY `status` (`status`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `dbix_class_schema_versions` +-- + +DROP TABLE IF EXISTS `dbix_class_schema_versions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `dbix_class_schema_versions` ( + `version` varchar(10) NOT NULL, + `installed` varchar(20) NOT NULL, + PRIMARY KEY (`version`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `demographics_backup` +-- + +DROP TABLE IF EXISTS `demographics_backup`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `demographics_backup` ( + `user_id` int(10) unsigned NOT NULL DEFAULT '0', + `country` char(2) NOT NULL DEFAULT '', + `affiliation` varchar(255) NOT NULL DEFAULT '', + `url` varchar(255) NOT NULL DEFAULT '', + `type` smallint(5) unsigned DEFAULT NULL, + `os` smallint(5) unsigned DEFAULT NULL, + `archive` varchar(16) DEFAULT NULL, + `subject_class` varchar(16) DEFAULT NULL, + `original_subject_classes` varchar(255) NOT NULL DEFAULT '', + `flag_group_physics` int(1) unsigned DEFAULT NULL, + `flag_group_math` int(1) unsigned NOT NULL DEFAULT '0', + `flag_group_cs` int(1) unsigned NOT NULL DEFAULT '0', + `flag_group_nlin` int(1) unsigned NOT NULL DEFAULT '0', + `flag_proxy` int(1) unsigned NOT NULL DEFAULT '0', + `flag_journal` int(1) unsigned NOT NULL DEFAULT '0', + `flag_xml` int(1) unsigned NOT NULL DEFAULT '0', + `dirty` int(1) unsigned NOT NULL DEFAULT '2', + `flag_group_test` int(1) unsigned NOT NULL DEFAULT '0', + `flag_suspect` int(1) unsigned NOT NULL DEFAULT '0', + `flag_group_q_bio` int(1) unsigned NOT NULL DEFAULT '0', + `flag_no_upload` int(1) unsigned NOT NULL DEFAULT '0', + `flag_no_endorse` int(1) unsigned NOT NULL DEFAULT '0', + `veto_status` enum('ok','no-endorse','no-upload') DEFAULT 'ok' +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `membership_institutions` +-- + +DROP TABLE IF EXISTS `membership_institutions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `membership_institutions` ( + `sid` int(11) NOT NULL, + `name` varchar(256) DEFAULT NULL, + `country` varchar(40) DEFAULT NULL, + `country_code` varchar(10) DEFAULT NULL, + `consortia_code` varchar(20) DEFAULT NULL, + `member_type` varchar(20) DEFAULT NULL, + `ror_id` varchar(50) DEFAULT NULL, + `is_consortium` tinyint(4) DEFAULT NULL, + `label` varchar(256) DEFAULT NULL, + `comment` text, + `is_active` tinyint(4) NOT NULL DEFAULT '1', + PRIMARY KEY (`sid`), + KEY `membership_Institution_name_index` (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `membership_users` +-- + +DROP TABLE IF EXISTS `membership_users`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `membership_users` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `sid` int(11) NOT NULL, + `user_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `sessions` +-- + +DROP TABLE IF EXISTS `sessions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `sessions` ( + `id` char(72) NOT NULL, + `session_data` text, + `expires` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_address` +-- + +DROP TABLE IF EXISTS `tapir_address`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_address` ( + `user_id` int(4) unsigned NOT NULL DEFAULT '0', + `address_type` int(1) NOT NULL DEFAULT '0', + `company` varchar(80) NOT NULL DEFAULT '', + `line1` varchar(80) NOT NULL DEFAULT '', + `line2` varchar(80) NOT NULL DEFAULT '', + `city` varchar(50) NOT NULL DEFAULT '', + `state` varchar(50) NOT NULL DEFAULT '', + `postal_code` varchar(16) NOT NULL DEFAULT '', + `country` char(2) NOT NULL DEFAULT '', + `share_addr` int(1) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`user_id`,`address_type`), + KEY `country` (`country`), + KEY `city` (`city`), + KEY `postal_code` (`postal_code`), + KEY `address_type` (`address_type`), + CONSTRAINT `0_522` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`), + CONSTRAINT `0_523` FOREIGN KEY (`country`) REFERENCES `tapir_countries` (`digraph`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_admin_audit` +-- + +DROP TABLE IF EXISTS `tapir_admin_audit`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_admin_audit` ( + `log_date` int(10) unsigned NOT NULL DEFAULT '0', + `session_id` int(4) unsigned DEFAULT NULL, + `ip_addr` varchar(16) NOT NULL DEFAULT '', + `remote_host` varchar(255) NOT NULL DEFAULT '', + `admin_user` int(4) unsigned DEFAULT NULL, + `affected_user` int(4) unsigned NOT NULL DEFAULT '0', + `tracking_cookie` varchar(255) NOT NULL DEFAULT '', + `action` varchar(32) NOT NULL DEFAULT '', + `data` text NOT NULL, + `comment` text NOT NULL, + `entry_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`entry_id`), + KEY `log_date` (`log_date`), + KEY `session_id` (`session_id`), + KEY `ip_addr` (`ip_addr`), + KEY `admin_user` (`admin_user`), + KEY `affected_user` (`affected_user`), + KEY `data` (`data`(32)), + KEY `data_2` (`data`(32)), + KEY `data_3` (`data`(32)), + CONSTRAINT `0_553` FOREIGN KEY (`session_id`) REFERENCES `tapir_sessions` (`session_id`), + CONSTRAINT `0_554` FOREIGN KEY (`admin_user`) REFERENCES `tapir_users` (`user_id`), + CONSTRAINT `0_555` FOREIGN KEY (`affected_user`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_countries` +-- + +DROP TABLE IF EXISTS `tapir_countries`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_countries` ( + `digraph` char(2) NOT NULL DEFAULT '', + `country_name` varchar(255) NOT NULL DEFAULT '', + `rank` int(1) unsigned NOT NULL DEFAULT '255', + PRIMARY KEY (`digraph`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_demographics` +-- + +DROP TABLE IF EXISTS `tapir_demographics`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_demographics` ( + `user_id` int(4) unsigned NOT NULL DEFAULT '0', + `gender` int(1) NOT NULL DEFAULT '0', + `share_gender` int(1) unsigned NOT NULL DEFAULT '16', + `birthday` date DEFAULT NULL, + `share_birthday` int(1) unsigned NOT NULL DEFAULT '16', + `country` char(2) NOT NULL DEFAULT '', + `share_country` int(1) unsigned NOT NULL DEFAULT '16', + `postal_code` varchar(16) NOT NULL DEFAULT '', + PRIMARY KEY (`user_id`), + KEY `country` (`country`), + KEY `postal_code` (`postal_code`), + KEY `birthday` (`birthday`), + CONSTRAINT `0_517` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`), + CONSTRAINT `0_518` FOREIGN KEY (`country`) REFERENCES `tapir_countries` (`digraph`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_email_change_tokens` +-- + +DROP TABLE IF EXISTS `tapir_email_change_tokens`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_email_change_tokens` ( + `user_id` int(4) unsigned NOT NULL DEFAULT '0', + `old_email` varchar(255) DEFAULT NULL, + `new_email` varchar(255) DEFAULT NULL, + `secret` varchar(32) NOT NULL DEFAULT '', + `tapir_dest` varchar(255) NOT NULL DEFAULT '', + `issued_when` int(10) unsigned NOT NULL DEFAULT '0', + `issued_to` varchar(16) NOT NULL DEFAULT '', + `remote_host` varchar(16) NOT NULL DEFAULT '', + `tracking_cookie` varchar(255) NOT NULL DEFAULT '', + `used` int(1) unsigned NOT NULL DEFAULT '0', + `session_id` int(4) unsigned NOT NULL DEFAULT '0', + `consumed_when` int(10) unsigned DEFAULT NULL, + `consumed_from` varchar(16) DEFAULT NULL, + PRIMARY KEY (`user_id`,`secret`), + KEY `secret` (`secret`), + CONSTRAINT `0_535` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_email_change_tokens_used` +-- + +DROP TABLE IF EXISTS `tapir_email_change_tokens_used`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_email_change_tokens_used` ( + `user_id` int(4) unsigned NOT NULL DEFAULT '0', + `secret` varchar(32) NOT NULL DEFAULT '', + `used_when` int(10) unsigned NOT NULL DEFAULT '0', + `used_from` varchar(16) NOT NULL DEFAULT '', + `remote_host` varchar(255) NOT NULL DEFAULT '', + `session_id` int(4) unsigned NOT NULL DEFAULT '0', + KEY `user_id` (`user_id`), + KEY `session_id` (`session_id`), + CONSTRAINT `0_537` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`), + CONSTRAINT `0_538` FOREIGN KEY (`session_id`) REFERENCES `tapir_sessions` (`session_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_email_headers` +-- + +DROP TABLE IF EXISTS `tapir_email_headers`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_email_headers` ( + `template_id` int(10) unsigned NOT NULL DEFAULT '0', + `header_name` varchar(32) NOT NULL DEFAULT '', + `header_content` varchar(255) NOT NULL DEFAULT '', + PRIMARY KEY (`template_id`,`header_name`), + CONSTRAINT `0_563` FOREIGN KEY (`template_id`) REFERENCES `tapir_email_templates` (`template_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_email_log` +-- + +DROP TABLE IF EXISTS `tapir_email_log`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_email_log` ( + `mail_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `reference_type` char(1) DEFAULT NULL, + `reference_id` int(4) unsigned DEFAULT NULL, + `sent_date` int(10) unsigned NOT NULL DEFAULT '0', + `email` varchar(255) DEFAULT NULL, + `flag_bounced` int(1) unsigned DEFAULT NULL, + `mailing_id` int(10) unsigned DEFAULT NULL, + `template_id` int(10) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`mail_id`), + KEY `mailing_id` (`mailing_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_email_mailings` +-- + +DROP TABLE IF EXISTS `tapir_email_mailings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_email_mailings` ( + `mailing_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `template_id` int(10) unsigned DEFAULT NULL, + `created_by` int(10) unsigned DEFAULT NULL, + `sent_by` int(10) unsigned DEFAULT NULL, + `created_date` int(10) unsigned DEFAULT NULL, + `sent_date` int(10) unsigned DEFAULT NULL, + `complete_date` int(10) unsigned DEFAULT NULL, + `mailing_name` varchar(255) DEFAULT NULL, + `comment` text, + PRIMARY KEY (`mailing_id`), + KEY `created_by` (`created_by`), + KEY `sent_by` (`sent_by`), + KEY `template_id` (`template_id`), + CONSTRAINT `0_565` FOREIGN KEY (`created_by`) REFERENCES `tapir_users` (`user_id`), + CONSTRAINT `0_566` FOREIGN KEY (`sent_by`) REFERENCES `tapir_users` (`user_id`), + CONSTRAINT `0_567` FOREIGN KEY (`template_id`) REFERENCES `tapir_email_templates` (`template_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_email_templates` +-- + +DROP TABLE IF EXISTS `tapir_email_templates`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_email_templates` ( + `template_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `short_name` varchar(32) NOT NULL DEFAULT '', + `lang` char(2) NOT NULL DEFAULT 'en', + `long_name` varchar(255) NOT NULL DEFAULT '', + `data` text NOT NULL, + `sql_statement` text NOT NULL, + `update_date` int(10) unsigned NOT NULL DEFAULT '0', + `created_by` int(4) unsigned NOT NULL DEFAULT '0', + `updated_by` int(4) unsigned NOT NULL DEFAULT '0', + `workflow_status` int(1) unsigned NOT NULL DEFAULT '0', + `flag_system` int(1) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`template_id`), + UNIQUE KEY `short_name` (`short_name`,`lang`), + KEY `created_by` (`created_by`), + KEY `updated_by` (`updated_by`), + KEY `update_date` (`update_date`), + CONSTRAINT `0_560` FOREIGN KEY (`created_by`) REFERENCES `tapir_users` (`user_id`), + CONSTRAINT `0_561` FOREIGN KEY (`updated_by`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_email_tokens` +-- + +DROP TABLE IF EXISTS `tapir_email_tokens`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_email_tokens` ( + `user_id` int(4) unsigned NOT NULL DEFAULT '0', + `secret` varchar(32) NOT NULL DEFAULT '', + `tapir_dest` varchar(255) NOT NULL DEFAULT '', + `issued_when` int(10) unsigned NOT NULL DEFAULT '0', + `issued_to` varchar(16) NOT NULL DEFAULT '', + `remote_host` varchar(255) NOT NULL DEFAULT '', + `tracking_cookie` varchar(255) NOT NULL DEFAULT '', + `wants_perm_token` int(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`user_id`,`secret`), + KEY `secret` (`secret`), + CONSTRAINT `0_530` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_email_tokens_used` +-- + +DROP TABLE IF EXISTS `tapir_email_tokens_used`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_email_tokens_used` ( + `user_id` int(4) unsigned NOT NULL DEFAULT '0', + `secret` varchar(32) NOT NULL DEFAULT '', + `used_when` int(10) unsigned NOT NULL DEFAULT '0', + `used_from` varchar(16) NOT NULL DEFAULT '', + `remote_host` varchar(255) NOT NULL DEFAULT '', + `session_id` int(4) unsigned NOT NULL DEFAULT '0', + KEY `user_id` (`user_id`), + KEY `session_id` (`session_id`), + CONSTRAINT `0_532` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`), + CONSTRAINT `0_533` FOREIGN KEY (`session_id`) REFERENCES `tapir_sessions` (`session_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_error_log` +-- + +DROP TABLE IF EXISTS `tapir_error_log`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_error_log` ( + `error_date` int(4) unsigned NOT NULL DEFAULT '0', + `user_id` int(4) unsigned DEFAULT NULL, + `session_id` int(4) unsigned DEFAULT NULL, + `ip_addr` varchar(16) NOT NULL DEFAULT '', + `remote_host` varchar(255) NOT NULL DEFAULT '', + `tracking_cookie` varchar(32) NOT NULL DEFAULT '', + `message` varchar(32) NOT NULL DEFAULT '', + `url` varchar(255) NOT NULL DEFAULT '', + `error_url` varchar(255) NOT NULL DEFAULT '', + KEY `error_date` (`error_date`), + KEY `user_id` (`user_id`), + KEY `session_id` (`session_id`), + KEY `ip_addr` (`ip_addr`), + KEY `tracking_cookie` (`tracking_cookie`), + KEY `message` (`message`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_integer_variables` +-- + +DROP TABLE IF EXISTS `tapir_integer_variables`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_integer_variables` ( + `variable_id` varchar(32) NOT NULL DEFAULT '', + `value` int(4) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`variable_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_nicknames` +-- + +DROP TABLE IF EXISTS `tapir_nicknames`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_nicknames` ( + `nick_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `nickname` varchar(20) NOT NULL DEFAULT '', + `user_id` int(4) unsigned NOT NULL DEFAULT '0', + `user_seq` int(1) unsigned NOT NULL DEFAULT '0', + `flag_valid` int(1) unsigned NOT NULL DEFAULT '0', + `role` int(10) unsigned NOT NULL DEFAULT '0', + `policy` int(10) unsigned NOT NULL DEFAULT '0', + `flag_primary` int(1) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`nick_id`), + UNIQUE KEY `user_id` (`user_id`,`user_seq`), + UNIQUE KEY `nickname` (`nickname`), + KEY `flag_valid` (`flag_valid`), + KEY `role` (`role`), + KEY `policy` (`policy`), + CONSTRAINT `0_570` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_nicknames_audit` +-- + +DROP TABLE IF EXISTS `tapir_nicknames_audit`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_nicknames_audit` ( + `nick_id` int(10) unsigned NOT NULL DEFAULT '0', + `creation_date` int(10) unsigned NOT NULL DEFAULT '0', + `creation_ip_num` varchar(16) NOT NULL DEFAULT '', + `remote_host` varchar(255) NOT NULL DEFAULT '', + `tracking_cookie` varchar(255) NOT NULL DEFAULT '', + PRIMARY KEY (`nick_id`), + KEY `creation_date` (`creation_date`), + KEY `creation_ip_num` (`creation_ip_num`), + KEY `tracking_cookie` (`tracking_cookie`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_no_cookies` +-- + +DROP TABLE IF EXISTS `tapir_no_cookies`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_no_cookies` ( + `log_date` int(10) unsigned NOT NULL DEFAULT '0', + `ip_addr` varchar(16) NOT NULL DEFAULT '', + `remote_host` varchar(255) NOT NULL DEFAULT '', + `tracking_cookie` varchar(255) NOT NULL DEFAULT '', + `session_data` varchar(255) NOT NULL DEFAULT '', + `user_agent` varchar(255) NOT NULL DEFAULT '' +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_periodic_tasks_log` +-- + +DROP TABLE IF EXISTS `tapir_periodic_tasks_log`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_periodic_tasks_log` ( + `t` int(4) unsigned NOT NULL DEFAULT '0', + `entry` text, + KEY `tapir_periodic_tasks_log_1` (`t`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_permanent_tokens` +-- + +DROP TABLE IF EXISTS `tapir_permanent_tokens`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_permanent_tokens` ( + `user_id` int(4) unsigned NOT NULL DEFAULT '0', + `secret` varchar(32) NOT NULL DEFAULT '', + `valid` int(1) NOT NULL DEFAULT '1', + `issued_when` int(4) unsigned NOT NULL DEFAULT '0', + `issued_to` varchar(16) NOT NULL DEFAULT '', + `remote_host` varchar(255) NOT NULL DEFAULT '', + `session_id` int(4) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`user_id`,`secret`), + KEY `session_id` (`session_id`), + CONSTRAINT `0_540` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`), + CONSTRAINT `0_541` FOREIGN KEY (`session_id`) REFERENCES `tapir_sessions` (`session_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_permanent_tokens_used` +-- + +DROP TABLE IF EXISTS `tapir_permanent_tokens_used`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_permanent_tokens_used` ( + `user_id` int(4) unsigned DEFAULT NULL, + `secret` varchar(32) NOT NULL DEFAULT '', + `used_when` int(4) unsigned DEFAULT NULL, + `used_from` varchar(16) DEFAULT NULL, + `remote_host` varchar(255) NOT NULL DEFAULT '', + `session_id` int(4) unsigned NOT NULL DEFAULT '0', + KEY `user_id` (`user_id`), + KEY `session_id` (`session_id`), + CONSTRAINT `0_543` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`), + CONSTRAINT `0_544` FOREIGN KEY (`session_id`) REFERENCES `tapir_sessions` (`session_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_phone` +-- + +DROP TABLE IF EXISTS `tapir_phone`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_phone` ( + `user_id` int(4) unsigned NOT NULL DEFAULT '0', + `phone_type` int(1) NOT NULL DEFAULT '0', + `phone_number` varchar(32) DEFAULT NULL, + `share_phone` int(1) unsigned NOT NULL DEFAULT '16', + PRIMARY KEY (`user_id`,`phone_type`), + KEY `phone_number` (`phone_number`), + KEY `phone_type` (`phone_type`), + CONSTRAINT `0_520` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_policy_classes` +-- + +DROP TABLE IF EXISTS `tapir_policy_classes`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_policy_classes` ( + `class_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(64) NOT NULL DEFAULT '', + `description` text NOT NULL, + `password_storage` int(1) unsigned NOT NULL DEFAULT '0', + `recovery_policy` int(1) unsigned NOT NULL DEFAULT '0', + `permanent_login` int(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`class_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_presessions` +-- + +DROP TABLE IF EXISTS `tapir_presessions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_presessions` ( + `presession_id` int(4) unsigned NOT NULL AUTO_INCREMENT, + `ip_num` varchar(16) NOT NULL DEFAULT '', + `remote_host` varchar(255) NOT NULL DEFAULT '', + `tracking_cookie` varchar(255) NOT NULL DEFAULT '', + `created_at` int(4) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`presession_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_recovery_tokens` +-- + +DROP TABLE IF EXISTS `tapir_recovery_tokens`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_recovery_tokens` ( + `user_id` int(4) unsigned NOT NULL DEFAULT '0', + `secret` varchar(32) NOT NULL DEFAULT '', + `valid` int(1) NOT NULL DEFAULT '1', + `tapir_dest` varchar(255) NOT NULL DEFAULT '', + `issued_when` int(10) unsigned NOT NULL DEFAULT '0', + `issued_to` varchar(16) NOT NULL DEFAULT '', + `remote_host` varchar(255) NOT NULL DEFAULT '', + `tracking_cookie` varchar(255) NOT NULL DEFAULT '', + PRIMARY KEY (`user_id`,`secret`), + KEY `secret` (`secret`), + CONSTRAINT `0_546` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_recovery_tokens_used` +-- + +DROP TABLE IF EXISTS `tapir_recovery_tokens_used`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_recovery_tokens_used` ( + `user_id` int(4) unsigned NOT NULL DEFAULT '0', + `secret` varchar(32) NOT NULL DEFAULT '', + `used_when` int(4) unsigned DEFAULT NULL, + `used_from` varchar(16) DEFAULT NULL, + `remote_host` varchar(255) NOT NULL DEFAULT '', + `session_id` int(4) unsigned DEFAULT NULL, + PRIMARY KEY (`user_id`,`secret`), + KEY `session_id` (`session_id`), + CONSTRAINT `0_548` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`), + CONSTRAINT `0_549` FOREIGN KEY (`session_id`) REFERENCES `tapir_sessions` (`session_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_save_post_variables` +-- + +DROP TABLE IF EXISTS `tapir_save_post_variables`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_save_post_variables` ( + `presession_id` int(4) unsigned NOT NULL DEFAULT '0', + `name` varchar(255) DEFAULT NULL, + `value` mediumtext NOT NULL, + `seq` int(4) unsigned NOT NULL DEFAULT '0', + KEY `presession_id` (`presession_id`), + CONSTRAINT `0_558` FOREIGN KEY (`presession_id`) REFERENCES `tapir_presessions` (`presession_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_sessions` +-- + +DROP TABLE IF EXISTS `tapir_sessions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_sessions` ( + `session_id` int(4) unsigned NOT NULL AUTO_INCREMENT, + `user_id` int(4) unsigned NOT NULL DEFAULT '0', + `last_reissue` int(11) NOT NULL DEFAULT '0', + `start_time` int(11) NOT NULL DEFAULT '0', + `end_time` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`session_id`), + KEY `user_id` (`user_id`), + KEY `start_time` (`start_time`), + KEY `end_time` (`end_time`), + CONSTRAINT `0_525` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_sessions_audit` +-- + +DROP TABLE IF EXISTS `tapir_sessions_audit`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_sessions_audit` ( + `session_id` int(4) unsigned NOT NULL DEFAULT '0', + `ip_addr` varchar(16) NOT NULL DEFAULT '', + `remote_host` varchar(255) NOT NULL DEFAULT '', + `tracking_cookie` varchar(255) NOT NULL DEFAULT '', + PRIMARY KEY (`session_id`), + KEY `ip_addr` (`ip_addr`), + KEY `tracking_cookie` (`tracking_cookie`), + CONSTRAINT `0_527` FOREIGN KEY (`session_id`) REFERENCES `tapir_sessions` (`session_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_string_variables` +-- + +DROP TABLE IF EXISTS `tapir_string_variables`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_string_variables` ( + `variable_id` varchar(32) NOT NULL DEFAULT '', + `value` text NOT NULL, + PRIMARY KEY (`variable_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_strings` +-- + +DROP TABLE IF EXISTS `tapir_strings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_strings` ( + `name` varchar(32) NOT NULL DEFAULT '', + `module` varchar(32) NOT NULL DEFAULT '', + `language` varchar(32) NOT NULL DEFAULT 'en', + `string` text NOT NULL, + PRIMARY KEY (`module`,`name`,`language`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_users` +-- + +DROP TABLE IF EXISTS `tapir_users`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_users` ( + `user_id` int(4) unsigned NOT NULL AUTO_INCREMENT, + `first_name` varchar(50) DEFAULT NULL, + `last_name` varchar(50) DEFAULT NULL, + `suffix_name` varchar(50) DEFAULT NULL, + `share_first_name` int(1) unsigned NOT NULL DEFAULT '1', + `share_last_name` int(1) unsigned NOT NULL DEFAULT '1', + `email` varchar(255) NOT NULL DEFAULT '', + `share_email` int(1) unsigned NOT NULL DEFAULT '8', + `email_bouncing` int(1) unsigned NOT NULL DEFAULT '0', + `policy_class` smallint(5) unsigned NOT NULL DEFAULT '0', + `joined_date` int(10) unsigned NOT NULL DEFAULT '0', + `joined_ip_num` varchar(16) DEFAULT NULL, + `joined_remote_host` varchar(255) NOT NULL DEFAULT '', + `flag_internal` int(1) unsigned NOT NULL DEFAULT '0', + `flag_edit_users` int(1) unsigned NOT NULL DEFAULT '0', + `flag_edit_system` int(1) unsigned NOT NULL DEFAULT '0', + `flag_email_verified` int(1) unsigned NOT NULL DEFAULT '0', + `flag_approved` int(1) unsigned NOT NULL DEFAULT '1', + `flag_deleted` int(1) unsigned NOT NULL DEFAULT '0', + `flag_banned` int(1) unsigned NOT NULL DEFAULT '0', + `flag_wants_email` int(1) unsigned NOT NULL DEFAULT '0', + `flag_html_email` int(1) unsigned NOT NULL DEFAULT '0', + `tracking_cookie` varchar(255) NOT NULL DEFAULT '', + `flag_allow_tex_produced` int(1) unsigned NOT NULL DEFAULT '0', + `flag_can_lock` int(1) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`user_id`), + UNIQUE KEY `email` (`email`), + KEY `policy_class` (`policy_class`), + KEY `first_name` (`first_name`), + KEY `last_name` (`last_name`), + KEY `tracking_cookie` (`tracking_cookie`), + KEY `joined_date` (`joined_date`), + KEY `flag_internal` (`flag_internal`), + KEY `flag_edit_users` (`flag_edit_users`), + KEY `flag_approved` (`flag_approved`), + KEY `flag_deleted` (`flag_deleted`), + KEY `flag_banned` (`flag_banned`), + KEY `joined_ip_num` (`joined_ip_num`), + KEY `flag_can_lock` (`flag_can_lock`), + CONSTRAINT `0_510` FOREIGN KEY (`policy_class`) REFERENCES `tapir_policy_classes` (`class_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_users_hot` +-- + +DROP TABLE IF EXISTS `tapir_users_hot`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_users_hot` ( + `user_id` int(4) unsigned NOT NULL DEFAULT '0', + `last_login` int(4) unsigned NOT NULL DEFAULT '0', + `second_last_login` int(4) unsigned NOT NULL DEFAULT '0', + `number_sessions` int(4) NOT NULL DEFAULT '0', + PRIMARY KEY (`user_id`), + KEY `last_login` (`last_login`), + KEY `second_last_login` (`second_last_login`), + KEY `number_sessions` (`number_sessions`), + CONSTRAINT `0_514` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tapir_users_password` +-- + +DROP TABLE IF EXISTS `tapir_users_password`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tapir_users_password` ( + `user_id` int(4) unsigned NOT NULL DEFAULT '0', + `password_storage` int(1) unsigned NOT NULL DEFAULT '0', + `password_enc` varchar(50) NOT NULL DEFAULT '', + PRIMARY KEY (`user_id`), + CONSTRAINT `0_512` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; +SET @@SESSION.SQL_LOG_BIN = @MYSQLDUMP_TEMP_LOG_BIN; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2024-11-21 10:44:33 diff --git a/development/create_arxiv_schema.sh b/development/create_arxiv_schema.sh new file mode 100755 index 000000000..2496df875 --- /dev/null +++ b/development/create_arxiv_schema.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +DB_NAME="arXiv" +DB_USER="testuser" +DB_PASSWORD="testpassword" +CHARSET="utf8mb4" +COLLATION="utf8mb4_unicode_ci" + +sudo mysql < str: + mysql_type: re.Pattern + for mysql_type, generic_type in type_mapping: + if mysql_type.search(line): + line = mysql_type.sub(generic_type, line) + return line + contents = "\n".join([mapper(line) for line in contents.splitlines()]) + return contents + +# ================================================================================================================ +# +# Model code merging + +def is_assign_expr(elem: cst.CSTNode): + """Check the element type for assignment""" + if isinstance(elem, cst.SimpleStatementLine): + return isinstance(elem.body[0], (cst.Assign, cst.AnnAssign)) + return False + +def is_table_def(node: cst.CSTNode): + """If this is a simple statement and RHS is table, this is a table definition.""" + return isinstance(node, cst.SimpleStatementLine) and is_table_assign(node.body[0]) + +def is_table_assign(node: cst.CSTNode): + """Assignment that the RHS starts with Table() is a table assign.""" + return isinstance(node, cst.Assign) and isinstance(node.value, cst.Call) and node.value.func.value == "Table" + + +def find_keyword_arg(elem: cst.Call, key_name: str) -> Tuple[int, cst.Arg] | None: + """ + Find a keyword ard in the function call. + """ + assert(isinstance(elem, cst.Call)) + for idx, arg in enumerate(elem.args): + if hasattr(arg, 'keyword') and arg.keyword and arg.keyword.value == key_name: + return idx, arg + return None + + +def copy_server_default(to_elem: cst.Call, from_elem: cst.Call) -> cst.Call: + """Copy the keyword 'server_default' from/to + If the original's server_default is working, even if the schema says otherwise, keep it. + + This might have a wrong impact in the instance but that's how it was working so preserve the behavior + """ + assert(isinstance(from_elem, cst.Call)) + assert(isinstance(to_elem, cst.Call)) + + existing_server_default = find_keyword_arg(from_elem, 'server_default') + if existing_server_default: + _, existing_arg = existing_server_default + server_default = find_keyword_arg(to_elem, 'server_default') + + if server_default: + idx, _ = server_default + arg: cst.Arg = to_elem.args[idx] + new_arg = arg.with_changes(value=existing_arg.value) + + # Replace the old argument with the new one in the args list + updated_call = to_elem.with_changes(args=[ + *to_elem.args[:idx], + new_arg, + *to_elem.args[idx + 1:] + ]) + return updated_call + return to_elem + + +class SchemaTransformer(cst.CSTTransformer): + """ + Visits the CST's node and applies the transformation. + + Since the nodes are immutable object, all of changes are to create new object and pass it back. + + In db/models.py, there are the class-based models and table objects. Merge of model is done with `leave_ClassDef` + and merge of table is done with `leave_Assign`. + + """ + def __init__(self, latest_def, latest_tables): + # Merging data + self.latest_def = latest_def + self.latest_tables = latest_tables + + def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef) -> cst.CSTNode: + """ + Update the existing assignments with latest assignments. + + The intention is to replace all of assignments with the latest. + + """ + + class_name = original_node.name.value + + # Skip the things I don't want to touch + if class_name in tables_i_cannot_update: + return updated_node + + if class_name in self.latest_def: + # Only updates if there is a latest. + latest_node = self.latest_def[class_name] + + # Collect the existing assignments from the original class body. These are the column and relationship + # definitions. + # If the assignments is NOT found in the latest, it could be a problematic so remember this. + existing_assignments = { + self.first_target(elem): elem for elem in original_node.body.body if + is_assign_expr(elem) + } + + updated_body = [] + + # Remember the original slot order. __tablename__ and __table_args__ are special. it is always the + # first and 2nd. + + # This is necessary to maintain the order of columns. Some of our tests do not use the column names + # in the sql statement so if you change the order, those test data fail to load. + # Also, if we ever stop using orig_models.py and use models.py as the old input (we may do so in future) + # maintaining the column order is good for easier code review. + original_slot_order = { + "__tablename__": 0, + "__table_args__": 1, + } + + # Save the order of assign statement. + for elem in original_node.body.body: + if is_assign_expr(elem): + target = self.first_target(elem) + if target not in original_slot_order: + original_slot_order[target] = len(original_slot_order.keys()) + + # If there is a non-assignment for first part, it's likely doc string so keep it + preamble = [] + for elem in original_node.body.body: + if is_assign_expr(elem): + break + preamble.append(elem) + + # Accumulate the assignments aka columns and relationships + for elem in latest_node.body.body: + if not is_assign_expr(elem): + continue + target = self.first_target(elem) + if target in existing_assignments: + existing_elem = existing_assignments[target] + # Use the original element if it's marked as int primary key or similar + # Also, it the line is commented, keep. + if self.is_intpk(existing_elem) or self.has_comment(existing_elem): + updated_body.append(existing_elem) + else: + if isinstance(elem.body[0].value, cst.Call) and isinstance(existing_elem.body[0].value, cst.Call): + if existing_elem.body[0].value.func.value == "relationship": + existing_primary_join = find_keyword_arg(existing_elem.body[0].value, "primaryjoin") + if existing_primary_join: + latest_primary_join = find_keyword_arg(existing_elem.body[0].value, "primaryjoin") + latest_pj = str(latest_primary_join[1].value.value) if latest_primary_join else "none" + if str(existing_primary_join[1].value.value) != latest_pj: + logging.warning( + f"{class_name}.{elem.body[0].targep!r} primary join -> {existing_primary_join[1].value.value} != {latest_pj}") + + elem = elem.with_changes( + body=[ + elem.body[0].with_changes( + value=copy_server_default(elem.body[0].value, existing_elem.body[0].value) + ) + ]) + pass + + updated_body.append(elem) + # Remove this from the existing assignments so it's visited. + del existing_assignments[target] + else: + # the slot not appearing shows up after the existing ones + if target not in original_slot_order: + original_slot_order[target] = len(original_slot_order.keys()) + updated_body.append(elem) + + # Adjust the slot order based on the existing slot while appending the new ones at the bottom + updated_body.sort(key=lambda slot: original_slot_order[self.first_target(slot)]) + + # Append the non-assigns. Non-assign before the assign is "preamble" + after_assign = False + for elem in original_node.body.body: + if is_assign_expr(elem): + after_assign = True + continue + if after_assign: + updated_body.append(elem) + + a_key: str + intended = {} + for a_key, a_value in existing_assignments.items(): + if not isinstance(a_value, cst.SimpleStatementLine): + continue + # If the lhs is all upper, it is def. added by hand. So, leave it in the class + if a_key == a_key.upper(): + updated_body.append(a_value) + intended[a_key] = a_value + continue + + # If the line has any comment, hand-added, so leave it + for line in a_value.leading_lines: + if line.comment: + updated_body.append(a_value) + intended[a_key] = a_value + continue + + # Warn the left over assigns. + if existing_assignments: + # ignore all uppers + props = [prop for prop in existing_assignments.keys() if prop not in intended] + if props: + extras = [class_name] + [f" {prop}" for prop in props] + logging.warning(f"Class with extra existing assignmet(s):\n" + "\n".join(extras)) + + # Rebuild the class body with updated assignments + body = preamble + updated_body + return updated_node.with_changes(body=updated_node.body.with_changes(body=body)) + return updated_node + + def first_target(self, node: cst.CSTNode): + """Find the LHS name. If it is targets, use the first one""" + if is_assign_expr(node): + if hasattr(node.body[0], 'target'): + return node.body[0].target.value + if hasattr(node.body[0], 'targets'): + return node.body[0].targets[0].target.value + return None + + def is_intpk(self, elem: cst.CSTNode): + """Find the intpk and print it as so. + In the orid_models.py, we use this syntax sugar so keep using it. + + It this is a simple assign: + and it's annotated + and the annotation uses intpk, + -> True + + """ + if isinstance(elem, cst.SimpleStatementLine): + if hasattr(elem.body[0], 'annotation'): + for anno in elem.body[0].annotation.children: + if isinstance(anno, cst.Subscript): + for sub_elem in anno.children: + if isinstance(sub_elem, cst.SubscriptElement): + for frag in sub_elem.children: + if hasattr(frag, 'value') and frag.value.value == 'intpk': + return True + return False + + def has_comment(self, elem: cst.CSTNode): + """commented? The commented line means that the statement's very last comment is not blank comment""" + if isinstance(elem, cst.SimpleStatementLine): + return elem.leading_lines and elem.leading_lines[-1] \ + and elem.leading_lines \ + and elem.leading_lines[-1] \ + and elem.leading_lines[-1].comment \ + and elem.leading_lines[-1].comment.value \ + and elem.leading_lines[-1].comment.value[1:].strip() + return False + + def leave_Assign(self, original_node: cst.Assign, updated_node: cst.Assign) -> cst.CSTNode: + """ + Handle the Table assignment + """ + + # Check if the value of the assignment is a Table call + lhs_name = original_node.targets[0].target.value + if lhs_name in tables_i_cannot_update: + return updated_node + + if not is_table_assign(original_node): + # If this is not FOO = Table(BAR), leave as is + return original_node + + latest_table_def: cst.Assign = self.latest_tables.get(lhs_name) + if not latest_table_def: + return original_node + + # If the original node is commented, consider it as hand-updated so leave as is + if isinstance(original_node, cst.SimpleStatementLine): + if original_node.leading_lines and original_node.leading_lines[-1].comment: + return original_node + + # Going to replace the table with the new one + updated_node = latest_table_def + + # updated_node = updated_node.with_changes(value=) + rh_new = updated_node.value + rh_old = original_node.value + + # Assignments do have ards + if hasattr(rh_new, 'args') and hasattr(rh_old, 'args'): + # + # This seems not needed + # + # foreign_key_constaints = {} + # simple_indecies = {} + # for new_col in rh_new.args: + # if isinstance(new_col.value, cst.Call): + # if new_col.value.func.value == "ForeignKeyConstraint": + # # see the args + # # args[0] is the list of columns on this table, and args[1] is the far table + # # if it's simple, remember + # cols = new_col.value.args[0] + # far = new_col.value.args[1] + # if len(cols.value.elements) == 1 and len(far.value.elements) == 1: + # # this is a simple foreign key ref + # foreign_key_constaints[cols.value.elements[0]] = far.value.elements[0] + # + # elif new_col.value.func.value == "Index": + # index_name = new_col.value.args[0] + # columns = new_col.value.args[1:] + # if len(columns) == 1: + # simple_indecies[index_name.value.value] = columns[0].value.value + + # Collect the old columns to look at + columns = {} + for old_col in rh_old.args: + # I only care the Column("foo") + if isinstance(old_col.value, cst.Call) and old_col.value.func.value == "Column": + # column def + column_name = old_col.value.args[0].value.value + columns[column_name] = old_col + + for i_col, new_column in enumerate(rh_new.args): + # I only care the Column("") + if isinstance(new_column.value, cst.Call) and new_column.value.func.value == "Column": + # new column def and matching one + column_name = new_column.value.args[0].value.value + old_column = columns.get(column_name) + + # If the old one exists... + if old_column: + # Copy the server_default= value + patched_call = copy_server_default(new_column.value, old_column.value) + if not patched_call.deep_equals(new_column.value): + column = new_column.with_changes(value = patched_call) + updated_node = updated_node.with_changes( + value = updated_node.value.with_changes( + args=[ + *updated_node.value.args[:i_col], + column, + *updated_node.value.args[i_col + 1:] + ] + ) + ) + + + return updated_node + + +def find_classes_and_tables(tree: cst.CSTNode): + classes = {} + tables = {} + + for node in tree.body: + if isinstance(node, cst.ClassDef): + classes[node.name.value] = node + if is_table_def(node): + tables[node.body[0].targets[0].target.value] = node.body[0] + return classes, tables + +# ================================================================================================================ + +# + +def is_port_open(host: str, port: int): + """See the TCP port is open or not""" + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + sock.settimeout(1) + result = sock.connect_ex((host, port)) + return result == 0 + + +def run_mysql_container(port: int): + """Start a mysql docker""" + mysql_image = "mysql:5.7.20" + try: + subprocess.run(["docker", "pull", mysql_image], check=True) + + subprocess.run( + [ + "docker", "run", "-d", "--name", "mysql-test", + "-e", "MYSQL_ROOT_PASSWORD=testpassword", + "-e", "MYSQL_USER=testuser", + "-e", "MYSQL_PASSWORD=testpassword", + "-e", "MYSQL_DATABASE=testdb", + "-p", f"{port}:3306", + mysql_image + ], + check=True + ) + logging.info("MySQL Docker container started successfully.") + except subprocess.CalledProcessError as e: + logging.error(f"Error: {e}") + except Exception as e: + logging.error(f"Unexpected error: {e}") + + +def load_sql_file(sql_file): + """Load a sql file to mysql + + If you see + +ERROR 1840 (HY000) at line 24: @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty. +ERROR:root:Error loading SQL file: Command '['mysql', '--host=127.0.0.1', '-uroot', '-ptestpassword', 'testdb']' returned non-zero exit status 1. + + it means that the sql is already loaded so ignore the error. + + """ + with open(sql_file, encoding="utf-8") as sql: + try: + subprocess.run(["mysql", "--host=127.0.0.1", "-uroot", "-ptestpassword", "testdb"], + stdin=sql, check=True) + logging.info(f"SQL file '{sql_file}' loaded successfully into 'testdb'.") + except subprocess.CalledProcessError as e: + logging.error(f"Error loading SQL file: {e}") + except Exception as e: + logging.error(f"Unexpected error: {e}") + + +def main() -> None: + + # This is the default mysql port. If you are using a native MySQL, that's fine. If you don't want to install + # mysql, it uses the MySQL docker. + mysql_port = 3306 + + arxiv_base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + p_outfile = os.path.join(arxiv_base_dir, "arxiv/db/autogen_models.py") + db_metadata = os.path.join(arxiv_base_dir, "arxiv/db/arxiv-db-metadata.yaml") + codegen_dir = os.path.join(arxiv_base_dir, "development/sqlacodegen") + + # If there is no MySQL up and running, start a container + if not is_port_open("127.0.0.1", mysql_port): + run_mysql_container(mysql_port) + for _ in range(20): + if is_port_open("127.0.0.1", mysql_port): + break + time.sleep(1) + + # Load the arxiv_db_schema.sql to the database. + load_sql_file(os.path.join(arxiv_base_dir, "development/arxiv_db_schema.sql")) + + p_url = "mysql://testuser:testpassword@127.0.0.1/testdb" + sys.path.append(os.path.join(codegen_dir, "src")) + subprocess.run(['venv/bin/python', '-m', 'sqlacodegen', p_url, '--outfile', p_outfile, + '--model-metadata', db_metadata], check=True, cwd=arxiv_base_dir) + + # autogen_models.py + with open(p_outfile, 'r') as src: + source = src.read() + + # Parse the autogen + try: + latest_tree = cst.parse_module(source) + except Exception as exc: + logging.error("%s: failed to parse", p_outfile, exc_info=exc) + exit(1) + + # Traverse the autogen and build the dicts + latest_classes, latest_tables = find_classes_and_tables(latest_tree) + + # Parse the exiting models + with open(os.path.join(arxiv_base_dir, 'arxiv/db/orig_models.py'), encoding='utf-8') as model_fd: + existing_models = model_fd.read() + existing_tree = cst.parse_module(existing_models) + + # Also build the dicts for the existing models and tables + existing_classes, existing_tables = find_classes_and_tables(existing_tree) + + # Warn of tables not mentioned in the existing model. This means the new table added and the + # exiting model does not know about it. + new_classes: [str] = list(set(latest_classes.keys()) - set(existing_classes.keys())) + new_classes.remove('Base') # base shows up here but Base is imported in existing models.py + if new_classes: + logging.warning("NEW CLASSES! Add this to the original") + for new_class in new_classes: + logging.warning(f"class {new_class}") + + new_tables = list(set(latest_tables.keys()) - set(existing_tables.keys())) + if new_tables: + logging.warning("NEW TABLES! Add this to the original") + for new_table in new_tables: + logging.warning(f"class {new_table}") + + # Merge the exiting and latest models + transformer = SchemaTransformer(latest_classes, latest_tables) + updated_tree = existing_tree.visit(transformer) + + # Write out the models after the merge + updated_model = os.path.join(arxiv_base_dir, 'arxiv/db/models.py') + with open(updated_model, "w", encoding='utf-8') as updated_fd: + updated_fd.write(updated_tree.code) + + # Patch the models with regex + # 1. MySQL types are replaced with the generic types. + # 2. sqlacodegen and db/models.py import things differently (eg from datatime import datatime) + # These can be done with hacking sqlacodegen but decided on the quick-and-dirty. + with open(updated_model, encoding='utf-8') as updated_fd: + contents = updated_fd.read() + contents = patch_mysql_types(contents) + with open(updated_model, 'w', encoding='utf-8') as updated_fd: + updated_fd.write(contents) + + # Then, make the code look neat. + subprocess.run(['black', "-l", "200", updated_model]) + + +if __name__ == "__main__": + """ + patch arxiv/db/autogen_models.py arxiv/db/autogen_models_patch.diff + """ + main() diff --git a/development/dump-schema.sh b/development/dump-schema.sh new file mode 100755 index 000000000..6f69eaffe --- /dev/null +++ b/development/dump-schema.sh @@ -0,0 +1,4 @@ +#!/bin/bash +# +PASSWORD=$(< ~/.arxiv/arxvi-db-read-only-password) +mysqldump -h 127.0.0.1 --port 2021 -u readonly -p"$PASSWORD" --no-data arXiv > arxiv_db_schema.sql diff --git a/development/extract_class_n_table.py b/development/extract_class_n_table.py new file mode 100644 index 000000000..536822856 --- /dev/null +++ b/development/extract_class_n_table.py @@ -0,0 +1,40 @@ +import json +import ast +from ruamel.yaml import YAML +import sys + +def extract_class_table_mapping(filename: str): + with open(filename, 'r') as src: + source = src.read() + + parse_tree = ast.parse(source) + + class_table_mapping = {} + + for node in ast.walk(parse_tree): + if isinstance(node, ast.ClassDef): + class_name = node.name + table_name = None + + # Walk through the class body to find __tablename__ assignments + for body_item in node.body: + if isinstance(body_item, ast.Assign): + for target in body_item.targets: + if isinstance(target, ast.Name) and target.id == "__tablename__": + if isinstance(body_item.value, ast.Str): + table_name = body_item.value.s + + if table_name: + class_table_mapping[table_name] = class_name + + return class_table_mapping + +if __name__ == '__main__': + output = sys.stdout + filename = 'arxiv/db/models.py' # Replace this with the path to your Python file + if len(sys.argv) > 1: + filename = sys.argv[1] + class_table_mapping = extract_class_table_mapping(filename) + yaml = YAML() + yaml.dump(class_table_mapping, output) + diff --git a/development/load_arxiv_db_schema.py b/development/load_arxiv_db_schema.py new file mode 100644 index 000000000..e133f8603 --- /dev/null +++ b/development/load_arxiv_db_schema.py @@ -0,0 +1,101 @@ +#!/usr/bin/python3 +import os +import sys +import subprocess +import logging +import time +import shlex +import argparse + +from development.run_mysql_container import is_port_open, run_mysql_container + +logging.basicConfig(level=logging.INFO) + +arxiv_base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.append(arxiv_base_dir) + + +def main(mysql_port: int, db_name: str, root_password: str="rootpassword", schema_sql: str="arxiv_db_schema.sql", + use_ssl: bool = False, + ) -> None: + conn_argv = [f"--port={mysql_port}", "-h", "127.0.0.1", "-u", "root", f"--password={root_password}"] + if not use_ssl: + conn_argv.append("--ssl-mode=DISABLED") + + if not is_port_open("127.0.0.1", mysql_port): + run_mysql_container(mysql_port, container_name="fake-arxiv-db", db_name=db_name, root_password=root_password) + + cli = ["mysql"] + conn_argv + [db_name] + for _ in range(20): + if is_port_open("127.0.0.1", mysql_port): + try: + mysql = subprocess.Popen(cli, encoding="utf-8", + stdin=subprocess.PIPE, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + mysql.communicate("select 1") + if mysql.returncode == 0: + break + except Exception as e: + print(e) + pass + time.sleep(1) + + if not os.path.exists(schema_sql) and ("/" not in schema_sql): + schema_sql = os.path.join(os.path.dirname(__file__), schema_sql) + try: + with open(schema_sql, encoding="utf-8") as schema_file: + subprocess.call(cli, encoding="utf-8", stdin=schema_file, timeout=60) + except: + logger.error("%s", shlex.join(cli), exc_info=True) + exit(1) + finally: + logger.info("Finish loading schema") + exit(0) + + +if __name__ == "__main__": + """ + """ + logger = logging.getLogger() + logger.setLevel(logging.DEBUG) + parser = argparse.ArgumentParser(description="populate database schema") + + # Add arguments for db_name and db_port + parser.add_argument( + "--db_name", + type=str, + default="testdb", + help="The name of the database", + ) + parser.add_argument( + "--db_port", + type=int, + default="3306", + help="The port number for the database", + ) + + parser.add_argument( + "--root_password", + type=str, + default="rootpassword", + help="Root password", + ) + + parser.add_argument( + "--schema", + type=str, + default="arxiv_db_schema.sql", + help="arXiv db Schema", + ) + + parser.add_argument( + "--use_ssl", + help="Use SSL", + action="store_true", + ) + + args = parser.parse_args() + db_port = int(args.db_port) + db_name = args.db_name + + logger.info("port : %s name: %s", db_port, db_name) + main(db_port, db_name, root_password=args.root_password, schema_sql=args.schema, use_ssl=args.use_ssl) diff --git a/development/populate_arxiv_db.py b/development/populate_arxiv_db.py new file mode 100644 index 000000000..24da30ba0 --- /dev/null +++ b/development/populate_arxiv_db.py @@ -0,0 +1,187 @@ +#!/usr/bin/python3 +""" +Create the db schema from arxiv/db/models.py + +NOTE: This does not work as the db/models is not fully expressing the original schema and thus +it cannot satisfy the database constraints. + +The code exists for more of less for the referencing purpose. +If one day, if we ditch the tests using sqlite3 and always use mysql, we can ues MySQL +data types instead of generic Python types and this would work. + +""" +import os +from sqlalchemy import create_engine, text +from sqlalchemy.orm import sessionmaker +from sqlalchemy.engine import Engine +import tempfile +import sqlite3 +import sys +import socket +import subprocess +import logging +import time +import shlex +import argparse + +logging.basicConfig(level=logging.INFO) + +arxiv_base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +sys.path.append(arxiv_base_dir) + +# Without this import, Base.metadata does not get populated. So it may look doing nothing but do not remove this. +import arxiv.db.models + +from arxiv.db import Base, LaTeXMLBase, session_factory, _classic_engine as classic_engine + + +def is_port_open(host: str, port: int): + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + sock.settimeout(1) + result = sock.connect_ex((host, port)) + return result == 0 + + +def _make_schemas(db_engine: Engine): + SessionLocal = sessionmaker(autocommit=False, autoflush=True) + SessionLocal.configure(bind=db_engine) + db_session = SessionLocal(autocommit=False, autoflush=True) + + Base.metadata.drop_all(db_engine) + Base.metadata.create_all(db_engine) + LaTeXMLBase.metadata.drop_all(db_engine) + LaTeXMLBase.metadata.create_all(db_engine) + + db_session.commit() + + +def run_mysql_container(port: int, container_name="mysql-test", db_name="testdb"): + """Start a mysql docker""" + mysql_image = "mysql:5.7.20" + + subprocess.run(["docker", "pull", mysql_image], check=True) + + subprocess.run(["docker", "rm", container_name], check=False) + + argv = [ + "docker", "run", "-d", "--name", container_name, + "-e", "MYSQL_ROOT_PASSWORD=testpassword", + "-e", "MYSQL_USER=testuser", + "-e", "MYSQL_PASSWORD=testpassword", + "-e", "MYSQL_DATABASE=" + db_name, + "-p", f"{port}:3306", + mysql_image + ] + + try: + subprocess.run(argv, check=True) + logging.info("MySQL Docker container started successfully.") + except subprocess.CalledProcessError as e: + logging.error(f"Error: {e}\n\n{shlex.join(argv)}") + except Exception as e: + logging.error(f"Unexpected error: {e}\n\n{shlex.join(argv)}") + + + + ping = ["mysql"] + conn_argv + [db_name] + logger.info(shlex.join(ping)) + + for _ in range(20): + try: + mysql = subprocess.Popen(ping, encoding="utf-8", stdin=subprocess.PIPE) + mysql.communicate("select 1") + if mysql.returncode == 0: + break + except Exception as e: + print(e) + pass + time.sleep(1) + + +def wait_for_mysql_docker(ping): + logger = logging.getLogger() + + for _ in range(20): + try: + mysql = subprocess.Popen(ping, encoding="utf-8", stdin=subprocess.PIPE) + mysql.communicate("select 1") + if mysql.returncode == 0: + break + except Exception as e: + print(e) + pass + time.sleep(1) + + +def main(mysql_port, db_name, root_password="rootpassword") -> None: + logger = logging.getLogger() + conn_argv = [f"--port={mysql_port}", "-h", "127.0.0.1", "-u", "root", f"--password={root_password}", + # "--ssl-mode=DISABLED" + ] + + if not is_port_open("127.0.0.1", mysql_port): + run_mysql_container(mysql_port, container_name="schema-creation-test-arxiv-db", db_name=db_name) + + ping = ["mysql"] + conn_argv + [db_name] + logger.info(shlex.join(ping)) + wait_for_mysql_docker(ping) + + + db_uri = f"mysql://testuser:testpassword@127.0.0.1:{mysql_port}/{db_name}" + db_engine = create_engine(db_uri) + + for _ in range(30): + try: + SessionLocal = sessionmaker(autocommit=False, autoflush=True) + SessionLocal.configure(bind=db_engine) + db_session = SessionLocal(autocommit=False, autoflush=True) + + db_session.commit() + break + except: + pass + time.sleep(1) + + + _make_schemas(db_engine) + + with open("schema-from-arxiv-db-model.sql", "w", encoding="utf-8") as sql_file: + subprocess.run(["mysqldump"] + conn_argv + ["--no-data", db_name], + stdout=sql_file, check=True) + + +if __name__ == "__main__": + logger = logging.getLogger() + logger.setLevel(logging.DEBUG) + logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO) + + parser = argparse.ArgumentParser(description="populate database schema") + + # Add arguments for db_name and db_port + parser.add_argument( + "--db_name", + type=str, + default="testdb", + help="The name of the database", + ) + parser.add_argument( + "--db_port", + type=int, + default="3306", + help="The port number for the database", + ) + + parser.add_argument( + "--root_password", + type=str, + default="rootpassword", + help="Root password", + ) + + args = parser.parse_args() + db_port = int(args.db_port) + db_name = args.db_name + + logger.info("port : %s name: %s", db_port, db_name) + main(db_port, db_name, root_password=args.root_password) diff --git a/development/run_mysql_container.py b/development/run_mysql_container.py new file mode 100644 index 000000000..c987320b8 --- /dev/null +++ b/development/run_mysql_container.py @@ -0,0 +1,132 @@ +#!/usr/bin/python3 +import os +import sys +import socket +import subprocess +import logging +import time +import shlex +import argparse + +logging.basicConfig(level=logging.INFO) + +arxiv_base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.append(arxiv_base_dir) + +def is_port_open(host: str, port: int) -> bool: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + sock.settimeout(1) + result = sock.connect_ex((host, port)) + return result == 0 + + +def run_mysql_container(port: int, container_name: str ="mysql-test", db_name: str ="testdb", + root_password: str = "rootpassword") -> None: + """Start a mysql docker""" + # mysql_image = "mysql:8.0.40" + mysql_image = "mysql:5.7.20" + + subprocess.run(["docker", "pull", mysql_image], check=True) + # subprocess.run(["docker", "kill", container_name], check=False) + subprocess.run(["docker", "rm", container_name], check=False) + + argv = [ + "docker", "run", "-d", "--name", container_name, + "-e", f"MYSQL_ROOT_PASSWORD={root_password}", + "-e", "MYSQL_USER=testuser", + "-e", "MYSQL_PASSWORD=testpassword", + "-e", "MYSQL_DATABASE=" + db_name, + "-p", f"{port}:3306", + mysql_image, + # Add this for mysql 8 and up to turn off SSL connection + # "--require_secure_transport=OFF" + ] + + try: + subprocess.run(argv, check=True) + logging.info("MySQL Docker container started successfully.") + except subprocess.CalledProcessError as e: + logging.error(f"Error: {e}\n\n{shlex.join(argv)}") + except Exception as e: + logging.error(f"Unexpected error: {e}\n\n{shlex.join(argv)}") + + +def stop_mysql_container(port: int, container_name: str = "mysql-test") -> None: + """Start a mysql docker""" + + subprocess.run(["docker", "kill", container_name], check=False) + for _ in range(10): + if not is_port_open("127.0.0.1", port): + break + + +def main(mysql_port: int, db_name: str, root_password: str = "rootpassword", restart: bool = False, use_ssl: bool =False) -> None: + conn_argv = [f"--port={mysql_port}", "-h", "127.0.0.1", "-u", "root", f"--password={root_password}"] + if not use_ssl: + conn_argv.append("--ssl=DISABLED") + + if is_port_open("127.0.0.1", mysql_port) and restart: + stop_mysql_container(mysql_port, container_name="fake-arxiv-db") + + if not is_port_open("127.0.0.1", mysql_port): + run_mysql_container(mysql_port, container_name="fake-arxiv-db", db_name=db_name, root_password=root_password) + + cli = ["mysql"] + conn_argv + [db_name] + for _ in range(20): + if is_port_open("127.0.0.1", mysql_port): + try: + mysql = subprocess.Popen(cli, encoding="utf-8", + stdin=subprocess.PIPE, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + mysql.communicate("select 1") + if mysql.returncode == 0: + break + except Exception as e: + print(e) + exit(1) + time.sleep(1) + + +if __name__ == "__main__": + logger = logging.getLogger() + logger.setLevel(logging.DEBUG) + parser = argparse.ArgumentParser(description="Run MySQL docker") + + # Add arguments for db_name and db_port + parser.add_argument( + "--db_name", + type=str, + default="testdb", + help="The name of the database", + ) + parser.add_argument( + "--db_port", + type=int, + default="3306", + help="The port number for the database", + ) + + parser.add_argument( + "--root_password", + type=str, + default="rootpassword", + help="Root password", + ) + + parser.add_argument( + "--restart", + help="Restart container", + action="store_true", + ) + + parser.add_argument( + "--use-ssl", + help="Use SSL", + action="store_true", + ) + + args = parser.parse_args() + db_port = int(args.db_port) + db_name = args.db_name + + logger.info("port : %s name: %s", db_port, db_name) + main(db_port, db_name, root_password=args.root_password, restart=args.restart, use_ssl=args.use_ssl) diff --git a/development/sqlacodegen/.gitignore b/development/sqlacodegen/.gitignore new file mode 100644 index 000000000..b5b2f478f --- /dev/null +++ b/development/sqlacodegen/.gitignore @@ -0,0 +1,15 @@ +*.egg-info +*.pyc +.project +.pydevproject +.coverage +.settings +.tox +.idea +.vscode +.cache +.pytest_cache +.mypy_cache +dist +build +venv* diff --git a/development/sqlacodegen/ARXIV-README.md b/development/sqlacodegen/ARXIV-README.md new file mode 100644 index 000000000..b99b1f9d8 --- /dev/null +++ b/development/sqlacodegen/ARXIV-README.md @@ -0,0 +1,167 @@ +# Changes from sqlacodegen + +When you run the original codegen, it it obvious the existing code has a quite a lot of changes made to it. +This creates a challenge to re-run the codegen and update the db/models.py. + +The overall codegen is driven by development/db_codegen.py, and the modification of sqlacodegen allows the +merging of existing and re-generated Python code. + +For example, when sqlacodegen runs, the model's class names are derived from the table name. This is not true +in our source code anymore. This was a starting point of modifying sqlacodegen. + +The key difference is that, the original codegen generates the faithful models of original tables. This is not +necessary for our use, as the python model is NOT the source of truth. +We need the db/models.py to be able to access data. +The database schema is instead managed externally and unfortunately somewhat ad-hoc. + +db/models.py is used to create new tables for testing so the Python model closely matching to the database has +some importance. + +There are 7 features added to sqlacodegen. + +1. Overriding the class name +2. Overriding the TableModel / Table selection +3. Manipulate the __table_args__ +4. Set the index/primary key attribute to the column definition from the table args. +5. Override the column definition +6. Override the relationship definition +7. Append the extra relationship + +NOTE: After all of these changes made, the original sqlacodegen allows to inject the "generator" class in a +CLI arg. So, I did not have to clone all of it. I however added CLI arg so the full-clone is not entirely +wasteful. + +## Use of codegen metadata + +arxiv/db/arxiv-db-metadata.yaml provides the input to the codegen. +The top-level key corresponds to the table name. + +This is an example of metadata for a table. + + arXiv_ownership_requests: + class_name: OwnershipRequest + table_args: drop + columns: + user_id: mapped_column(ForeignKey('tapir_users.user_id'), nullable=False, index=True, server_default=FetchedValue()) + endorsement_request_id: mapped_column(ForeignKey('arXiv_endorsement_requests.request_id'), index=True) + + relationships: + endorsement_request: "relationship('EndorsementRequest', primaryjoin='OwnershipRequest.endorsement_request_id == EndorsementRequest.request_id', back_populates='arXiv_ownership_requests')" + user: "relationship('TapirUser', primaryjoin='OwnershipRequest.user_id == TapirUser.user_id', back_populates='arXiv_ownership_requests')" + additional_relationships: + - "request_audit = relationship('OwnershipRequestsAudit', back_populates='ownership_request', uselist=False)" + - "documents = relationship('Document', secondary=t_arXiv_ownership_requests_papers)" + +### Definition of metadata + +For table model class: + + TABLE_NAME: + class_name: + + table_args: + - replace: [, ] + + columns: + : | + + relationships: + : + : + + additional_relationships: + - + +For table instance: + + TABLE_NAME: + indecies: + - replace: [, ] + +#### table_args + +When the `table_args` is given `drop` , it is dropped and does not appear in the output. +When `replace` is used, python's string replace is applied to it. There is no semantic consideration. + + arXiv_admin_metadata: + class_name: AdminMetadata + table_args: + - replace: ["Index('pidv', 'paper_id', 'version', unique=True)", "Index('arxiv_admin_pidv', 'paper_id', 'version', unique=True)"] + +In this case, `pidv` is renamed to `arxiv_admin_pidv`. This is done because `pidv` is used as a column name and +the model object cannot have both. This kind of hand-editing is in the original db/models.py but the metadata splits +it out so we can preserve the changes. + +#### columns + +You can override the RHS of column. For example: + + status: "mapped_column(Enum('new', 'frozen', 'published', 'rejected'), nullable=False, index=True, server_default=FetchedValue())" + +If the table schema has no concept of string literal enum but you want to define it, you may want to override +the generated definition. + +There are two types of column's RHS. One with type and without type. When the first character of RHS is ":", it is +a typed RHS. + +#### relationships + + relationships: + user: "" + +When there is no value, it is dropped. + + relationships: + user: "relationship('TapirUser', primaryjoin='CrossControl.user_id == TapirUser.user_id', back_populates='arXiv_cross_controls')" + +The value is used for the relationship. This is often used when the back_populates property name is changed from +the default value. (eg. dropping "arXiv_" or "controls" vs "control") + + relationships: + arXiv_categories: + arXiv_category: "relationship('Category', primaryjoin='and_(CrossControl.archive == Category.archive, CrossControl.subject_class == Category.subject_class)', back_populates='arXiv_cross_controls')" + +Here, from the DDL, the default name is `arXiv_categories` but it is renamed in the model to be `arXiv_category`. +This syntax allows to rename and give it the value. + +Note that, the field type is given from the DDL. Do not include the type in the value. Doing so causes the Python +syntax error. + +#### additional_relationships + +The string literals are appended to the relationship. + +#### indicies + +The table definition's Index uses same mechanism as table_args to patch up the index definition. + +## Class name designation + +`class_name` designates the class name used in the generated code. If the table is simple, you'd not get +the model class. Instead, the sqlacodegen generates a table definition. + +This is an example of Table object. + + t_arXiv_bad_pw = Table( + "arXiv_bad_pw", + metadata, + Column("user_id", Integer, nullable=False, server_default=FetchedValue()), + ) + +If you provide the table name with a class name, the codegen then generates the model class instead. +You must ues this very carefully since this is not a natural representation. This feature exists for maintaining +the existing table classes and if possible, avoid using this feature as you'd need to manipulate the class definition +in significant way. + + +## Development and debugging + +To run sqlacodegen under the debugger, it is highly recommended to run mysql on local machine, and load the schema +to replicate the tables without data. + +Once you have a local mysql, + + python -m sqlacodegen "mysql://testuser:testpassword@127.0.0.1/testdb" --outfile "arxiv/db/near_models.py" --model-metadata "arxiv/db/arxiv-db-metadata.yaml" + +to run it under debugger. `development/db_codegen.py` populates the docker mysql tables. Keep the docker mysql +running so you'd be able to repeatedly run the command without any impact to the production. diff --git a/development/sqlacodegen/CHANGES.rst b/development/sqlacodegen/CHANGES.rst new file mode 100644 index 000000000..f5dc1436f --- /dev/null +++ b/development/sqlacodegen/CHANGES.rst @@ -0,0 +1,189 @@ +Version history +=============== + +**3.0.0rc5** + +- Fixed pgvector support not working + +**3.0.0rc4** + +- Dropped support for Python 3.7 +- Dropped support for SQLAlchemy 1.x +- Added support for the ``pgvector`` extension (with help from KellyRousselHoomano) + +**3.0.0rc3** + +- Added support for SQLAlchemy 2 (PR by rbuffat with help from mhauru) +- Renamed ``--option`` to ``--options`` and made its values delimited by commas +- Restored CIText and GeoAlchemy2 support (PR by stavvy-rotte) + +**3.0.0rc2** + +- Added support for generating SQLModel classes (PR by Andrii Khirilov) +- Fixed code generation when a single-column index is unique or does not match the + dialect's naming convention (PR by Leonardus Chen) +- Fixed another problem where sequence schemas were not properly separated from the + sequence name +- Fixed invalid generated primary/secondaryjoin expressions in self-referential + many-to-many relationships by using lambdas instead of strings +- Fixed ``AttributeError`` when the declarative generator encounters a table name + already in singular form when ``--option use_inflect`` is enabled +- Increased minimum SQLAlchemy version to 1.4.36 to address issues with ``ForeignKey`` + and indexes, and to eliminate the PostgreSQL UUID column type annotation hack + +**3.0.0rc1** + +- Migrated all packaging/testing configuration to ``pyproject.toml`` +- Fixed unwarranted ``ForeignKey`` declarations appearing in column attributes when + there are named, single column foreign key constraints (PR by Leonardus Chen) +. Fixed ``KeyError`` when rendering an index without any columns +- Fixed improper handling of schema prefixes in sequence names in server defaults +- Fixed identically named tables from different schemas resulting in invalid generated + code +- Fixed imports caused by ``server_default`` conflicting with class attribute names +- Worked around PostgreSQL UUID columns getting ``Any`` as the type annotation + +**3.0.0b3** + +- Dropped support for Python < 3.7 +- Dropped support for SQLAlchemy 1.3 +- Added a ``__main__`` module which can be used as an alternate entry point to the CLI +- Added detection for sequence use in column defaults on PostgreSQL +- Fixed ``sqlalchemy.exc.InvalidRequestError`` when encountering a column named + "metadata" (regression from 2.0) +- Fixed missing ``MetaData`` import with ``DeclarativeGenerator`` when only plain tables + are generated +- Fixed invalid data classes being generated due to some relationships having been + rendered without a default value +- Improved translation of column names into column attributes where the column name has + whitespace at the beginning or end +- Modified constraint and index rendering to add them explicitly instead of using + shortcuts like ``unique=True``, ``index=True`` or ``primary=True`` when the constraint + or index has a name that does not match the default naming convention + +**3.0.0b2** + +- Fixed ``IDENTITY`` columns not rendering properly when they are part of the primary + key + +**3.0.0b1** + +**NOTE**: Both the API and the command line interface have been refactored in a +backwards incompatible fashion. Notably several command line options have been moved to +specific generators and are no longer visible from ``sqlacodegen --help``. Their +replacement are documented in the README. + +- Dropped support for Python < 3.6 +- Added support for Python 3.10 +- Added support for SQLAlchemy 1.4 +- Added support for bidirectional relationships (use ``--option nobidi``) to disable +- Added support for multiple schemas via ``--schemas`` +- Added support for ``IDENTITY`` columns +- Disabled inflection during table/relationship name generation by default + (use ``--option use_inflect`` to re-enable) +- Refactored the old ``CodeGenerator`` class into separate generator classes, selectable + via ``--generator`` +- Refactored several command line options into generator specific options: + + - ``--noindexes`` → ``--option noindexes`` + - ``--noconstraints`` → ``--option noconstraints`` + - ``--nocomments`` → ``--option nocomments`` + - ``--nojoined`` → ``--option nojoined`` (``declarative`` and ``dataclass`` generators + only) + - ``--noinflect`` → (now the default; use ``--option use_inflect`` instead) + (``declarative`` and ``dataclass`` generators only) +- Fixed missing import for ``JSONB`` ``astext_type`` argument +- Fixed generated column or relationship names colliding with imports or each other +- Fixed ``CompileError`` when encountering server defaults that contain colons (``:``) + +**2.3.0** + +- Added support for rendering computed columns +- Fixed ``--nocomments`` not taking effect (fix proposed by AzuresYang) +- Fixed handling of MySQL ``SET`` column types (and possibly others as well) + +**2.2.0** + +- Added support for rendering table comments (PR by David Hirschfeld) +- Fixed bad identifier names being generated for plain tables (PR by softwarepk) + +**2.1.0** + +- Dropped support for Python 3.4 +- Dropped support for SQLAlchemy 0.8 +- Added support for Python 3.7 and 3.8 +- Added support for SQLAlchemy 1.3 +- Added support for column comments (requires SQLAlchemy 1.2+; based on PR by koalas8) +- Fixed crash on unknown column types (``NullType``) + +**2.0.1** + +- Don't adapt dialect specific column types if they need special constructor arguments + (thanks Nicholas Martin for the PR) + +**2.0.0** + +- Refactored code for better reuse +- Dropped support for Python 2.6, 3.2 and 3.3 +- Dropped support for SQLAlchemy < 0.8 +- Worked around a bug regarding Enum on SQLAlchemy 1.2+ (``name`` was missing) +- Added support for Geoalchemy2 +- Fixed invalid class names being generated (fixes #60; PR by Dan O'Huiginn) +- Fixed array item types not being adapted or imported + (fixes #46; thanks to Martin Glauer and Shawn Koschik for help) +- Fixed attribute name of columns named ``metadata`` in mapped classes (fixes #62) +- Fixed rendered column types being changed from the original (fixes #11) +- Fixed server defaults which contain double quotes (fixes #7, #17, #28, #33, #36) +- Fixed ``secondary=`` not taking into account the association table's schema name + (fixes #30) +- Sort models by foreign key dependencies instead of schema and name (fixes #15, #16) + +**1.1.6** + +- Fixed compatibility with SQLAlchemy 1.0 +- Added an option to only generate tables + +**1.1.5** + +- Fixed potential assignment of columns or relationships into invalid attribute names + (fixes #10) +- Fixed unique=True missing from unique Index declarations +- Fixed several issues with server defaults +- Fixed potential assignment of columns or relationships into invalid attribute names +- Allowed pascal case for tables already using it +- Switched from Mercurial to Git + +**1.1.4** + +- Fixed compatibility with SQLAlchemy 0.9.0 + +**1.1.3** + +- Fixed compatibility with SQLAlchemy 0.8.3+ +- Migrated tests from nose to pytest + +**1.1.2** + +- Fixed non-default schema name not being present in __table_args__ (fixes #2) +- Fixed self referential foreign key causing column type to not be rendered +- Fixed missing "deferrable" and "initially" keyword arguments in ForeignKey constructs +- Fixed foreign key and check constraint handling with alternate schemas (fixes #3) + +**1.1.1** + +- Fixed TypeError when inflect could not determine the singular name of a table for a + many-to-1 relationship +- Fixed _IntegerType, _StringType etc. being rendered instead of proper types on MySQL + +**1.1.0** + +- Added automatic detection of joined-table inheritance +- Fixed missing class name prefix in primary/secondary joins in relationships +- Instead of wildcard imports, generate explicit imports dynamically (fixes #1) +- Use the inflect library to produce better guesses for table to class name conversion +- Automatically detect Boolean columns based on CheckConstraints +- Skip redundant CheckConstraints for Enum and Boolean columns + +**1.0.0** + +- Initial release diff --git a/development/sqlacodegen/CONTRIBUTING.rst b/development/sqlacodegen/CONTRIBUTING.rst new file mode 100644 index 000000000..56145058a --- /dev/null +++ b/development/sqlacodegen/CONTRIBUTING.rst @@ -0,0 +1,47 @@ +Contributing to sqlacodegen +=========================== + +If you wish to contribute a fix or feature to sqlacodegen, please follow the following +guidelines. + +When you make a pull request against the main sqlacodegen codebase, Github runs the +sqlacodegen test suite against your modified code. Before making a pull request, you +should ensure that the modified code passes tests locally. To that end, the use of tox_ +is recommended. The default tox run first runs ``pre-commit`` and then the actual test +suite. To run the checks on all environments in parallel, invoke tox with ``tox -p``. + +To build the documentation, run ``tox -e docs`` which will generate a directory named +``build`` in which you may view the formatted HTML documentation. + +sqlacodegen uses pre-commit_ to perform several code style/quality checks. It is +recommended to activate pre-commit_ on your local clone of the repository (using +``pre-commit install``) to ensure that your changes will pass the same checks on GitHub. + +.. _tox: https://tox.readthedocs.io/en/latest/install.html +.. _pre-commit: https://pre-commit.com/#installation + +Making a pull request on Github +------------------------------- + +To get your changes merged to the main codebase, you need a Github account. + +#. Fork the repository (if you don't have your own fork of it yet) by navigating to the + `main sqlacodegen repository`_ and clicking on "Fork" near the top right corner. +#. Clone the forked repository to your local machine with + ``git clone git@github.com/yourusername/sqlacodegen``. +#. Create a branch for your pull request, like ``git checkout -b myfixname`` +#. Make the desired changes to the code base. +#. Commit your changes locally. If your changes close an existing issue, add the text + ``Fixes #XXX.`` or ``Closes #XXX.`` to the commit message (where XXX is the issue + number). +#. Push the changeset(s) to your forked repository (``git push``) +#. Navigate to Pull requests page on the original repository (not your fork) and click + "New pull request" +#. Click on the text "compare across forks". +#. Select your own fork as the head repository and then select the correct branch name. +#. Click on "Create pull request". + +If you have trouble, consult the `pull request making guide`_ on opensource.com. + +.. _main sqlacodegen repository: https://github.com/agronholm/sqlacodegen +.. _pull request making guide: https://opensource.com/article/19/7/create-pull-request-github diff --git a/development/sqlacodegen/LICENSE b/development/sqlacodegen/LICENSE new file mode 100644 index 000000000..07806f8af --- /dev/null +++ b/development/sqlacodegen/LICENSE @@ -0,0 +1,19 @@ +This is the MIT license: http://www.opensource.org/licenses/mit-license.php + +Copyright (c) Alex Grönholm + +Permission is hereby granted, free of charge, to any person obtaining a copy of this +software and associated documentation files (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/development/sqlacodegen/README.rst b/development/sqlacodegen/README.rst new file mode 100644 index 000000000..efcaf4941 --- /dev/null +++ b/development/sqlacodegen/README.rst @@ -0,0 +1,208 @@ + +Notice +====== + +Date: 2024-11-01 + +This is a diverged version of sqlacodegen. I'd like to feedback features to upstream but until then, +the chance of all the things done here is somewhat unlikely to be brought into the upstream, or at +least requires a lot of careful considerations in order to propose PR from this. See ARXIX-README.md. + +---- + +This is a tool that reads the structure of an existing database and generates the +appropriate SQLAlchemy model code, using the declarative style if possible. + +This tool was written as a replacement for `sqlautocode`_, which was suffering from +several issues (including, but not limited to, incompatibility with Python 3 and the +latest SQLAlchemy version). + +.. _sqlautocode: http://code.google.com/p/sqlautocode/ + + +Features +======== + +* Supports SQLAlchemy 2.x +* Produces declarative code that almost looks like it was hand written +* Produces `PEP 8`_ compliant code +* Accurately determines relationships, including many-to-many, one-to-one +* Automatically detects joined table inheritance +* Excellent test coverage + +.. _PEP 8: http://www.python.org/dev/peps/pep-0008/ + + +Installation +============ + +To install, do:: + + pip install sqlacodegen + +To include support for the PostgreSQL ``CITEXT`` extension type (which should be +considered as tested only under a few environments) specify the ``citext`` extra:: + + pip install sqlacodegen[citext] + + +To include support for the PostgreSQL ``GEOMETRY``, ``GEOGRAPHY``, and ``RASTER`` types +(which should be considered as tested only under a few environments) specify the +``geoalchemy2`` extra: + +To include support for the PostgreSQL ``PGVECTOR`` extension type, specify the +``pgvector`` extra:: + + pip install sqlacodegen[pgvector] + +.. code-block:: bash + + pip install sqlacodegen[geoalchemy2] + + +Quickstart +========== + +At the minimum, you have to give sqlacodegen a database URL. The URL is passed directly +to SQLAlchemy's `create_engine()`_ method so please refer to +`SQLAlchemy's documentation`_ for instructions on how to construct a proper URL. + +Examples:: + + sqlacodegen postgresql:///some_local_db + sqlacodegen --generator tables mysql+pymysql://user:password@localhost/dbname + sqlacodegen --generator dataclasses sqlite:///database.db + +To see the list of generic options:: + + sqlacodegen --help + +.. _create_engine(): http://docs.sqlalchemy.org/en/latest/core/engines.html#sqlalchemy.create_engine +.. _SQLAlchemy's documentation: http://docs.sqlalchemy.org/en/latest/core/engines.html + +Available generators +==================== + +The selection of a generator determines the + +The following built-in generators are available: + +* ``tables`` (only generates ``Table`` objects, for those who don't want to use the ORM) +* ``declarative`` (the default; generates classes inheriting from ``declarative_base()`` +* ``dataclasses`` (generates dataclass-based models; v1.4+ only) +* ``sqlmodels`` (generates model classes for SQLModel_) + +.. _SQLModel: https://sqlmodel.tiangolo.com/ + +Generator-specific options +========================== + +The following options can be turned on by passing them using ``--options`` (multiple +values must be delimited by commas, e.g. ``--options noconstraints,nobidi``): + +* ``tables`` + + * ``noconstraints``: ignore constraints (foreign key, unique etc.) + * ``nocomments``: ignore table/column comments + * ``noindexes``: ignore indexes + +* ``declarative`` + + * all the options from ``tables`` + * ``use_inflect``: use the ``inflect`` library when naming classes and relationships + (turning plural names into singular; see below for details) + * ``nojoined``: don't try to detect joined-class inheritance (see below for details) + * ``nobidi``: generate relationships in a unidirectional fashion, so only the + many-to-one or first side of many-to-many relationships gets a relationship + attribute, as on v2.X + +* ``dataclasses`` + + * all the options from ``declarative`` + +* ``sqlmodel`` + + * all the options from ``declarative`` + +Model class generators +---------------------- + +The code generators that generate classes try to generate model classes whenever +possible. There are two circumstances in which a ``Table`` is generated instead: + +* the table has no primary key constraint (which is required by SQLAlchemy for every + model class) +* the table is an association table between two other tables (see below for the + specifics) + +Model class naming logic +++++++++++++++++++++++++ + +By default, table names are converted to valid PEP 8 compliant class names by replacing +all characters unsuitable for Python identifiers with ``_``. Then, each valid parts +(separated by underscores) are title cased and then joined together, eliminating the +underscores. So, ``example_name`` becomes ``ExampleName``. + +If the ``use_inflect`` option is used, the table name (which is assumed to be in +English) is converted to singular form using the "inflect" library. For example, +``sales_invoices`` becomes ``SalesInvoice``. Since table names are not always in +English, and the inflection process is far from perfect, inflection is disabled by +default. + +Relationship detection logic +++++++++++++++++++++++++++++ + +Relationships are detected based on existing foreign key constraints as follows: + +* **many-to-one**: a foreign key constraint exists on the table +* **one-to-one**: same as **many-to-one**, but a unique constraint exists on the + column(s) involved +* **many-to-many**: (not implemented on the ``sqlmodel`` generator) an association table + is found to exist between two tables + +A table is considered an association table if it satisfies all of the following +conditions: + +#. has exactly two foreign key constraints +#. all its columns are involved in said constraints + +Relationship naming logic ++++++++++++++++++++++++++ + +Relationships are typically named based on the table name of the opposite class. +For example, if a class has a relationship to another class with the table named +``companies``, the relationship would be named ``companies`` (unless the ``use_inflect`` +option was enabled, in which case it would be named ``company`` in the case of a +many-to-one or one-to-one relationship). + +A special case for single column many-to-one and one-to-one relationships, however, is +if the column is named like ``employer_id``. Then the relationship is named ``employer`` +due to that ``_id`` suffix. + +For self referential relationships, the reverse side of the relationship will be named +with the ``_reverse`` suffix appended to it. + +Customizing code generation logic +================================= + +If the built-in generators with all their options don't quite do what you want, you can +customize the logic by subclassing one of the existing code generator classes. Override +whichever methods you need, and then add an `entry point`_ in the +``sqlacodegen.generators`` namespace that points to your new class. Once the entry point +is in place (you typically have to install the project with ``pip install``), you can +use ``--generator `` to invoke your custom code generator. + +For examples, you can look at sqlacodegen's own entry points in its `pyproject.toml`_. + +.. _entry point: https://setuptools.readthedocs.io/en/latest/userguide/entry_point.html +.. _pyproject.toml: https://github.com/agronholm/sqlacodegen/blob/master/pyproject.toml + +Getting help +============ + +If you have problems or other questions, you should start a discussion on the +`sqlacodegen discussion forum`_. As an alternative, you could also try your luck on the +sqlalchemy_ room on Gitter. + +.. _sqlacodegen discussion forum: https://github.com/agronholm/sqlacodegen/discussions/categories/q-a +.. _sqlalchemy: https://app.gitter.im/#/room/#sqlalchemy_community:gitter.im diff --git a/development/sqlacodegen/poetry.lock b/development/sqlacodegen/poetry.lock new file mode 100644 index 000000000..024f7369b --- /dev/null +++ b/development/sqlacodegen/poetry.lock @@ -0,0 +1,879 @@ +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. + +[[package]] +name = "annotated-types" +version = "0.7.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "coverage" +version = "7.6.1" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16"}, + {file = "coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959"}, + {file = "coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232"}, + {file = "coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"}, + {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"}, + {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d"}, + {file = "coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5"}, + {file = "coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155"}, + {file = "coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a"}, + {file = "coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3"}, + {file = "coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f"}, + {file = "coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657"}, + {file = "coverage-7.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0"}, + {file = "coverage-7.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989"}, + {file = "coverage-7.6.1-cp38-cp38-win32.whl", hash = "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7"}, + {file = "coverage-7.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8"}, + {file = "coverage-7.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255"}, + {file = "coverage-7.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36"}, + {file = "coverage-7.6.1-cp39-cp39-win32.whl", hash = "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c"}, + {file = "coverage-7.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca"}, + {file = "coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df"}, + {file = "coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d"}, +] + +[package.extras] +toml = ["tomli"] + +[[package]] +name = "exceptiongroup" +version = "1.2.2" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "geoalchemy2" +version = "0.15.2" +description = "Using SQLAlchemy with Spatial Databases" +optional = false +python-versions = ">=3.7" +files = [ + {file = "GeoAlchemy2-0.15.2-py3-none-any.whl", hash = "sha256:546455dc39f5bcdfc5b871e57d3f7546c8a6f798eb364c474200f488ace6fd32"}, + {file = "geoalchemy2-0.15.2.tar.gz", hash = "sha256:3af0272db927373e74ee3b064cdc9464ba08defdb945c51745db1b841482f5dc"}, +] + +[package.dependencies] +packaging = "*" +SQLAlchemy = ">=1.4" + +[package.extras] +shapely = ["Shapely (>=1.7)"] + +[[package]] +name = "greenlet" +version = "3.1.1" +description = "Lightweight in-process concurrent programming" +optional = false +python-versions = ">=3.7" +files = [ + {file = "greenlet-3.1.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:0bbae94a29c9e5c7e4a2b7f0aae5c17e8e90acbfd3bf6270eeba60c39fce3563"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fde093fb93f35ca72a556cf72c92ea3ebfda3d79fc35bb19fbe685853869a83"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:36b89d13c49216cadb828db8dfa6ce86bbbc476a82d3a6c397f0efae0525bdd0"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94b6150a85e1b33b40b1464a3f9988dcc5251d6ed06842abff82e42632fac120"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93147c513fac16385d1036b7e5b102c7fbbdb163d556b791f0f11eada7ba65dc"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da7a9bff22ce038e19bf62c4dd1ec8391062878710ded0a845bcf47cc0200617"}, + {file = "greenlet-3.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b2795058c23988728eec1f36a4e5e4ebad22f8320c85f3587b539b9ac84128d7"}, + {file = "greenlet-3.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ed10eac5830befbdd0c32f83e8aa6288361597550ba669b04c48f0f9a2c843c6"}, + {file = "greenlet-3.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:77c386de38a60d1dfb8e55b8c1101d68c79dfdd25c7095d51fec2dd800892b80"}, + {file = "greenlet-3.1.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e4d333e558953648ca09d64f13e6d8f0523fa705f51cae3f03b5983489958c70"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fc016b73c94e98e29af67ab7b9a879c307c6731a2c9da0db5a7d9b7edd1159"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5e975ca70269d66d17dd995dafc06f1b06e8cb1ec1e9ed54c1d1e4a7c4cf26e"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b2813dc3de8c1ee3f924e4d4227999285fd335d1bcc0d2be6dc3f1f6a318ec1"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e347b3bfcf985a05e8c0b7d462ba6f15b1ee1c909e2dcad795e49e91b152c383"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e8f8c9cb53cdac7ba9793c276acd90168f416b9ce36799b9b885790f8ad6c0a"}, + {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:62ee94988d6b4722ce0028644418d93a52429e977d742ca2ccbe1c4f4a792511"}, + {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1776fd7f989fc6b8d8c8cb8da1f6b82c5814957264d1f6cf818d475ec2bf6395"}, + {file = "greenlet-3.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:48ca08c771c268a768087b408658e216133aecd835c0ded47ce955381105ba39"}, + {file = "greenlet-3.1.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:4afe7ea89de619adc868e087b4d2359282058479d7cfb94970adf4b55284574d"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f406b22b7c9a9b4f8aa9d2ab13d6ae0ac3e85c9a809bd590ad53fed2bf70dc79"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c3a701fe5a9695b238503ce5bbe8218e03c3bcccf7e204e455e7462d770268aa"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2846930c65b47d70b9d178e89c7e1a69c95c1f68ea5aa0a58646b7a96df12441"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99cfaa2110534e2cf3ba31a7abcac9d328d1d9f1b95beede58294a60348fba36"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1443279c19fca463fc33e65ef2a935a5b09bb90f978beab37729e1c3c6c25fe9"}, + {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b7cede291382a78f7bb5f04a529cb18e068dd29e0fb27376074b6d0317bf4dd0"}, + {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:23f20bb60ae298d7d8656c6ec6db134bca379ecefadb0b19ce6f19d1f232a942"}, + {file = "greenlet-3.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:7124e16b4c55d417577c2077be379514321916d5790fa287c9ed6f23bd2ffd01"}, + {file = "greenlet-3.1.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:05175c27cb459dcfc05d026c4232f9de8913ed006d42713cb8a5137bd49375f1"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:935e943ec47c4afab8965954bf49bfa639c05d4ccf9ef6e924188f762145c0ff"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667a9706c970cb552ede35aee17339a18e8f2a87a51fba2ed39ceeeb1004798a"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8a678974d1f3aa55f6cc34dc480169d58f2e6d8958895d68845fa4ab566509e"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efc0f674aa41b92da8c49e0346318c6075d734994c3c4e4430b1c3f853e498e4"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e"}, + {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:275f72decf9932639c1c6dd1013a1bc266438eb32710016a1c742df5da6e60a1"}, + {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c4aab7f6381f38a4b42f269057aee279ab0fc7bf2e929e3d4abfae97b682a12c"}, + {file = "greenlet-3.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:b42703b1cf69f2aa1df7d1030b9d77d3e584a70755674d60e710f0af570f3761"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1695e76146579f8c06c1509c7ce4dfe0706f49c6831a817ac04eebb2fd02011"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7876452af029456b3f3549b696bb36a06db7c90747740c5302f74a9e9fa14b13"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ead44c85f8ab905852d3de8d86f6f8baf77109f9da589cb4fa142bd3b57b475"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8320f64b777d00dd7ccdade271eaf0cad6636343293a25074cc5566160e4de7b"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6510bf84a6b643dabba74d3049ead221257603a253d0a9873f55f6a59a65f822"}, + {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:04b013dc07c96f83134b1e99888e7a79979f1a247e2a9f59697fa14b5862ed01"}, + {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47da355d8687fd65240c364c90a31569a133b7b60de111c255ef5b606f2ae291"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:98884ecf2ffb7d7fe6bd517e8eb99d31ff7855a840fa6d0d63cd07c037f6a981"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1d4aeb8891338e60d1ab6127af1fe45def5259def8094b9c7e34690c8858803"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db32b5348615a04b82240cc67983cb315309e88d444a288934ee6ceaebcad6cc"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dcc62f31eae24de7f8dce72134c8651c58000d3b1868e01392baea7c32c247de"}, + {file = "greenlet-3.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1d3755bcb2e02de341c55b4fca7a745a24a9e7212ac953f6b3a48d117d7257aa"}, + {file = "greenlet-3.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b8da394b34370874b4572676f36acabac172602abf054cbc4ac910219f3340af"}, + {file = "greenlet-3.1.1-cp37-cp37m-win32.whl", hash = "sha256:a0dfc6c143b519113354e780a50381508139b07d2177cb6ad6a08278ec655798"}, + {file = "greenlet-3.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:54558ea205654b50c438029505def3834e80f0869a70fb15b871c29b4575ddef"}, + {file = "greenlet-3.1.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:346bed03fe47414091be4ad44786d1bd8bef0c3fcad6ed3dee074a032ab408a9"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfc59d69fc48664bc693842bd57acfdd490acafda1ab52c7836e3fc75c90a111"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21e10da6ec19b457b82636209cbe2331ff4306b54d06fa04b7c138ba18c8a81"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:37b9de5a96111fc15418819ab4c4432e4f3c2ede61e660b1e33971eba26ef9ba"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef9ea3f137e5711f0dbe5f9263e8c009b7069d8a1acea822bd5e9dae0ae49c8"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85f3ff71e2e60bd4b4932a043fbbe0f499e263c628390b285cb599154a3b03b1"}, + {file = "greenlet-3.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:95ffcf719966dd7c453f908e208e14cde192e09fde6c7186c8f1896ef778d8cd"}, + {file = "greenlet-3.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:03a088b9de532cbfe2ba2034b2b85e82df37874681e8c470d6fb2f8c04d7e4b7"}, + {file = "greenlet-3.1.1-cp38-cp38-win32.whl", hash = "sha256:8b8b36671f10ba80e159378df9c4f15c14098c4fd73a36b9ad715f057272fbef"}, + {file = "greenlet-3.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:7017b2be767b9d43cc31416aba48aab0d2309ee31b4dbf10a1d38fb7972bdf9d"}, + {file = "greenlet-3.1.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:396979749bd95f018296af156201d6211240e7a23090f50a8d5d18c370084dc3"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca9d0ff5ad43e785350894d97e13633a66e2b50000e8a183a50a88d834752d42"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f6ff3b14f2df4c41660a7dec01045a045653998784bf8cfcb5a525bdffffbc8f"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94ebba31df2aa506d7b14866fed00ac141a867e63143fe5bca82a8e503b36437"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73aaad12ac0ff500f62cebed98d8789198ea0e6f233421059fa68a5aa7220145"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63e4844797b975b9af3a3fb8f7866ff08775f5426925e1e0bbcfe7932059a12c"}, + {file = "greenlet-3.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7939aa3ca7d2a1593596e7ac6d59391ff30281ef280d8632fa03d81f7c5f955e"}, + {file = "greenlet-3.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d0028e725ee18175c6e422797c407874da24381ce0690d6b9396c204c7f7276e"}, + {file = "greenlet-3.1.1-cp39-cp39-win32.whl", hash = "sha256:5e06afd14cbaf9e00899fae69b24a32f2196c19de08fcb9f4779dd4f004e5e7c"}, + {file = "greenlet-3.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:3319aa75e0e0639bc15ff54ca327e8dc7a6fe404003496e3c6925cd3142e0e22"}, + {file = "greenlet-3.1.1.tar.gz", hash = "sha256:4ce3ac6cdb6adf7946475d7ef31777c26d94bccc377e070a7986bd2d5c515467"}, +] + +[package.extras] +docs = ["Sphinx", "furo"] +test = ["objgraph", "psutil"] + +[[package]] +name = "importlib-metadata" +version = "8.5.0" +description = "Read metadata from Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"}, + {file = "importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"}, +] + +[package.dependencies] +zipp = ">=3.20" + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +perf = ["ipython"] +test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +type = ["pytest-mypy"] + +[[package]] +name = "inflect" +version = "7.4.0" +description = "Correctly generate plurals, singular nouns, ordinals, indefinite articles" +optional = false +python-versions = ">=3.8" +files = [ + {file = "inflect-7.4.0-py3-none-any.whl", hash = "sha256:85af0997ee2bda942b1c1eed8c8a827abda91aa3e22d1efaa0eea817f9350ce7"}, + {file = "inflect-7.4.0.tar.gz", hash = "sha256:904baa17cc2cb74827a6c27b95692e95670dadc72b208b3e8c1c05aeed47026b"}, +] + +[package.dependencies] +more-itertools = ">=8.5.0" +typeguard = ">=4.0.1" +typing-extensions = {version = "*", markers = "python_version < \"3.9\""} + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["pygments", "pytest (>=6,!=8.1.*)"] +type = ["pytest-mypy"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "more-itertools" +version = "10.5.0" +description = "More routines for operating on iterables, beyond itertools" +optional = false +python-versions = ">=3.8" +files = [ + {file = "more-itertools-10.5.0.tar.gz", hash = "sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6"}, + {file = "more_itertools-10.5.0-py3-none-any.whl", hash = "sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef"}, +] + +[[package]] +name = "mypy" +version = "1.12.1" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mypy-1.12.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3d7d4371829184e22fda4015278fbfdef0327a4b955a483012bd2d423a788801"}, + {file = "mypy-1.12.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f59f1dfbf497d473201356966e353ef09d4daec48caeacc0254db8ef633a28a5"}, + {file = "mypy-1.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b947097fae68004b8328c55161ac9db7d3566abfef72d9d41b47a021c2fba6b1"}, + {file = "mypy-1.12.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:96af62050971c5241afb4701c15189ea9507db89ad07794a4ee7b4e092dc0627"}, + {file = "mypy-1.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:d90da248f4c2dba6c44ddcfea94bb361e491962f05f41990ff24dbd09969ce20"}, + {file = "mypy-1.12.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1230048fec1380faf240be6385e709c8570604d2d27ec6ca7e573e3bc09c3735"}, + {file = "mypy-1.12.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:02dcfe270c6ea13338210908f8cadc8d31af0f04cee8ca996438fe6a97b4ec66"}, + {file = "mypy-1.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a5a437c9102a6a252d9e3a63edc191a3aed5f2fcb786d614722ee3f4472e33f6"}, + {file = "mypy-1.12.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:186e0c8346efc027ee1f9acf5ca734425fc4f7dc2b60144f0fbe27cc19dc7931"}, + {file = "mypy-1.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:673ba1140a478b50e6d265c03391702fa11a5c5aff3f54d69a62a48da32cb811"}, + {file = "mypy-1.12.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9fb83a7be97c498176fb7486cafbb81decccaef1ac339d837c377b0ce3743a7f"}, + {file = "mypy-1.12.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:389e307e333879c571029d5b93932cf838b811d3f5395ed1ad05086b52148fb0"}, + {file = "mypy-1.12.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:94b2048a95a21f7a9ebc9fbd075a4fcd310410d078aa0228dbbad7f71335e042"}, + {file = "mypy-1.12.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ee5932370ccf7ebf83f79d1c157a5929d7ea36313027b0d70a488493dc1b179"}, + {file = "mypy-1.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:19bf51f87a295e7ab2894f1d8167622b063492d754e69c3c2fed6563268cb42a"}, + {file = "mypy-1.12.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d34167d43613ffb1d6c6cdc0cc043bb106cac0aa5d6a4171f77ab92a3c758bcc"}, + {file = "mypy-1.12.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:427878aa54f2e2c5d8db31fa9010c599ed9f994b3b49e64ae9cd9990c40bd635"}, + {file = "mypy-1.12.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5fcde63ea2c9f69d6be859a1e6dd35955e87fa81de95bc240143cf00de1f7f81"}, + {file = "mypy-1.12.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d54d840f6c052929f4a3d2aab2066af0f45a020b085fe0e40d4583db52aab4e4"}, + {file = "mypy-1.12.1-cp313-cp313-win_amd64.whl", hash = "sha256:20db6eb1ca3d1de8ece00033b12f793f1ea9da767334b7e8c626a4872090cf02"}, + {file = "mypy-1.12.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b16fe09f9c741d85a2e3b14a5257a27a4f4886c171d562bc5a5e90d8591906b8"}, + {file = "mypy-1.12.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0dcc1e843d58f444fce19da4cce5bd35c282d4bde232acdeca8279523087088a"}, + {file = "mypy-1.12.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e10ba7de5c616e44ad21005fa13450cd0de7caaa303a626147d45307492e4f2d"}, + {file = "mypy-1.12.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0e6fe449223fa59fbee351db32283838a8fee8059e0028e9e6494a03802b4004"}, + {file = "mypy-1.12.1-cp38-cp38-win_amd64.whl", hash = "sha256:dc6e2a2195a290a7fd5bac3e60b586d77fc88e986eba7feced8b778c373f9afe"}, + {file = "mypy-1.12.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:de5b2a8988b4e1269a98beaf0e7cc71b510d050dce80c343b53b4955fff45f19"}, + {file = "mypy-1.12.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:843826966f1d65925e8b50d2b483065c51fc16dc5d72647e0236aae51dc8d77e"}, + {file = "mypy-1.12.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9fe20f89da41a95e14c34b1ddb09c80262edcc295ad891f22cc4b60013e8f78d"}, + {file = "mypy-1.12.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8135ffec02121a75f75dc97c81af7c14aa4ae0dda277132cfcd6abcd21551bfd"}, + {file = "mypy-1.12.1-cp39-cp39-win_amd64.whl", hash = "sha256:a7b76fa83260824300cc4834a3ab93180db19876bce59af921467fd03e692810"}, + {file = "mypy-1.12.1-py3-none-any.whl", hash = "sha256:ce561a09e3bb9863ab77edf29ae3a50e65685ad74bba1431278185b7e5d5486e"}, + {file = "mypy-1.12.1.tar.gz", hash = "sha256:f5b3936f7a6d0e8280c9bdef94c7ce4847f5cdfc258fbb2c29a8c1711e8bb96d"}, +] + +[package.dependencies] +mypy-extensions = ">=1.0.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = ">=4.6.0" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "numpy" +version = "1.24.4" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "numpy-1.24.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0bfb52d2169d58c1cdb8cc1f16989101639b34c7d3ce60ed70b19c63eba0b64"}, + {file = "numpy-1.24.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ed094d4f0c177b1b8e7aa9cba7d6ceed51c0e569a5318ac0ca9a090680a6a1b1"}, + {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79fc682a374c4a8ed08b331bef9c5f582585d1048fa6d80bc6c35bc384eee9b4"}, + {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ffe43c74893dbf38c2b0a1f5428760a1a9c98285553c89e12d70a96a7f3a4d6"}, + {file = "numpy-1.24.4-cp310-cp310-win32.whl", hash = "sha256:4c21decb6ea94057331e111a5bed9a79d335658c27ce2adb580fb4d54f2ad9bc"}, + {file = "numpy-1.24.4-cp310-cp310-win_amd64.whl", hash = "sha256:b4bea75e47d9586d31e892a7401f76e909712a0fd510f58f5337bea9572c571e"}, + {file = "numpy-1.24.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f136bab9c2cfd8da131132c2cf6cc27331dd6fae65f95f69dcd4ae3c3639c810"}, + {file = "numpy-1.24.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2926dac25b313635e4d6cf4dc4e51c8c0ebfed60b801c799ffc4c32bf3d1254"}, + {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:222e40d0e2548690405b0b3c7b21d1169117391c2e82c378467ef9ab4c8f0da7"}, + {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7215847ce88a85ce39baf9e89070cb860c98fdddacbaa6c0da3ffb31b3350bd5"}, + {file = "numpy-1.24.4-cp311-cp311-win32.whl", hash = "sha256:4979217d7de511a8d57f4b4b5b2b965f707768440c17cb70fbf254c4b225238d"}, + {file = "numpy-1.24.4-cp311-cp311-win_amd64.whl", hash = "sha256:b7b1fc9864d7d39e28f41d089bfd6353cb5f27ecd9905348c24187a768c79694"}, + {file = "numpy-1.24.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1452241c290f3e2a312c137a9999cdbf63f78864d63c79039bda65ee86943f61"}, + {file = "numpy-1.24.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:04640dab83f7c6c85abf9cd729c5b65f1ebd0ccf9de90b270cd61935eef0197f"}, + {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5425b114831d1e77e4b5d812b69d11d962e104095a5b9c3b641a218abcc050e"}, + {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd80e219fd4c71fc3699fc1dadac5dcf4fd882bfc6f7ec53d30fa197b8ee22dc"}, + {file = "numpy-1.24.4-cp38-cp38-win32.whl", hash = "sha256:4602244f345453db537be5314d3983dbf5834a9701b7723ec28923e2889e0bb2"}, + {file = "numpy-1.24.4-cp38-cp38-win_amd64.whl", hash = "sha256:692f2e0f55794943c5bfff12b3f56f99af76f902fc47487bdfe97856de51a706"}, + {file = "numpy-1.24.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2541312fbf09977f3b3ad449c4e5f4bb55d0dbf79226d7724211acc905049400"}, + {file = "numpy-1.24.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9667575fb6d13c95f1b36aca12c5ee3356bf001b714fc354eb5465ce1609e62f"}, + {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3a86ed21e4f87050382c7bc96571755193c4c1392490744ac73d660e8f564a9"}, + {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d11efb4dbecbdf22508d55e48d9c8384db795e1b7b51ea735289ff96613ff74d"}, + {file = "numpy-1.24.4-cp39-cp39-win32.whl", hash = "sha256:6620c0acd41dbcb368610bb2f4d83145674040025e5536954782467100aa8835"}, + {file = "numpy-1.24.4-cp39-cp39-win_amd64.whl", hash = "sha256:befe2bf740fd8373cf56149a5c23a0f601e82869598d41f8e188a0e9869926f8"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:31f13e25b4e304632a4619d0e0777662c2ffea99fcae2029556b17d8ff958aef"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95f7ac6540e95bc440ad77f56e520da5bf877f87dca58bd095288dce8940532a"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e98f220aa76ca2a977fe435f5b04d7b3470c0a2e6312907b37ba6068f26787f2"}, + {file = "numpy-1.24.4.tar.gz", hash = "sha256:80f5e3a4e498641401868df4208b74581206afbee7cf7b8329daae82676d9463"}, +] + +[[package]] +name = "packaging" +version = "24.1" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, +] + +[[package]] +name = "pgvector" +version = "0.3.5" +description = "pgvector support for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pgvector-0.3.5-py3-none-any.whl", hash = "sha256:56cca90392e596ea18873c593ec858a1984a77d16d1f82b8d0c180e79ef1018f"}, + {file = "pgvector-0.3.5.tar.gz", hash = "sha256:e876c9ee382c4c2f7ee57691a4c4015d688c7222e47448ce310ded03ecfafe2f"}, +] + +[package.dependencies] +numpy = "*" + +[[package]] +name = "pluggy" +version = "1.5.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pydantic" +version = "2.9.2" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12"}, + {file = "pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f"}, +] + +[package.dependencies] +annotated-types = ">=0.6.0" +pydantic-core = "2.23.4" +typing-extensions = [ + {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, + {version = ">=4.6.1", markers = "python_version < \"3.13\""}, +] + +[package.extras] +email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata"] + +[[package]] +name = "pydantic-core" +version = "2.23.4" +description = "Core functionality for Pydantic validation and serialization" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic_core-2.23.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b"}, + {file = "pydantic_core-2.23.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f"}, + {file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3"}, + {file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071"}, + {file = "pydantic_core-2.23.4-cp310-none-win32.whl", hash = "sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119"}, + {file = "pydantic_core-2.23.4-cp310-none-win_amd64.whl", hash = "sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f"}, + {file = "pydantic_core-2.23.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8"}, + {file = "pydantic_core-2.23.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b"}, + {file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0"}, + {file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64"}, + {file = "pydantic_core-2.23.4-cp311-none-win32.whl", hash = "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f"}, + {file = "pydantic_core-2.23.4-cp311-none-win_amd64.whl", hash = "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3"}, + {file = "pydantic_core-2.23.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231"}, + {file = "pydantic_core-2.23.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126"}, + {file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e"}, + {file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24"}, + {file = "pydantic_core-2.23.4-cp312-none-win32.whl", hash = "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84"}, + {file = "pydantic_core-2.23.4-cp312-none-win_amd64.whl", hash = "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9"}, + {file = "pydantic_core-2.23.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc"}, + {file = "pydantic_core-2.23.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327"}, + {file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6"}, + {file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f"}, + {file = "pydantic_core-2.23.4-cp313-none-win32.whl", hash = "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769"}, + {file = "pydantic_core-2.23.4-cp313-none-win_amd64.whl", hash = "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5"}, + {file = "pydantic_core-2.23.4-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555"}, + {file = "pydantic_core-2.23.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12"}, + {file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2"}, + {file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb"}, + {file = "pydantic_core-2.23.4-cp38-none-win32.whl", hash = "sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6"}, + {file = "pydantic_core-2.23.4-cp38-none-win_amd64.whl", hash = "sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556"}, + {file = "pydantic_core-2.23.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a"}, + {file = "pydantic_core-2.23.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55"}, + {file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040"}, + {file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605"}, + {file = "pydantic_core-2.23.4-cp39-none-win32.whl", hash = "sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6"}, + {file = "pydantic_core-2.23.4-cp39-none-win_amd64.whl", hash = "sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e"}, + {file = "pydantic_core-2.23.4.tar.gz", hash = "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + +[[package]] +name = "pydocstyle" +version = "6.3.0" +description = "Python docstring style checker" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pydocstyle-6.3.0-py3-none-any.whl", hash = "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019"}, + {file = "pydocstyle-6.3.0.tar.gz", hash = "sha256:7ce43f0c0ac87b07494eb9c0b462c0b73e6ff276807f204d6b53edc72b7e44e1"}, +] + +[package.dependencies] +snowballstemmer = ">=2.2.0" + +[package.extras] +toml = ["tomli (>=1.2.3)"] + +[[package]] +name = "pytest" +version = "8.3.3" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, + {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=1.5,<2" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "ruamel-yaml" +version = "0.18.6" +description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruamel.yaml-0.18.6-py3-none-any.whl", hash = "sha256:57b53ba33def16c4f3d807c0ccbc00f8a6081827e81ba2491691b76882d0c636"}, + {file = "ruamel.yaml-0.18.6.tar.gz", hash = "sha256:8b27e6a217e786c6fbe5634d8f3f11bc63e0f80f6a5890f28863d9c45aac311b"}, +] + +[package.dependencies] +"ruamel.yaml.clib" = {version = ">=0.2.7", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.13\""} + +[package.extras] +docs = ["mercurial (>5.7)", "ryd"] +jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] + +[[package]] +name = "ruamel-yaml-clib" +version = "0.2.8" +description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" +optional = false +python-versions = ">=3.6" +files = [ + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win32.whl", hash = "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win32.whl", hash = "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win32.whl", hash = "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win_amd64.whl", hash = "sha256:1758ce7d8e1a29d23de54a16ae867abd370f01b5a69e1a3ba75223eaa3ca1a1b"}, + {file = "ruamel.yaml.clib-0.2.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a5aa27bad2bb83670b71683aae140a1f52b0857a2deff56ad3f6c13a017a26ed"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c58ecd827313af6864893e7af0a3bb85fd529f862b6adbefe14643947cfe2942"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:77159f5d5b5c14f7c34073862a6b7d34944075d9f93e681638f6d753606c6ce6"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7f67a1ee819dc4562d444bbafb135832b0b909f81cc90f7aa00260968c9ca1b3"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4ecbf9c3e19f9562c7fdd462e8d18dd902a47ca046a2e64dba80699f0b6c09b7"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:87ea5ff66d8064301a154b3933ae406b0863402a799b16e4a1d24d9fbbcbe0d3"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win32.whl", hash = "sha256:75e1ed13e1f9de23c5607fe6bd1aeaae21e523b32d83bb33918245361e9cc51b"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win_amd64.whl", hash = "sha256:3f215c5daf6a9d7bbed4a0a4f760f3113b10e82ff4c5c44bec20a68c8014f675"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:305889baa4043a09e5b76f8e2a51d4ffba44259f6b4c72dec8ca56207d9c6fe1"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win32.whl", hash = "sha256:955eae71ac26c1ab35924203fda6220f84dce57d6d7884f189743e2abe3a9fbe"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win_amd64.whl", hash = "sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win32.whl", hash = "sha256:84b554931e932c46f94ab306913ad7e11bba988104c5cff26d90d03f68258cd5"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win_amd64.whl", hash = "sha256:25ac8c08322002b06fa1d49d1646181f0b2c72f5cbc15a85e80b4c30a544bb15"}, + {file = "ruamel.yaml.clib-0.2.8.tar.gz", hash = "sha256:beb2e0404003de9a4cab9753a8805a8fe9320ee6673136ed7f04255fe60bb512"}, +] + +[[package]] +name = "snowballstemmer" +version = "2.2.0" +description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." +optional = false +python-versions = "*" +files = [ + {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, + {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, +] + +[[package]] +name = "sqlalchemy" +version = "2.0.36" +description = "Database Abstraction Library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "SQLAlchemy-2.0.36-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:59b8f3adb3971929a3e660337f5dacc5942c2cdb760afcabb2614ffbda9f9f72"}, + {file = "SQLAlchemy-2.0.36-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37350015056a553e442ff672c2d20e6f4b6d0b2495691fa239d8aa18bb3bc908"}, + {file = "SQLAlchemy-2.0.36-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8318f4776c85abc3f40ab185e388bee7a6ea99e7fa3a30686580b209eaa35c08"}, + {file = "SQLAlchemy-2.0.36-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c245b1fbade9c35e5bd3b64270ab49ce990369018289ecfde3f9c318411aaa07"}, + {file = "SQLAlchemy-2.0.36-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:69f93723edbca7342624d09f6704e7126b152eaed3cdbb634cb657a54332a3c5"}, + {file = "SQLAlchemy-2.0.36-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f9511d8dd4a6e9271d07d150fb2f81874a3c8c95e11ff9af3a2dfc35fe42ee44"}, + {file = "SQLAlchemy-2.0.36-cp310-cp310-win32.whl", hash = "sha256:c3f3631693003d8e585d4200730616b78fafd5a01ef8b698f6967da5c605b3fa"}, + {file = "SQLAlchemy-2.0.36-cp310-cp310-win_amd64.whl", hash = "sha256:a86bfab2ef46d63300c0f06936bd6e6c0105faa11d509083ba8f2f9d237fb5b5"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fd3a55deef00f689ce931d4d1b23fa9f04c880a48ee97af488fd215cf24e2a6c"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4f5e9cd989b45b73bd359f693b935364f7e1f79486e29015813c338450aa5a71"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0ddd9db6e59c44875211bc4c7953a9f6638b937b0a88ae6d09eb46cced54eff"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2519f3a5d0517fc159afab1015e54bb81b4406c278749779be57a569d8d1bb0d"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59b1ee96617135f6e1d6f275bbe988f419c5178016f3d41d3c0abb0c819f75bb"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:39769a115f730d683b0eb7b694db9789267bcd027326cccc3125e862eb03bfd8"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-win32.whl", hash = "sha256:66bffbad8d6271bb1cc2f9a4ea4f86f80fe5e2e3e501a5ae2a3dc6a76e604e6f"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-win_amd64.whl", hash = "sha256:23623166bfefe1487d81b698c423f8678e80df8b54614c2bf4b4cfcd7c711959"}, + {file = "SQLAlchemy-2.0.36-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7b64e6ec3f02c35647be6b4851008b26cff592a95ecb13b6788a54ef80bbdd4"}, + {file = "SQLAlchemy-2.0.36-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:46331b00096a6db1fdc052d55b101dbbfc99155a548e20a0e4a8e5e4d1362855"}, + {file = "SQLAlchemy-2.0.36-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdf3386a801ea5aba17c6410dd1dc8d39cf454ca2565541b5ac42a84e1e28f53"}, + {file = "SQLAlchemy-2.0.36-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac9dfa18ff2a67b09b372d5db8743c27966abf0e5344c555d86cc7199f7ad83a"}, + {file = "SQLAlchemy-2.0.36-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:90812a8933df713fdf748b355527e3af257a11e415b613dd794512461eb8a686"}, + {file = "SQLAlchemy-2.0.36-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1bc330d9d29c7f06f003ab10e1eaced295e87940405afe1b110f2eb93a233588"}, + {file = "SQLAlchemy-2.0.36-cp312-cp312-win32.whl", hash = "sha256:79d2e78abc26d871875b419e1fd3c0bca31a1cb0043277d0d850014599626c2e"}, + {file = "SQLAlchemy-2.0.36-cp312-cp312-win_amd64.whl", hash = "sha256:b544ad1935a8541d177cb402948b94e871067656b3a0b9e91dbec136b06a2ff5"}, + {file = "SQLAlchemy-2.0.36-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b5cc79df7f4bc3d11e4b542596c03826063092611e481fcf1c9dfee3c94355ef"}, + {file = "SQLAlchemy-2.0.36-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3c01117dd36800f2ecaa238c65365b7b16497adc1522bf84906e5710ee9ba0e8"}, + {file = "SQLAlchemy-2.0.36-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bc633f4ee4b4c46e7adcb3a9b5ec083bf1d9a97c1d3854b92749d935de40b9b"}, + {file = "SQLAlchemy-2.0.36-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e46ed38affdfc95d2c958de328d037d87801cfcbea6d421000859e9789e61c2"}, + {file = "SQLAlchemy-2.0.36-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b2985c0b06e989c043f1dc09d4fe89e1616aadd35392aea2844f0458a989eacf"}, + {file = "SQLAlchemy-2.0.36-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a121d62ebe7d26fec9155f83f8be5189ef1405f5973ea4874a26fab9f1e262c"}, + {file = "SQLAlchemy-2.0.36-cp313-cp313-win32.whl", hash = "sha256:0572f4bd6f94752167adfd7c1bed84f4b240ee6203a95e05d1e208d488d0d436"}, + {file = "SQLAlchemy-2.0.36-cp313-cp313-win_amd64.whl", hash = "sha256:8c78ac40bde930c60e0f78b3cd184c580f89456dd87fc08f9e3ee3ce8765ce88"}, + {file = "SQLAlchemy-2.0.36-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:be9812b766cad94a25bc63bec11f88c4ad3629a0cec1cd5d4ba48dc23860486b"}, + {file = "SQLAlchemy-2.0.36-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50aae840ebbd6cdd41af1c14590e5741665e5272d2fee999306673a1bb1fdb4d"}, + {file = "SQLAlchemy-2.0.36-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4557e1f11c5f653ebfdd924f3f9d5ebfc718283b0b9beebaa5dd6b77ec290971"}, + {file = "SQLAlchemy-2.0.36-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:07b441f7d03b9a66299ce7ccf3ef2900abc81c0db434f42a5694a37bd73870f2"}, + {file = "SQLAlchemy-2.0.36-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:28120ef39c92c2dd60f2721af9328479516844c6b550b077ca450c7d7dc68575"}, + {file = "SQLAlchemy-2.0.36-cp37-cp37m-win32.whl", hash = "sha256:b81ee3d84803fd42d0b154cb6892ae57ea6b7c55d8359a02379965706c7efe6c"}, + {file = "SQLAlchemy-2.0.36-cp37-cp37m-win_amd64.whl", hash = "sha256:f942a799516184c855e1a32fbc7b29d7e571b52612647866d4ec1c3242578fcb"}, + {file = "SQLAlchemy-2.0.36-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3d6718667da04294d7df1670d70eeddd414f313738d20a6f1d1f379e3139a545"}, + {file = "SQLAlchemy-2.0.36-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:72c28b84b174ce8af8504ca28ae9347d317f9dba3999e5981a3cd441f3712e24"}, + {file = "SQLAlchemy-2.0.36-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b11d0cfdd2b095e7b0686cf5fabeb9c67fae5b06d265d8180715b8cfa86522e3"}, + {file = "SQLAlchemy-2.0.36-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e32092c47011d113dc01ab3e1d3ce9f006a47223b18422c5c0d150af13a00687"}, + {file = "SQLAlchemy-2.0.36-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6a440293d802d3011028e14e4226da1434b373cbaf4a4bbb63f845761a708346"}, + {file = "SQLAlchemy-2.0.36-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c54a1e53a0c308a8e8a7dffb59097bff7facda27c70c286f005327f21b2bd6b1"}, + {file = "SQLAlchemy-2.0.36-cp38-cp38-win32.whl", hash = "sha256:1e0d612a17581b6616ff03c8e3d5eff7452f34655c901f75d62bd86449d9750e"}, + {file = "SQLAlchemy-2.0.36-cp38-cp38-win_amd64.whl", hash = "sha256:8958b10490125124463095bbdadda5aa22ec799f91958e410438ad6c97a7b793"}, + {file = "SQLAlchemy-2.0.36-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dc022184d3e5cacc9579e41805a681187650e170eb2fd70e28b86192a479dcaa"}, + {file = "SQLAlchemy-2.0.36-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b817d41d692bf286abc181f8af476c4fbef3fd05e798777492618378448ee689"}, + {file = "SQLAlchemy-2.0.36-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4e46a888b54be23d03a89be510f24a7652fe6ff660787b96cd0e57a4ebcb46d"}, + {file = "SQLAlchemy-2.0.36-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4ae3005ed83f5967f961fd091f2f8c5329161f69ce8480aa8168b2d7fe37f06"}, + {file = "SQLAlchemy-2.0.36-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:03e08af7a5f9386a43919eda9de33ffda16b44eb11f3b313e6822243770e9763"}, + {file = "SQLAlchemy-2.0.36-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3dbb986bad3ed5ceaf090200eba750b5245150bd97d3e67343a3cfed06feecf7"}, + {file = "SQLAlchemy-2.0.36-cp39-cp39-win32.whl", hash = "sha256:9fe53b404f24789b5ea9003fc25b9a3988feddebd7e7b369c8fac27ad6f52f28"}, + {file = "SQLAlchemy-2.0.36-cp39-cp39-win_amd64.whl", hash = "sha256:af148a33ff0349f53512a049c6406923e4e02bf2f26c5fb285f143faf4f0e46a"}, + {file = "SQLAlchemy-2.0.36-py3-none-any.whl", hash = "sha256:fddbe92b4760c6f5d48162aef14824add991aeda8ddadb3c31d56eb15ca69f8e"}, + {file = "sqlalchemy-2.0.36.tar.gz", hash = "sha256:7f2767680b6d2398aea7082e45a774b2b0767b5c8d8ffb9c8b683088ea9b29c5"}, +] + +[package.dependencies] +greenlet = {version = "!=0.4.17", markers = "python_version < \"3.13\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} +typing-extensions = ">=4.6.0" + +[package.extras] +aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"] +aioodbc = ["aioodbc", "greenlet (!=0.4.17)"] +aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] +asyncio = ["greenlet (!=0.4.17)"] +asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (!=0.4.17)"] +mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5,!=1.1.10)"] +mssql = ["pyodbc"] +mssql-pymssql = ["pymssql"] +mssql-pyodbc = ["pyodbc"] +mypy = ["mypy (>=0.910)"] +mysql = ["mysqlclient (>=1.4.0)"] +mysql-connector = ["mysql-connector-python"] +oracle = ["cx_oracle (>=8)"] +oracle-oracledb = ["oracledb (>=1.0.1)"] +postgresql = ["psycopg2 (>=2.7)"] +postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] +postgresql-pg8000 = ["pg8000 (>=1.29.1)"] +postgresql-psycopg = ["psycopg (>=3.0.7)"] +postgresql-psycopg2binary = ["psycopg2-binary"] +postgresql-psycopg2cffi = ["psycopg2cffi"] +postgresql-psycopgbinary = ["psycopg[binary] (>=3.0.7)"] +pymysql = ["pymysql"] +sqlcipher = ["sqlcipher3_binary"] + +[[package]] +name = "sqlalchemy-citext" +version = "1.8.0" +description = "A sqlalchemy plugin that allows postgres use of CITEXT." +optional = false +python-versions = "*" +files = [ + {file = "sqlalchemy-citext-1.8.0.tar.gz", hash = "sha256:a1740e693a9a334e7c8f60ae731083fe75ce6c1605bb9ca6644a6f1f63b15b77"}, +] + +[package.dependencies] +SQLAlchemy = ">=0.6" + +[[package]] +name = "sqlmodel" +version = "0.0.22" +description = "SQLModel, SQL databases in Python, designed for simplicity, compatibility, and robustness." +optional = false +python-versions = ">=3.7" +files = [ + {file = "sqlmodel-0.0.22-py3-none-any.whl", hash = "sha256:a1ed13e28a1f4057cbf4ff6cdb4fc09e85702621d3259ba17b3c230bfb2f941b"}, + {file = "sqlmodel-0.0.22.tar.gz", hash = "sha256:7d37c882a30c43464d143e35e9ecaf945d88035e20117bf5ec2834a23cbe505e"}, +] + +[package.dependencies] +pydantic = ">=1.10.13,<3.0.0" +SQLAlchemy = ">=2.0.14,<2.1.0" + +[[package]] +name = "tomli" +version = "2.0.2" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38"}, + {file = "tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed"}, +] + +[[package]] +name = "typeguard" +version = "4.3.0" +description = "Run-time type checker for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typeguard-4.3.0-py3-none-any.whl", hash = "sha256:4d24c5b39a117f8a895b9da7a9b3114f04eb63bade45a4492de49b175b6f7dfa"}, + {file = "typeguard-4.3.0.tar.gz", hash = "sha256:92ee6a0aec9135181eae6067ebd617fd9de8d75d714fb548728a4933b1dea651"}, +] + +[package.dependencies] +importlib-metadata = {version = ">=3.6", markers = "python_version < \"3.10\""} +typing-extensions = ">=4.10.0" + +[package.extras] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme (>=1.3.0)"] +test = ["coverage[toml] (>=7)", "mypy (>=1.2.0)", "pytest (>=7)"] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + +[[package]] +name = "zipp" +version = "3.20.2" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.8" +files = [ + {file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"}, + {file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"}, +] + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +type = ["pytest-mypy"] + +[extras] +test = [] + +[metadata] +lock-version = "2.0" +python-versions = ">=3.8" +content-hash = "9bff1881085c3218507be95158a19367ee28abe3675bbd74b909191af9af1557" diff --git a/development/sqlacodegen/pyproject.toml b/development/sqlacodegen/pyproject.toml new file mode 100644 index 000000000..f546c3e98 --- /dev/null +++ b/development/sqlacodegen/pyproject.toml @@ -0,0 +1,100 @@ +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" + +[tool.poetry] +name = "sqlacodegen" +description = "Automatic model code generator for SQLAlchemy" +version = "0.1.0" # Define a fixed version or use a dynamic versioning tool +readme = "README.rst" +authors = ["Alex Grönholm "] +license = "MIT" +keywords = ["sqlalchemy"] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Environment :: Console", + "Topic :: Database", + "Topic :: Software Development :: Code Generators", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", +] +repository = "https://github.com/agronholm/sqlacodegen" +homepage = "https://github.com/agronholm/sqlacodegen" +documentation = "https://github.com/agronholm/sqlacodegen" + +[tool.poetry.dependencies] +python = ">=3.8" +SQLAlchemy = ">=2.0.23" +inflect = ">=4.0.0" +importlib_metadata = {version = "*", markers = "python_version < '3.10'"} +sqlmodel = ">=0.0.12" +sqlalchemy-citext = ">=1.7.0" +geoalchemy2 = ">=0.11.1" +pgvector = ">=0.2.4" +ruamel-yaml = "^0.18.6" + +[tool.poetry.dev-dependencies] +pydocstyle = "*" +mypy = "*" +pytest = "*" +coverage = ">=7.0" + +[tool.poetry.extras] +test = ["pytest", "coverage", "psycopg2-binary", "mysql-connector-python"] + +[tool.poetry.scripts] +sqlacodegen = "sqlacodegen.cli:main" + +[tool.poetry.plugins."sqlacodegen.generators"] +tables = "sqlacodegen.generators:TablesGenerator" +declarative = "sqlacodegen.generators:DeclarativeGenerator" +dataclasses = "sqlacodegen.generators:DataclassGenerator" +sqlmodels = "sqlacodegen.generators:SQLModelGenerator" + +[tool.setuptools_scm] +version_scheme = "post-release" +local_scheme = "dirty-tag" + +[tool.ruff] +select = [ + "E", "F", "W", # default Flake8 + "I", # isort + "ISC", # flake8-implicit-str-concat + "PGH", # pygrep-hooks + "RUF100", # unused noqa (yesqa) + "UP", # pyupgrade +] +src = ["src"] + +[tool.mypy] +strict = true + +[tool.pytest.ini_options] +addopts = "-rsx --tb=short" +testpaths = ["tests"] + +[coverage.run] +source = ["sqlacodegen"] +relative_files = true + +[coverage.report] +show_missing = true + +[tool.tox] +legacy_tox_ini = """ +[tox] +envlist = py38, py39, py310, py311, py312 +skip_missing_interpreters = true +minversion = 4.0.0 + +[testenv] +extras = test +commands = python -m pytest {posargs} +""" diff --git a/development/sqlacodegen/src/sqlacodegen/__init__.py b/development/sqlacodegen/src/sqlacodegen/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/development/sqlacodegen/src/sqlacodegen/__main__.py b/development/sqlacodegen/src/sqlacodegen/__main__.py new file mode 100644 index 000000000..4e28416e1 --- /dev/null +++ b/development/sqlacodegen/src/sqlacodegen/__main__.py @@ -0,0 +1,3 @@ +from .cli import main + +main() diff --git a/development/sqlacodegen/src/sqlacodegen/cli.py b/development/sqlacodegen/src/sqlacodegen/cli.py new file mode 100644 index 000000000..9f79e364c --- /dev/null +++ b/development/sqlacodegen/src/sqlacodegen/cli.py @@ -0,0 +1,128 @@ +from __future__ import annotations + +import argparse +import json +import os +import sys +from contextlib import ExitStack +from typing import TextIO + +from sqlalchemy.engine import create_engine +from sqlalchemy.schema import MetaData +from ruamel.yaml import YAML + +try: + import citext +except ImportError: + citext = None + +try: + import geoalchemy2 +except ImportError: + geoalchemy2 = None + +try: + import pgvector.sqlalchemy +except ImportError: + pgvector = None + +if sys.version_info < (3, 10): + from importlib_metadata import entry_points, version +else: + from importlib.metadata import entry_points, version + + +def main() -> None: + generators = {ep.name: ep for ep in entry_points(group="sqlacodegen.generators")} + parser = argparse.ArgumentParser( + description="Generates SQLAlchemy model code from an existing database." + ) + parser.add_argument("url", nargs="?", help="SQLAlchemy url to the database") + parser.add_argument( + "--options", help="options (comma-delimited) passed to the generator class" + ) + parser.add_argument( + "--version", action="store_true", help="print the version number and exit" + ) + parser.add_argument( + "--schemas", help="load tables from the given schemas (comma-delimited)" + ) + parser.add_argument( + "--generator", + choices=generators, + default="declarative", + help="generator class to use", + ) + parser.add_argument( + "--tables", help="tables to process (comma-delimited, default: all)" + ) + parser.add_argument( + "--model-metadata", help="the model's codegen metadata" + ) + parser.add_argument("--noviews", action="store_true", help="ignore views") + parser.add_argument("--outfile", help="file to write output to (default: stdout)") + args = parser.parse_args() + + if args.version: + print(version("sqlacodegen")) + return + + if not args.url: + print("You must supply a url\n", file=sys.stderr) + parser.print_help() + return + + if citext: + print(f"Using sqlalchemy-citext {version('citext')}") + + if geoalchemy2: + print(f"Using geoalchemy2 {version('geoalchemy2')}") + + if pgvector: + print(f"Using pgvector {version('pgvector')}") + + # Use reflection to fill in the metadata + naming_convention = { + "ix": "ix_%(table_name)s_%(column_0_label)s", + "uq": "uq_%(table_name)s_%(column_0_name)s", + "ck": "ck_%(table_name)s_%(constraint_name)s", + "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", + "pk": "pk_%(table_name)s" + } + + engine = create_engine(args.url) + metadata = MetaData(naming_convention=naming_convention) + tables = args.tables.split(",") if args.tables else None + schemas = args.schemas.split(",") if args.schemas else [None] + + options = set(args.options.split(",")) if args.options else set() + for schema in schemas: + metadata.reflect(engine, schema, not args.noviews, tables) + + kwargs = {} + if args.model_metadata: + with open(args.model_metadata, "r", encoding="utf-8") as metadata_fd: + if os.path.splitext(args.model_metadata)[1] == ".json": + kwargs["model_metadata"] = json.load(metadata_fd) + elif os.path.splitext(args.model_metadata)[1] == ".yaml": + yaml = YAML(typ="safe") + kwargs["model_metadata"] = yaml.load(metadata_fd) + else: + raise Exception("not supported") + + # Instantiate the generator + generator_class = generators[args.generator].load() + + generator = generator_class(metadata, engine, options, **kwargs) + + # Open the target file (if given) + with ExitStack() as stack: + outfile: TextIO + if args.outfile: + outfile = open(args.outfile, "w", encoding="utf-8") + stack.enter_context(outfile) + else: + outfile = sys.stdout + + # Write the generated model code to the specified file or standard output + outfile.write(generator.generate()) diff --git a/development/sqlacodegen/src/sqlacodegen/generators.py b/development/sqlacodegen/src/sqlacodegen/generators.py new file mode 100644 index 000000000..23808b334 --- /dev/null +++ b/development/sqlacodegen/src/sqlacodegen/generators.py @@ -0,0 +1,1658 @@ +from __future__ import annotations + +import inspect +import re +import sys +from abc import ABCMeta, abstractmethod +from collections import defaultdict +from collections.abc import Collection, Iterable, Sequence +from dataclasses import dataclass +from importlib import import_module +from inspect import Parameter +from itertools import count +from keyword import iskeyword +from pprint import pformat +from textwrap import indent +from typing import Any, ClassVar + +import inflect +import sqlalchemy +from sqlalchemy import ( + ARRAY, + Boolean, + CheckConstraint, + Column, + Computed, + Constraint, + DefaultClause, + Enum, + Integer, + Float, + ForeignKey, + ForeignKeyConstraint, + Identity, + Index, + MetaData, + PrimaryKeyConstraint, + String, + Table, + Text, + UniqueConstraint, +) +from sqlalchemy.dialects.postgresql import JSONB +from sqlalchemy.engine import Connection, Engine +from sqlalchemy.exc import CompileError +from sqlalchemy.sql.elements import TextClause + +from .models import ( + ColumnAttribute, + JoinType, + Model, + ModelClass, + RelationshipAttribute, + RelationshipType, +) +from .utils import ( + decode_postgresql_sequence, + get_column_names, + get_common_fk_constraints, + get_compiled_expression, + get_constraint_sort_key, + qualified_table_name, + render_callable, + #uses_default_name, +) + +def uses_default_name(_constraint: Constraint | Index) -> bool: + return True + +if sys.version_info < (3, 10): + pass +else: + pass + +_re_boolean_check_constraint = re.compile(r"(?:.*?\.)?(.*?) IN \(0, 1\)") +_re_column_name = re.compile(r'(?:(["`]?).*\1\.)?(["`]?)(.*)\2') +_re_enum_check_constraint = re.compile(r"(?:.*?\.)?(.*?) IN \((.+)\)") +_re_enum_item = re.compile(r"'(.*?)(? str: + """ + Generate the code for the given metadata. + .. note:: May modify the metadata. + """ + + +@dataclass(eq=False) +class TablesGenerator(CodeGenerator): + valid_options: ClassVar[set[str]] = {"noindexes", "noconstraints", "nocomments"} + builtin_module_names: ClassVar[set[str]] = set(sys.builtin_module_names) | { + "dataclasses" + } + + def __init__( + self, + metadata: MetaData, + bind: Connection | Engine, + options: Sequence[str], + *, + indentation: str = " ", + model_metadata: dict = {}, + ): + super().__init__(metadata, bind, options) + self.indentation: str = indentation + self.imports: dict[str, set[str]] = defaultdict(set) + self.module_imports: set[str] = set() + self.model_metadata = model_metadata + self.names_map = model_metadata.get('_names_map_', {}) + + + def get_class_name_override(self, table_name: str, suggested: str): + opt = self.model_metadata.get(table_name) + if isinstance(opt, str): + raise Exception("not supported") + if isinstance(opt, dict): + return opt.get('class_name', suggested) + return suggested + + def get_arg_override(self, table: Table, keyword: str, default: str | None) -> str | None: + assert isinstance(table, Table) + result = default + override = self.model_metadata.get(table.name, None) + if isinstance(override, dict): + ops = override.get(keyword) + if ops == "drop": + if keyword == "table_args": + try: + value = eval(default) + charset = value.get("mysql_charset") + if charset: + return repr({"mysql_charset": charset}) + except: + return None if default is None else "" + pass + return None if default is None else "" + if ops: + for op in ops: + if result == None: + result = "" + if "replace" in op: + values = op["replace"] + result = result.replace(values[0], values[1]) + return result + + def get_column_overrides(self, table: Table) -> dict: + override = self.model_metadata.get(table.name, None) + if isinstance(override, dict): + return override.get("columns", {}) + return {} + + def get_column_type_override(self, table: Table, col_name: str) -> dict | None: + return self.get_column_overrides(table).get(col_name) + + + def get_relationship_overrides(self, table: Table) -> dict: + override = self.model_metadata.get(table.name, None) + if isinstance(override, dict): + return override.get("relationships", {}) + return {} + + def get_additional_relationships(self, table: Table) -> list[str]: + override = self.model_metadata.get(table.name, None) + if isinstance(override, dict): + add_ons = override.get("additional_relationships", []) + if add_ons and isinstance(add_ons, list): + return add_ons + return [] + + + def is_table_class(self, table: Table) -> bool: + """Returns true if table has corresponding class name""" + opt = self.model_metadata.get(table.name, None) + return isinstance(opt, dict) and 'class_name' in opt + + + def generate_base(self) -> None: + self.base = Base( + literal_imports=[LiteralImport("sqlalchemy", "MetaData")], + declarations=["metadata = MetaData()"], + metadata_ref="metadata", + ) + + def generate(self) -> str: + self.generate_base() + + if self.bind.dialect.name == "mysql": + from .mysql_util import get_mysql_table_charsets + chasets = get_mysql_table_charsets(self.bind, self.bind.engine.url.database) + for table_name, charset in chasets.items(): + if table_name in self.model_metadata: + self.model_metadata[table_name]["charset"] = charset + else: + self.model_metadata[table_name] = {"charset": charset} + + sections: list[str] = [] + + # Remove unwanted elements from the metadata + for table in list(self.metadata.tables.values()): + if self.should_ignore_table(table): + self.metadata.remove(table) + continue + + if "noindexes" in self.options: + table.indexes.clear() + + if "noconstraints" in self.options: + table.constraints.clear() + + if "nocomments" in self.options: + table.comment = None + + for column in table.columns: + if "nocomments" in self.options: + column.comment = None + + # Use information from column constraints to figure out the intended column + # types + for table in self.metadata.tables.values(): + self.fix_column_types(table) + + # Generate the models + models: list[Model] = self.generate_models() + + # Render module level variables + variables = self.render_module_variables(models) + if variables: + sections.append(variables + "\n") + + # Render models + rendered_models = self.render_models(models) + if rendered_models: + sections.append(rendered_models) + + # Render collected imports + groups = self.group_imports() + imports = "\n\n".join("\n".join(line for line in group) for group in groups) + if imports: + sections.insert(0, imports) + + return "\n\n".join(sections) + "\n" + + def collect_imports(self, models: Iterable[Model]) -> None: + for literal_import in self.base.literal_imports: + self.add_literal_import(literal_import.pkgname, literal_import.name) + + for model in models: + self.collect_imports_for_model(model) + + def collect_imports_for_model(self, model: Model) -> None: + if model.__class__ is Model: + self.add_import(Table) + + for column in model.table.c: + self.collect_imports_for_column(column) + + for constraint in model.table.constraints: + self.collect_imports_for_constraint(constraint) + + for index in model.table.indexes: + self.collect_imports_for_constraint(index) + + def collect_imports_for_column(self, column: Column[Any]) -> None: + self.add_import(column.type) + + if isinstance(column.type, ARRAY): + self.add_import(column.type.item_type.__class__) + elif isinstance(column.type, JSONB): + if ( + not isinstance(column.type.astext_type, Text) + or column.type.astext_type.length is not None + ): + self.add_import(column.type.astext_type) + + if column.default: + self.add_import(column.default) + + if column.server_default: + if isinstance(column.server_default, (Computed, Identity)): + self.add_import(column.server_default) + elif isinstance(column.server_default, DefaultClause): + self.add_literal_import("sqlalchemy", "text") + + def collect_imports_for_constraint(self, constraint: Constraint | Index) -> None: + if isinstance(constraint, Index): + if len(constraint.columns) > 1 or not uses_default_name(constraint): + self.add_literal_import("sqlalchemy", "Index") + elif isinstance(constraint, PrimaryKeyConstraint): + if not uses_default_name(constraint): + self.add_literal_import("sqlalchemy", "PrimaryKeyConstraint") + elif isinstance(constraint, UniqueConstraint): + if len(constraint.columns) > 1 or not uses_default_name(constraint): + self.add_literal_import("sqlalchemy", "UniqueConstraint") + elif isinstance(constraint, ForeignKeyConstraint): + if len(constraint.columns) > 1 or not uses_default_name(constraint): + self.add_literal_import("sqlalchemy", "ForeignKeyConstraint") + else: + self.add_import(ForeignKey) + else: + self.add_import(constraint) + + def add_import(self, obj: Any) -> None: + # Don't store builtin imports + if getattr(obj, "__module__", "builtins") == "builtins": + return + + type_ = type(obj) if not isinstance(obj, type) else obj + pkgname = type_.__module__ + + # The column types have already been adapted towards generic types if possible, + # so if this is still a vendor specific type (e.g., MySQL INTEGER) be sure to + # use that rather than the generic sqlalchemy type as it might have different + # constructor parameters. + if pkgname.startswith("sqlalchemy.dialects."): + dialect_pkgname = ".".join(pkgname.split(".")[0:3]) + dialect_pkg = import_module(dialect_pkgname) + + if type_.__name__ in dialect_pkg.__all__: + pkgname = dialect_pkgname + elif type_.__name__ in dir(sqlalchemy): + pkgname = "sqlalchemy" + else: + pkgname = type_.__module__ + + self.add_literal_import(pkgname, type_.__name__) + + def add_literal_import(self, pkgname: str, name: str) -> None: + names = self.imports.setdefault(pkgname, set()) + names.add(name) + + def remove_literal_import(self, pkgname: str, name: str) -> None: + names = self.imports.setdefault(pkgname, set()) + if name in names: + names.remove(name) + + def add_module_import(self, pgkname: str) -> None: + self.module_imports.add(pgkname) + + def group_imports(self) -> list[list[str]]: + future_imports: list[str] = [] + stdlib_imports: list[str] = [] + thirdparty_imports: list[str] = [] + + for package in sorted(self.imports): + imports = ", ".join(sorted(self.imports[package])) + collection = thirdparty_imports + if package == "__future__": + collection = future_imports + elif package in self.builtin_module_names: + collection = stdlib_imports + elif package in sys.modules: + if "site-packages" not in (sys.modules[package].__file__ or ""): + collection = stdlib_imports + + collection.append(f"from {package} import {imports}") + + for module in sorted(self.module_imports): + thirdparty_imports.append(f"import {module}") + + return [ + group + for group in (future_imports, stdlib_imports, thirdparty_imports) + if group + ] + + def generate_models(self) -> list[Model]: + models = [Model(table) for table in self.metadata.sorted_tables] + + # Collect the imports + self.collect_imports(models) + + # Generate names for models + global_names = { + name for namespace in self.imports.values() for name in namespace + } + for model in models: + self.generate_model_name(model, global_names) + global_names.add(model.name) + + return models + + def generate_model_name(self, model: Model, global_names: set[str]) -> None: + preferred_name = self.get_class_name_override(model.table.name, f"t_{model.table.name}") + model.name = self.find_free_name(preferred_name, global_names) + + def render_module_variables(self, models: list[Model]) -> str: + declarations = self.base.declarations + + if any(not isinstance(model, ModelClass) for model in models): + if self.base.table_metadata_declaration is not None: + declarations.append(self.base.table_metadata_declaration) + + return "\n".join(declarations) + + def render_models(self, models: list[Model]) -> str: + rendered: list[str] = [] + for model in models: + rendered_table = self.render_table(model.table) + rendered.append(f"{model.name} = {rendered_table}") + + return "\n\n".join(rendered) + + def render_table(self, table: Table) -> str: + args: list[str] = [f"{table.name!r}, {self.base.metadata_ref}"] + kwargs: dict[str, object] = {} + + used_args = set() + for constraint in table.constraints: + if isinstance(constraint, PrimaryKeyConstraint): + if len(constraint.columns) == 1: + constraint.columns[0].primary_key = True + used_args.add(constraint) + + if isinstance(constraint, ForeignKeyConstraint): + if len(constraint.columns) == 1: + # constraint.columns[0].type = constraint.elements[0] + used_args.add(constraint) + + used_indecies = set() + for index in table.indexes: + if len(index.columns) == 1: + index.columns[0].index = True + used_indecies.add(index) + + for column in table.columns: + # Cast is required because of a bug in the SQLAlchemy stubs regarding + # Table.columns + args.append(self.render_column(column, True, is_table=True, table=table)) + + for constraint in sorted(table.constraints, key=get_constraint_sort_key): + if uses_default_name(constraint): + if isinstance(constraint, PrimaryKeyConstraint): + continue + elif isinstance(constraint, (ForeignKeyConstraint, UniqueConstraint)): + if len(constraint.columns) == 1: + continue + if constraint not in used_args: + args.append(self.render_constraint(constraint)) + + for index in sorted(table.indexes, key=lambda i: i.name): + # One-column indexes should be rendered as index=True on columns + if len(index.columns) > 1 or not uses_default_name(index): + if index not in used_indecies: + args.append(self.render_index(index, table)) + + if table.schema: + kwargs["schema"] = repr(table.schema) + + table_comment = getattr(table, "comment", None) + if table_comment: + kwargs["comment"] = repr(table.comment) + + return render_callable("Table", *args, kwargs=kwargs, indentation=" ") + + def render_index(self, index: Index, table: Table) -> str: + extra_args = [repr(col.name) for col in index.columns] + kwargs = {} + if index.unique: + kwargs["unique"] = True + + index_expr = render_callable("Index", repr(index.name), *extra_args, kwargs=kwargs) + return self.get_arg_override(table, "indecies", index_expr) + + # TODO find better solution for is_table + def render_column( + self, column: Column[Any], show_name: bool, is_table: bool = False, table: Table | None = None, + ) -> str: + args = [] + kwargs: dict[str, Any] = {} + kwarg = [] + is_sole_pk = column.primary_key and len(column.table.primary_key) == 1 + dedicated_fks = [ + c + for c in column.foreign_keys + if c.constraint + and len(c.constraint.columns) == 1 + # and uses_default_name(c.constraint) + ] + is_unique = any( + isinstance(c, UniqueConstraint) + and set(c.columns) == {column} + and uses_default_name(c) + for c in column.table.constraints + ) + is_unique = is_unique or any( + i.unique and set(i.columns) == {column} and uses_default_name(i) + for i in column.table.indexes + ) + is_primary = ( + any( + isinstance(c, PrimaryKeyConstraint) + and column.name in c.columns + and uses_default_name(c) + for c in column.table.constraints + ) + or column.primary_key + ) + has_index = any( + set(i.columns) == {column} and uses_default_name(i) + for i in column.table.indexes + ) or column.index + + if show_name: + args.append(repr(column.name)) + + # Render the column type if there are no foreign keys on it or any of them + # points back to itself + if not dedicated_fks or any(fk.column is column for fk in dedicated_fks): + args.append(self.render_column_type(column.type)) + + for fk in dedicated_fks: + args.append(self.render_constraint(fk)) + + if column.default: + args.append(repr(column.default)) + + if column.key != column.name: + kwargs["key"] = column.key + if is_primary: + kwargs["primary_key"] = True + if not column.nullable and not is_sole_pk: + kwargs["nullable"] = False + + if is_unique: + column.unique = True + kwargs["unique"] = True + if has_index: + column.index = True + kwarg.append("index") + kwargs["index"] = True + + if isinstance(column.server_default, DefaultClause): + kwargs["server_default"] = render_callable( + "text", repr(column.server_default.arg.text) + ) + elif isinstance(column.server_default, Computed): + expression = str(column.server_default.sqltext) + + computed_kwargs = {} + if column.server_default.persisted is not None: + computed_kwargs["persisted"] = column.server_default.persisted + + args.append( + render_callable("Computed", repr(expression), kwargs=computed_kwargs) + ) + elif isinstance(column.server_default, Identity): + args.append(repr(column.server_default)) + elif column.server_default: + kwargs["server_default"] = repr(column.server_default) + + comment = getattr(column, "comment", None) + if comment: + kwargs["comment"] = repr(comment) + + if is_table: + self.add_import(Column) + return render_callable("Column", *args, kwargs=kwargs) + else: + return render_callable("mapped_column", *args, kwargs=kwargs) + + def render_column_type(self, coltype: object) -> str: + args = [] + kwargs: dict[str, Any] = {} + sig = inspect.signature(coltype.__class__.__init__) + defaults = {param.name: param.default for param in sig.parameters.values()} + missing = object() + use_kwargs = False + for param in list(sig.parameters.values())[1:]: + # Remove annoyances like _warn_on_bytestring + if param.name.startswith("_"): + continue + elif param.kind in (Parameter.VAR_POSITIONAL, Parameter.VAR_KEYWORD): + continue + + value = getattr(coltype, param.name, missing) + default = defaults.get(param.name, missing) + if value is missing or value == default: + use_kwargs = True + elif use_kwargs: + kwargs[param.name] = repr(value) + else: + args.append(repr(value)) + + vararg = next( + ( + param.name + for param in sig.parameters.values() + if param.kind is Parameter.VAR_POSITIONAL + ), + None, + ) + if vararg and hasattr(coltype, vararg): + varargs_repr = [repr(arg) for arg in getattr(coltype, vararg)] + args.extend(varargs_repr) + + if isinstance(coltype, Enum) and coltype.name is not None: + kwargs["name"] = repr(coltype.name) + + if isinstance(coltype, JSONB): + # Remove astext_type if it's the default + if ( + isinstance(coltype.astext_type, Text) + and coltype.astext_type.length is None + ): + del kwargs["astext_type"] + + if args or kwargs: + return render_callable(coltype.__class__.__name__, *args, kwargs=kwargs) + else: + return coltype.__class__.__name__ + + def render_constraint(self, constraint: Constraint | ForeignKey) -> str: + def add_fk_options(*opts: Any) -> None: + args.extend(repr(opt) for opt in opts) + for attr in "ondelete", "onupdate", "deferrable", "initially", "match": + value = getattr(constraint, attr, None) + if value: + kwargs[attr] = repr(value) + + args: list[str] = [] + kwargs: dict[str, Any] = {} + if isinstance(constraint, ForeignKey): + remote_column = ( + f"{constraint.column.table.fullname}.{constraint.column.name}" + ) + add_fk_options(remote_column) + elif isinstance(constraint, ForeignKeyConstraint): + local_columns = get_column_names(constraint) + remote_columns = [ + f"{fk.column.table.fullname}.{fk.column.name}" + for fk in constraint.elements + ] + add_fk_options(local_columns, remote_columns) + elif isinstance(constraint, CheckConstraint): + args.append(repr(get_compiled_expression(constraint.sqltext, self.bind))) + elif isinstance(constraint, (UniqueConstraint, PrimaryKeyConstraint)): + args.extend(repr(col.name) for col in constraint.columns) + else: + raise TypeError( + f"Cannot render constraint of type {constraint.__class__.__name__}" + ) + + if isinstance(constraint, Constraint) and not uses_default_name(constraint): + kwargs["name"] = repr(constraint.name) + + return render_callable(constraint.__class__.__name__, *args, kwargs=kwargs) + + def should_ignore_table(self, table: Table) -> bool: + # Support for Alembic and sqlalchemy-migrate -- never expose the schema version + # tables + return table.name in ("alembic_version", "migrate_version") + + def find_free_name( + self, name: str, global_names: set[str], local_names: Collection[str] = () + ) -> str: + """ + Generate an attribute name that does not clash with other local or global names. + """ + name = name.strip() + assert name, "Identifier cannot be empty" + name = _re_invalid_identifier.sub("_", name) + name = self.names_map.get(name, name) + + if name[0].isdigit(): + name = "_" + name + elif iskeyword(name) or name == "metadata": + name += "_" + + original = name + for i in count(): + if name not in global_names and name not in local_names: + break + + name = original + (str(i) if i else "_") + + return name + + def fix_column_types(self, table: Table) -> None: + """Adjust the reflected column types.""" + # Detect check constraints for boolean and enum columns + for constraint in table.constraints.copy(): + if isinstance(constraint, CheckConstraint): + sqltext = get_compiled_expression(constraint.sqltext, self.bind) + + # Turn any integer-like column with a CheckConstraint like + # "column IN (0, 1)" into a Boolean + match = _re_boolean_check_constraint.match(sqltext) + if match: + colname_match = _re_column_name.match(match.group(1)) + if colname_match: + colname = colname_match.group(3) + table.constraints.remove(constraint) + table.c[colname].type = Boolean() + continue + + # Turn any string-type column with a CheckConstraint like + # "column IN (...)" into an Enum + match = _re_enum_check_constraint.match(sqltext) + if match: + colname_match = _re_column_name.match(match.group(1)) + if colname_match: + colname = colname_match.group(3) + items = match.group(2) + if isinstance(table.c[colname].type, String): + table.constraints.remove(constraint) + if not isinstance(table.c[colname].type, Enum): + options = _re_enum_item.findall(items) + table.c[colname].type = Enum( + *options, native_enum=False + ) + + continue + + for column in table.c: + try: + column.type = self.get_adapted_type(column.type) + except CompileError: + pass + + # PostgreSQL specific fix: detect sequences from server_default + if column.server_default and self.bind.dialect.name == "postgresql": + if isinstance(column.server_default, DefaultClause) and isinstance( + column.server_default.arg, TextClause + ): + schema, seqname = decode_postgresql_sequence( + column.server_default.arg + ) + if seqname: + # Add an explicit sequence + if seqname != f"{column.table.name}_{column.name}_seq": + column.default = sqlalchemy.Sequence(seqname, schema=schema) + + column.server_default = None + + def get_adapted_type(self, coltype: Any) -> Any: + compiled_type = coltype.compile(self.bind.engine.dialect) + for supercls in coltype.__class__.__mro__: + if not supercls.__name__.startswith("_") and hasattr( + supercls, "__visit_name__" + ): + # Hack to fix adaptation of the Enum class which is broken since + # SQLAlchemy 1.2 + kw = {} + if supercls is Enum: + kw["name"] = coltype.name + + try: + new_coltype = coltype.adapt(supercls) + except TypeError: + # If the adaptation fails, don't try again + break + + for key, value in kw.items(): + setattr(new_coltype, key, value) + + if isinstance(coltype, ARRAY): + new_coltype.item_type = self.get_adapted_type(new_coltype.item_type) + + try: + # If the adapted column type does not render the same as the + # original, don't substitute it + if new_coltype.compile(self.bind.engine.dialect) != compiled_type: + # Make an exception to the rule for Float and arrays of Float, + # since at least on PostgreSQL, Float can accurately represent + # both REAL and DOUBLE_PRECISION + if not isinstance(new_coltype, Float) and not ( + isinstance(new_coltype, ARRAY) + and isinstance(new_coltype.item_type, Float) + ): + break + except CompileError: + # If the adapted column type can't be compiled, don't substitute it + break + + # Stop on the first valid non-uppercase column type class + coltype = new_coltype + if supercls.__name__ != supercls.__name__.upper(): + break + + return coltype + + +class DeclarativeGenerator(TablesGenerator): + valid_options: ClassVar[set[str]] = TablesGenerator.valid_options | { + "use_inflect", + "nojoined", + "nobidi", + } + + def __init__( + self, + metadata: MetaData, + bind: Connection | Engine, + options: Sequence[str], + *, + indentation: str = " ", + base_class_name: str = "Base", + model_metadata: dict = {}, + ): + super().__init__(metadata, bind, options, indentation=indentation, model_metadata=model_metadata) + self.base_class_name: str = base_class_name + self.inflect_engine = inflect.engine() + + def generate_base(self) -> None: + self.base = Base( + literal_imports=[LiteralImport("sqlalchemy.orm", "DeclarativeBase")], + declarations=[ + f"class {self.base_class_name}(DeclarativeBase):", + f"{self.indentation}pass", + ], + metadata_ref=f"{self.base_class_name}.metadata", + ) + + def collect_imports(self, models: Iterable[Model]) -> None: + super().collect_imports(models) + if any(isinstance(model, ModelClass) for model in models): + self.add_literal_import("sqlalchemy.orm", "Mapped") + self.add_literal_import("sqlalchemy.orm", "mapped_column") + + def collect_imports_for_model(self, model: Model) -> None: + super().collect_imports_for_model(model) + if isinstance(model, ModelClass): + if model.relationships: + self.add_literal_import("sqlalchemy.orm", "relationship") + + def generate_models(self) -> list[Model]: + models_by_table_name: dict[str, Model] = {} + + # Pick association tables from the metadata into their own set, don't process + # them normally + links: defaultdict[str, list[Model]] = defaultdict(lambda: []) + for table in self.metadata.sorted_tables: + qualified_name = qualified_table_name(table) + + # Link tables have exactly two foreign key constraints and all columns are + # involved in them + fk_constraints = sorted( + table.foreign_key_constraints, key=get_constraint_sort_key + ) + if len(fk_constraints) == 2 and all( + col.foreign_keys for col in table.columns + ): + model = models_by_table_name[qualified_name] = Model(table) + tablename = fk_constraints[0].elements[0].column.table.name + links[tablename].append(model) + continue + + # Only form model classes for tables that have a primary key and are not + # association tables + if not table.primary_key and (not self.is_table_class(table)): + models_by_table_name[qualified_name] = Model(table) + else: + model = ModelClass(table) + models_by_table_name[qualified_name] = model + + # Fill in the columns + for column in table.c: + column_attr = ColumnAttribute(model, column) + model.columns.append(column_attr) + + # Add relationships + for model in models_by_table_name.values(): + if isinstance(model, ModelClass): + self.generate_relationships( + model, models_by_table_name, links[model.table.name] + ) + + # Nest inherited classes in their superclasses to ensure proper ordering + if "nojoined" not in self.options: + for model in list(models_by_table_name.values()): + if not isinstance(model, ModelClass): + continue + + pk_column_names = {col.name for col in model.table.primary_key.columns} + for constraint in model.table.foreign_key_constraints: + if set(get_column_names(constraint)) == pk_column_names: + target = models_by_table_name[ + qualified_table_name(constraint.elements[0].column.table) + ] + if isinstance(target, ModelClass): + model.parent_class = target + target.children.append(model) + + # Change base if we only have tables + if not any( + isinstance(model, ModelClass) for model in models_by_table_name.values() + ): + super().generate_base() + + # Collect the imports + self.collect_imports(models_by_table_name.values()) + + # Rename models and their attributes that conflict with imports or other + # attributes + global_names = { + name for namespace in self.imports.values() for name in namespace + } + for model in models_by_table_name.values(): + self.generate_model_name(model, global_names) + global_names.add(model.name) + + return list(models_by_table_name.values()) + + def generate_relationships( + self, + source: ModelClass, + models_by_table_name: dict[str, Model], + association_tables: list[Model], + ) -> list[RelationshipAttribute]: + relationships: list[RelationshipAttribute] = [] + reverse_relationship: RelationshipAttribute | None + + # Add many-to-one (and one-to-many) relationships + pk_column_names = {col.name for col in source.table.primary_key.columns} + for constraint in sorted( + source.table.foreign_key_constraints, key=get_constraint_sort_key + ): + target = models_by_table_name[ + qualified_table_name(constraint.elements[0].column.table) + ] + if isinstance(target, ModelClass): + if "nojoined" not in self.options: + if set(get_column_names(constraint)) == pk_column_names: + parent = models_by_table_name[ + qualified_table_name(constraint.elements[0].column.table) + ] + if isinstance(parent, ModelClass): + source.parent_class = parent + parent.children.append(source) + continue + + # Add uselist=False to One-to-One relationships + column_names = get_column_names(constraint) + if any( + isinstance(c, (PrimaryKeyConstraint, UniqueConstraint)) + and {col.name for col in c.columns} == set(column_names) + for c in constraint.table.constraints + ): + r_type = RelationshipType.ONE_TO_ONE + else: + r_type = RelationshipType.MANY_TO_ONE + + relationship = RelationshipAttribute(r_type, source, target, constraint) + source.relationships.append(relationship) + + # For self referential relationships, remote_side needs to be set + if source is target: + relationship.remote_side = [ + source.get_column_attribute(col.name) + for col in constraint.referred_table.primary_key + ] + + # If the two tables share more than one foreign key constraint, + # SQLAlchemy needs an explicit primaryjoin to figure out which column(s) + # it needs + common_fk_constraints = get_common_fk_constraints( + source.table, target.table + ) + if len(common_fk_constraints) > 1: + relationship.foreign_keys = [ + source.get_column_attribute(key) + for key in constraint.column_keys + ] + + # Generate the opposite end of the relationship in the target class + if "nobidi" not in self.options: + if r_type is RelationshipType.MANY_TO_ONE: + r_type = RelationshipType.ONE_TO_MANY + + reverse_relationship = RelationshipAttribute( + r_type, + target, + source, + constraint, + foreign_keys=relationship.foreign_keys, + backref=relationship, + ) + relationship.backref = reverse_relationship + target.relationships.append(reverse_relationship) + + # For self referential relationships, remote_side needs to be set + if source is target: + reverse_relationship.remote_side = [ + source.get_column_attribute(colname) + for colname in constraint.column_keys + ] + + # Add many-to-many relationships + for association_table in association_tables: + fk_constraints = sorted( + association_table.table.foreign_key_constraints, + key=get_constraint_sort_key, + ) + target = models_by_table_name[ + qualified_table_name(fk_constraints[1].elements[0].column.table) + ] + if isinstance(target, ModelClass): + relationship = RelationshipAttribute( + RelationshipType.MANY_TO_MANY, + source, + target, + fk_constraints[1], + association_table, + ) + source.relationships.append(relationship) + + # Generate the opposite end of the relationship in the target class + reverse_relationship = None + if "nobidi" not in self.options: + reverse_relationship = RelationshipAttribute( + RelationshipType.MANY_TO_MANY, + target, + source, + fk_constraints[0], + association_table, + relationship, + ) + relationship.backref = reverse_relationship + target.relationships.append(reverse_relationship) + + # Add a primary/secondary join for self-referential many-to-many + # relationships + if source is target: + both_relationships = [relationship] + reverse_flags = [False, True] + if reverse_relationship: + both_relationships.append(reverse_relationship) + + for relationship, reverse in zip(both_relationships, reverse_flags): + if ( + not relationship.association_table + or not relationship.constraint + ): + continue + + constraints = sorted( + relationship.constraint.table.foreign_key_constraints, + key=get_constraint_sort_key, + reverse=reverse, + ) + pri_pairs = zip( + get_column_names(constraints[0]), constraints[0].elements + ) + sec_pairs = zip( + get_column_names(constraints[1]), constraints[1].elements + ) + relationship.primaryjoin = [ + ( + relationship.source, + elem.column.name, + relationship.association_table, + col, + ) + for col, elem in pri_pairs + ] + relationship.secondaryjoin = [ + ( + relationship.target, + elem.column.name, + relationship.association_table, + col, + ) + for col, elem in sec_pairs + ] + + return relationships + + def generate_model_name(self, model: Model, global_names: set[str]) -> None: + if isinstance(model, ModelClass): + preferred_name = _re_invalid_identifier.sub("_", model.table.name) + if model.table.name in self.model_metadata: + preferred_name = self.get_class_name_override(model.table.name, preferred_name) + else: + preferred_name = "".join( + part[:1].upper() + part[1:] for part in preferred_name.split("_") + ) + if "use_inflect" in self.options: + singular_name = self.inflect_engine.singular_noun(preferred_name) + if singular_name: + preferred_name = singular_name + + model.name = self.find_free_name(preferred_name, global_names) + + # Fill in the names for column attributes + local_names: set[str] = set() + for column_attr in model.columns: + self.generate_column_attr_name(column_attr, global_names, local_names) + local_names.add(column_attr.name) + + # Fill in the names for relationship attributes + for relationship in model.relationships: + self.generate_relationship_name(relationship, global_names, local_names) + local_names.add(relationship.name) + else: + super().generate_model_name(model, global_names) + + def generate_column_attr_name( + self, + column_attr: ColumnAttribute, + global_names: set[str], + local_names: set[str], + ) -> None: + column_attr.name = self.find_free_name( + column_attr.column.name, global_names, local_names + ) + + def generate_relationship_name( + self, + relationship: RelationshipAttribute, + global_names: set[str], + local_names: set[str], + ) -> None: + # Self referential reverse relationships + preferred_name: str + if ( + relationship.type + in (RelationshipType.ONE_TO_MANY, RelationshipType.ONE_TO_ONE) + and relationship.source is relationship.target + and relationship.backref + and relationship.backref.name + ): + preferred_name = relationship.backref.name + "_reverse" + else: + preferred_name = relationship.target.table.name + + # If there's a constraint with a single column that ends with "_id", use the + # preceding part as the relationship name + if relationship.constraint: + is_source = relationship.source.table is relationship.constraint.table + if is_source or relationship.type not in ( + RelationshipType.ONE_TO_ONE, + RelationshipType.ONE_TO_MANY, + ): + column_names = [c.name for c in relationship.constraint.columns] + if len(column_names) == 1 and column_names[0].endswith("_id"): + preferred_name = column_names[0][:-3] + + if "use_inflect" in self.options: + if relationship.type in ( + RelationshipType.ONE_TO_MANY, + RelationshipType.MANY_TO_MANY, + ): + inflected_name = self.inflect_engine.plural_noun(preferred_name) + if inflected_name: + preferred_name = inflected_name + else: + inflected_name = self.inflect_engine.singular_noun(preferred_name) + if inflected_name: + preferred_name = inflected_name + + relationship.name = self.find_free_name( + preferred_name, global_names, local_names + ) + + def render_models(self, models: list[Model]) -> str: + rendered: list[str] = [] + for model in models: + if isinstance(model, ModelClass): + rendered.append(self.render_class(model)) + else: + rendered.append(f"{model.name} = {self.render_table(model.table)}") + + return "\n\n\n".join(rendered) + + def render_class(self, model: ModelClass) -> str: + sections: list[str] = [] + indexed_columns = set() + + # Render class variables / special declarations + class_vars: str = self.render_class_variables(model, indexed_columns=indexed_columns) + + # Render column attributes + # This populates "index" + rendered_column_attributes: list[str] = [] + for nullable in (False, True): + for column_attr in model.columns: + if column_attr.column.nullable is nullable: + rendered_column_attributes.append( + self.render_column_attribute(column_attr, model.table) + ) + + for column_attr in model.columns: + if column_attr.column.index: + indexed_columns.add(column_attr.column.name) + + # Render class variables / special declarations + if class_vars: + sections.append(class_vars) + + if rendered_column_attributes: + sections.append("\n".join(rendered_column_attributes)) + + # Render relationship attributes + rendered_relationship_attributes: list[str] = [ + self.render_relationship(relationship, model.table) + for relationship in model.relationships + ] + + rendered_relationship_attributes.extend(self.get_additional_relationships(model.table)) + rendered_relationship_attributes = [attr for attr in rendered_relationship_attributes if attr] + + if rendered_relationship_attributes: + sections.append("\n".join(rendered_relationship_attributes)) + + declaration = self.render_class_declaration(model) + rendered_sections = "\n\n".join( + indent(section, self.indentation) for section in sections + ) + + return f"{declaration}\n{rendered_sections}" + + def render_class_declaration(self, model: ModelClass) -> str: + parent_class_name = ( + model.parent_class.name if model.parent_class else self.base_class_name + ) + return f"class {model.name}({parent_class_name}):" + + def render_class_variables(self, model: ModelClass, indexed_columns: set) -> str: + variables = [f"__tablename__ = {model.table.name!r}"] + + # Render constraints and indexes as __table_args__ + table_args = self.render_table_args(model.table, indexed_columns) + table_args = self.get_arg_override(model.table, "table_args", table_args) + + if table_args: + variables.append(f"__table_args__ = {table_args}") + + return "\n".join(variables) + + def render_table_args(self, table: Table, indexed_columns: set) -> str: + args: list[str] = [] + kwargs: dict[str, str] = {} + + # Render constraints + foreign_keys = set() + for constraint in sorted(table.constraints, key=get_constraint_sort_key): + if uses_default_name(constraint): + if isinstance(constraint, PrimaryKeyConstraint): + continue + if ( + isinstance(constraint, (ForeignKeyConstraint, UniqueConstraint)) + and len(constraint.columns) == 1 + ): + continue + + if isinstance(constraint, ForeignKeyConstraint): + foreign_keys.add(repr(constraint.column_keys)) + args.append(self.render_constraint(constraint)) + + # Render indexes + simple_indecies = set() + for index in sorted(table.indexes, key=lambda i: i.name): + if len(index.columns) == 1: + simple_indecies.add(index.columns[0].name) + index.columns[0].index = True + continue + if repr([col.name for col in index.columns]) in foreign_keys: + continue + if len(index.columns) > 1 or not uses_default_name(index): + args.append(self.render_index(index, table)) + + if table.schema: + kwargs["schema"] = table.schema + + if table.comment: + kwargs["comment"] = table.comment + + table_charset = self.model_metadata.get(table.name, {}).get("charset") + if table_charset: + kwargs["mysql_charset"] = table_charset + + + if kwargs: + formatted_kwargs = pformat(kwargs) + if not args: + return formatted_kwargs + else: + args.append(formatted_kwargs) + + if args: + rendered_args = f",\n{self.indentation}".join(args) + if len(args) == 1: + rendered_args += "," + + return f"(\n{self.indentation}{rendered_args}\n)" + else: + return "" + + def render_column_attribute(self, column_attr: ColumnAttribute, table: Table) -> str: + column = column_attr.column + override = self.get_column_type_override(table, column.name) + if override == "drop": + return f"# {column_attr.name} is dropped." + if override and override[0] == ":": + return f"{column_attr.name}: {override[1:]}" + rendered_column = self.render_column(column, column_attr.name != column.name) + rendered_column = override if override else rendered_column + + try: + python_type = column.type.python_type + python_type_name = python_type.__name__ + if python_type.__module__ == "builtins": + column_python_type = python_type_name + else: + python_type_module = python_type.__module__ + column_python_type = f"{python_type_module}.{python_type_name}" + self.add_module_import(python_type_module) + except NotImplementedError: + self.add_literal_import("typing", "Any") + column_python_type = "Any" + + # if the RHS is enum, propagate to LHS as literal + if isinstance(column_attr.column.type, Enum) and column_python_type == "str": + column_python_type = "Literal%s" % repr(column_attr.column.type.enums) + + if column.nullable: + self.add_literal_import("typing", "Optional") + column_python_type = f"Optional[{column_python_type}]" + return f"{column_attr.name}: Mapped[{column_python_type}] = {rendered_column}" + + def render_relationship(self, relationship: RelationshipAttribute, table: Table) -> str: + def render_column_attrs(column_attrs: list[ColumnAttribute]) -> str: + rendered = [] + for attr in column_attrs: + if attr.model is relationship.source: + rendered.append(attr.name) + else: + rendered.append(repr(f"{attr.model.name}.{attr.name}")) + + return "[" + ", ".join(rendered) + "]" + + def render_foreign_keys(column_attrs: list[ColumnAttribute]) -> str: + rendered = [] + render_as_string = False + # Assume that column_attrs are all in relationship.source or none + for attr in column_attrs: + if attr.model is relationship.source: + rendered.append(attr.name) + else: + rendered.append(f"{attr.model.name}.{attr.name}") + render_as_string = True + + if render_as_string: + return "'[" + ", ".join(rendered) + "]'" + else: + return "[" + ", ".join(rendered) + "]" + + def render_join(terms: list[JoinType]) -> str: + rendered_joins = [] + for source, source_col, target, target_col in terms: + rendered = f"lambda: {source.name}.{source_col} == {target.name}." + if target.__class__ is Model: + rendered += "c." + + rendered += str(target_col) + rendered_joins.append(rendered) + + if len(rendered_joins) > 1: + rendered = ", ".join(rendered_joins) + return f"and_({rendered})" + else: + return rendered_joins[0] + + # Render keyword arguments + kwargs: dict[str, Any] = {} + if relationship.type is RelationshipType.ONE_TO_ONE and relationship.constraint: + if relationship.constraint.referred_table is relationship.source.table: + kwargs["uselist"] = False + + # Add the "secondary" keyword for many-to-many relationships + if relationship.association_table: + table_ref = relationship.association_table.table.name + if relationship.association_table.schema: + table_ref = f"{relationship.association_table.schema}.{table_ref}" + + kwargs["secondary"] = repr(table_ref) + + if relationship.remote_side: + kwargs["remote_side"] = render_column_attrs(relationship.remote_side) + + if relationship.foreign_keys: + kwargs["foreign_keys"] = render_foreign_keys(relationship.foreign_keys) + + if relationship.primaryjoin: + kwargs["primaryjoin"] = render_join(relationship.primaryjoin) + + if relationship.secondaryjoin: + kwargs["secondaryjoin"] = render_join(relationship.secondaryjoin) + + if relationship.backref: + kwargs["back_populates"] = repr(relationship.backref.name) + + rendered_relationship = render_callable( + "relationship", repr(relationship.target.name), kwargs=kwargs + ) + + relationship_type: str + if relationship.type == RelationshipType.ONE_TO_MANY: + self.add_literal_import("typing", "List") + relationship_type = f"List['{relationship.target.name}']" + elif relationship.type in ( + RelationshipType.ONE_TO_ONE, + RelationshipType.MANY_TO_ONE, + ): + relationship_type = f"'{relationship.target.name}'" + elif relationship.type == RelationshipType.MANY_TO_MANY: + self.add_literal_import("typing", "List") + relationship_type = f"List['{relationship.target.name}']" + else: + self.add_literal_import("typing", "Any") + relationship_type = "Any" + + relationship_override = self.get_relationship_overrides(table) + rendered_relationship = relationship_override.get(relationship.name, rendered_relationship) + if not rendered_relationship: + return "" + if isinstance(rendered_relationship, dict): + assert len(rendered_relationship) == 1 + name, value = list(rendered_relationship.items())[0] + if value: + # When the RHS start with :, it has the type included + if value[0] == ":": + return f"{name}: {value[1:]}" + else: + return f"{name}: Mapped[{relationship_type}] = {value}" + return "" + return ( + f"{relationship.name}: Mapped[{relationship_type}] " + f"= {rendered_relationship}" + ) + + +class DataclassGenerator(DeclarativeGenerator): + def __init__( + self, + metadata: MetaData, + bind: Connection | Engine, + options: Sequence[str], + *, + indentation: str = " ", + base_class_name: str = "Base", + quote_annotations: bool = False, + metadata_key: str = "sa", + model_metadata: dict = {}, + ): + super().__init__( + metadata, + bind, + options, + indentation=indentation, + base_class_name=base_class_name, + model_metadata=model_metadata + ) + self.metadata_key: str = metadata_key + self.quote_annotations: bool = quote_annotations + + def generate_base(self) -> None: + self.base = Base( + literal_imports=[ + LiteralImport("sqlalchemy.orm", "DeclarativeBase"), + LiteralImport("sqlalchemy.orm", "MappedAsDataclass"), + ], + declarations=[ + ( + f"class {self.base_class_name}(MappedAsDataclass, " + "DeclarativeBase):" + ), + f"{self.indentation}pass", + ], + metadata_ref=f"{self.base_class_name}.metadata", + ) + + +class SQLModelGenerator(DeclarativeGenerator): + def __init__( + self, + metadata: MetaData, + bind: Connection | Engine, + options: Sequence[str], + *, + indentation: str = " ", + base_class_name: str = "SQLModel", + model_metadata: dict = {}, + ): + super().__init__( + metadata, + bind, + options, + indentation=indentation, + base_class_name=base_class_name, + model_metadata=model_metadata + ) + + def generate_base(self) -> None: + self.base = Base( + literal_imports=[], + declarations=[], + metadata_ref="", + ) + + def collect_imports(self, models: Iterable[Model]) -> None: + super(DeclarativeGenerator, self).collect_imports(models) + if any(isinstance(model, ModelClass) for model in models): + self.remove_literal_import("sqlalchemy", "MetaData") + self.add_literal_import("sqlmodel", "SQLModel") + self.add_literal_import("sqlmodel", "Field") + + def collect_imports_for_model(self, model: Model) -> None: + super(DeclarativeGenerator, self).collect_imports_for_model(model) + if isinstance(model, ModelClass): + for column_attr in model.columns: + if column_attr.column.nullable: + self.add_literal_import("typing", "Optional") + break + + if model.relationships: + self.add_literal_import("sqlmodel", "Relationship") + + for relationship_attr in model.relationships: + if relationship_attr.type in ( + RelationshipType.ONE_TO_MANY, + RelationshipType.MANY_TO_MANY, + ): + self.add_literal_import("typing", "List") + + def collect_imports_for_column(self, column: Column[Any]) -> None: + super().collect_imports_for_column(column) + try: + python_type = column.type.python_type + except NotImplementedError: + self.add_literal_import("typing", "Any") + else: + self.add_import(python_type) + + def render_module_variables(self, models: list[Model]) -> str: + declarations: list[str] = [] + if any(not isinstance(model, ModelClass) for model in models): + if self.base.table_metadata_declaration is not None: + declarations.append(self.base.table_metadata_declaration) + + return "\n".join(declarations) + + def render_class_declaration(self, model: ModelClass) -> str: + if model.parent_class: + parent = model.parent_class.name + else: + parent = self.base_class_name + + superclass_part = f"({parent}, table=True)" + return f"class {model.name}{superclass_part}:" + + def render_class_variables(self, model: ModelClass) -> str: + variables = [] + + if model.table.name != model.name.lower(): + variables.append(f"__tablename__ = {model.table.name!r}") + + # Render constraints and indexes as __table_args__ + table_args = self.render_table_args(model.table) + if table_args: + variables.append(f"__table_args__ = {table_args}") + + return "\n".join(variables) + + def render_column_attribute(self, column_attr: ColumnAttribute, table: Table) -> str: + column = column_attr.column + try: + python_type = column.type.python_type + except NotImplementedError: + python_type_name = "Any" + else: + python_type_name = python_type.__name__ + + kwargs: dict[str, Any] = {} + if ( + column.autoincrement and column.name in column.table.primary_key + ) or column.nullable: + self.add_literal_import("typing", "Optional") + kwargs["default"] = None + python_type_name = f"Optional[{python_type_name}]" + + rendered_column = self.render_column(column, True) + kwargs["sa_column"] = f"{rendered_column}" + rendered_field = render_callable("Field", kwargs=kwargs) + return f"{column_attr.name}: {python_type_name} = {rendered_field}" + + def render_relationship(self, relationship: RelationshipAttribute, table: Table) -> str: + rendered = super().render_relationship(relationship, table).partition(" = ")[2] + args = self.render_relationship_args(rendered, ) + kwargs: dict[str, Any] = {} + annotation = repr(relationship.target.name) + + if relationship.type in ( + RelationshipType.ONE_TO_MANY, + RelationshipType.MANY_TO_MANY, + ): + self.add_literal_import("typing", "List") + annotation = f"List[{annotation}]" + else: + self.add_literal_import("typing", "Optional") + annotation = f"Optional[{annotation}]" + + rendered_field = render_callable("Relationship", *args, kwargs=kwargs) + relationship_override = self.get_relationship_overrides(table) + rendered_field = relationship_override.get(relationship.name, rendered_field) + if not rendered_field: + return "" + return f"{relationship.name}: {annotation} = {rendered_field}" + + def render_relationship_args(self, arguments: str) -> list[str]: + argument_list = arguments.split(",") + # delete ')' and ' ' from args + argument_list[-1] = argument_list[-1][:-1] + argument_list = [argument[1:] for argument in argument_list] + + rendered_args: list[str] = [] + for arg in argument_list: + if "back_populates" in arg: + rendered_args.append(arg) + if "uselist=False" in arg: + rendered_args.append("sa_relationship_kwargs={'uselist': False}") + + return rendered_args diff --git a/development/sqlacodegen/src/sqlacodegen/models.py b/development/sqlacodegen/src/sqlacodegen/models.py new file mode 100644 index 000000000..3f03e026d --- /dev/null +++ b/development/sqlacodegen/src/sqlacodegen/models.py @@ -0,0 +1,79 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +from enum import Enum, auto +from typing import Any, Tuple, Union + +from sqlalchemy.sql.schema import Column, ForeignKeyConstraint, Table + + +@dataclass +class Model: + table: Table + name: str = field(init=False, default="") + + @property + def schema(self) -> str | None: + return self.table.schema + + +@dataclass +class ModelClass(Model): + columns: list[ColumnAttribute] = field(default_factory=list) + relationships: list[RelationshipAttribute] = field(default_factory=list) + parent_class: ModelClass | None = None + children: list[ModelClass] = field(default_factory=list) + + def get_column_attribute(self, column_name: str) -> ColumnAttribute: + for column in self.columns: + if column.column.name == column_name: + return column + + raise LookupError(f"Cannot find column attribute for {column_name!r}") + + +class RelationshipType(Enum): + ONE_TO_ONE = auto() + ONE_TO_MANY = auto() + MANY_TO_ONE = auto() + MANY_TO_MANY = auto() + + +@dataclass +class ColumnAttribute: + model: ModelClass + column: Column[Any] + name: str = field(init=False, default="") + + def __repr__(self) -> str: + return f"{self.__class__.__name__}(name={self.name!r}, type={self.column.type})" + + def __str__(self) -> str: + return self.name + + +JoinType = Tuple[Model, Union[ColumnAttribute, str], Model, Union[ColumnAttribute, str]] + + +@dataclass +class RelationshipAttribute: + type: RelationshipType + source: ModelClass + target: ModelClass + constraint: ForeignKeyConstraint | None = None + association_table: Model | None = None + backref: RelationshipAttribute | None = None + remote_side: list[ColumnAttribute] = field(default_factory=list) + foreign_keys: list[ColumnAttribute] = field(default_factory=list) + primaryjoin: list[JoinType] = field(default_factory=list) + secondaryjoin: list[JoinType] = field(default_factory=list) + name: str = field(init=False, default="") + + def __repr__(self) -> str: + return ( + f"{self.__class__.__name__}(name={self.name!r}, type={self.type}, " + f"target={self.target.name})" + ) + + def __str__(self) -> str: + return self.name diff --git a/development/sqlacodegen/src/sqlacodegen/mysql_util.py b/development/sqlacodegen/src/sqlacodegen/mysql_util.py new file mode 100644 index 000000000..9ceed3913 --- /dev/null +++ b/development/sqlacodegen/src/sqlacodegen/mysql_util.py @@ -0,0 +1,21 @@ +from sqlalchemy.engine import Connection, Engine +from sqlalchemy import text + +def get_mysql_table_charsets(engine: Engine, schema_name: str) -> dict: + # Query to fetch table names and their character sets + query = f""" + SELECT + TABLE_NAME, + SUBSTRING_INDEX(TABLE_COLLATION, '_', 1) AS CHARACTER_SET + FROM + INFORMATION_SCHEMA.TABLES + WHERE + TABLE_SCHEMA = '{schema_name}'; + """ + + with engine.connect() as conn: + result = conn.execute(text(query)).fetchall() + charsets = {row[0]: row[1] for row in result} + + + return charsets diff --git a/development/sqlacodegen/src/sqlacodegen/py.typed b/development/sqlacodegen/src/sqlacodegen/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/development/sqlacodegen/src/sqlacodegen/utils.py b/development/sqlacodegen/src/sqlacodegen/utils.py new file mode 100644 index 000000000..397f89e08 --- /dev/null +++ b/development/sqlacodegen/src/sqlacodegen/utils.py @@ -0,0 +1,204 @@ +from __future__ import annotations + +import re +from collections.abc import Mapping +from typing import Any + +from sqlalchemy import PrimaryKeyConstraint, UniqueConstraint +from sqlalchemy.engine import Connection, Engine +from sqlalchemy.sql import ClauseElement +from sqlalchemy.sql.elements import TextClause +from sqlalchemy.sql.schema import ( + CheckConstraint, + ColumnCollectionConstraint, + Constraint, + ForeignKeyConstraint, + Index, + Table, +) + +_re_postgresql_nextval_sequence = re.compile(r"nextval\('(.+)'::regclass\)") +_re_postgresql_sequence_delimiter = re.compile(r'(.*?)([."]|$)') + + +def get_column_names(constraint: ColumnCollectionConstraint) -> list[str]: + return list(constraint.columns.keys()) + + +def get_constraint_sort_key(constraint: Constraint) -> str: + if isinstance(constraint, CheckConstraint): + return f"C{constraint.sqltext}" + elif isinstance(constraint, ColumnCollectionConstraint): + return constraint.__class__.__name__[0] + repr(get_column_names(constraint)) + else: + return str(constraint) + + +def get_compiled_expression(statement: ClauseElement, bind: Engine | Connection) -> str: + """Return the statement in a form where any placeholders have been filled in.""" + return str(statement.compile(bind, compile_kwargs={"literal_binds": True})) + + +def get_common_fk_constraints( + table1: Table, table2: Table +) -> set[ForeignKeyConstraint]: + """ + Return a set of foreign key constraints the two tables have against each other. + + """ + c1 = { + c + for c in table1.constraints + if isinstance(c, ForeignKeyConstraint) and c.elements[0].column.table == table2 + } + c2 = { + c + for c in table2.constraints + if isinstance(c, ForeignKeyConstraint) and c.elements[0].column.table == table1 + } + return c1.union(c2) + + +def uses_default_name(constraint: Constraint | Index) -> bool: + if not constraint.name or constraint.table is None: + return True + + table = constraint.table + values: dict[str, Any] = { + "table_name": table.name, + "constraint_name": constraint.name, + } + if isinstance(constraint, (Index, ColumnCollectionConstraint)): + values.update( + { + "column_0N_name": "".join(col.name for col in constraint.columns), + "column_0_N_name": "_".join(col.name for col in constraint.columns), + "column_0N_label": "".join( + col.label(col.name).name for col in constraint.columns + ), + "column_0_N_label": "_".join( + col.label(col.name).name for col in constraint.columns + ), + "column_0N_key": "".join( + col.key for col in constraint.columns if col.key + ), + "column_0_N_key": "_".join( + col.key for col in constraint.columns if col.key + ), + } + ) + if constraint.columns: + columns = constraint.columns.values() + values.update( + { + "column_0_name": columns[0].name, + "column_0_label": columns[0].label(columns[0].name).name, + "column_0_key": columns[0].key, + } + ) + + if isinstance(constraint, Index): + key = "ix" + elif isinstance(constraint, CheckConstraint): + key = "ck" + elif isinstance(constraint, UniqueConstraint): + key = "uq" + elif isinstance(constraint, PrimaryKeyConstraint): + key = "pk" + elif isinstance(constraint, ForeignKeyConstraint): + key = "fk" + values.update( + { + "referred_table_name": constraint.referred_table, + "referred_column_0_name": constraint.elements[0].column.name, + "referred_column_0N_name": "".join( + fk.column.name for fk in constraint.elements + ), + "referred_column_0_N_name": "_".join( + fk.column.name for fk in constraint.elements + ), + "referred_column_0_label": constraint.elements[0] + .column.label(constraint.elements[0].column.name) + .name, + "referred_fk.column_0N_label": "".join( + fk.column.label(fk.column.name).name for fk in constraint.elements + ), + "referred_fk.column_0_N_label": "_".join( + fk.column.label(fk.column.name).name for fk in constraint.elements + ), + "referred_fk.column_0_key": constraint.elements[0].column.key, + "referred_fk.column_0N_key": "".join( + fk.column.key for fk in constraint.elements if fk.column.key + ), + "referred_fk.column_0_N_key": "_".join( + fk.column.key for fk in constraint.elements if fk.column.key + ), + } + ) + else: + raise TypeError(f"Unknown constraint type: {constraint.__class__.__qualname__}") + + try: + convention: str = table.metadata.naming_convention[key] + return constraint.name == (convention % values) + except KeyError: + return False + + +def render_callable( + name: str, + *args: object, + kwargs: Mapping[str, object] | None = None, + indentation: str = "", +) -> str: + """ + Render a function call. + + :param name: name of the callable + :param args: positional arguments + :param kwargs: keyword arguments + :param indentation: if given, each argument will be rendered on its own line with + this value used as the indentation + + """ + if kwargs: + args += tuple(f"{key}={value}" for key, value in kwargs.items()) + + if indentation: + prefix = f"\n{indentation}" + suffix = "\n" + delimiter = f",\n{indentation}" + else: + prefix = suffix = "" + delimiter = ", " + + rendered_args = delimiter.join(str(arg) for arg in args) + return f"{name}({prefix}{rendered_args}{suffix})" + + +def qualified_table_name(table: Table) -> str: + if table.schema: + return f"{table.schema}.{table.name}" + else: + return str(table.name) + + +def decode_postgresql_sequence(clause: TextClause) -> tuple[str | None, str | None]: + match = _re_postgresql_nextval_sequence.match(clause.text) + if not match: + return None, None + + schema: str | None = None + sequence: str = "" + in_quotes = False + for match in _re_postgresql_sequence_delimiter.finditer(match.group(1)): + sequence += match.group(1) + if match.group(2) == '"': + in_quotes = not in_quotes + elif match.group(2) == ".": + if in_quotes: + sequence += "." + else: + schema, sequence = sequence, "" + + return schema, sequence diff --git a/development/sqlacodegen/tests/__init__.py b/development/sqlacodegen/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/development/sqlacodegen/tests/conftest.py b/development/sqlacodegen/tests/conftest.py new file mode 100644 index 000000000..022e786cd --- /dev/null +++ b/development/sqlacodegen/tests/conftest.py @@ -0,0 +1,33 @@ +from textwrap import dedent + +import pytest +from pytest import FixtureRequest +from sqlalchemy.engine import Engine, create_engine +from sqlalchemy.orm import clear_mappers, configure_mappers +from sqlalchemy.schema import MetaData + + +@pytest.fixture +def engine(request: FixtureRequest) -> Engine: + dialect = getattr(request, "param", None) + if dialect == "postgresql": + return create_engine("postgresql:///testdb") + elif dialect == "mysql": + return create_engine("mysql+mysqlconnector://testdb") + else: + return create_engine("sqlite:///:memory:") + + +@pytest.fixture +def metadata() -> MetaData: + return MetaData() + + +def validate_code(generated_code: str, expected_code: str) -> None: + expected_code = dedent(expected_code) + assert generated_code == expected_code + try: + exec(generated_code, {}) + configure_mappers() + finally: + clear_mappers() diff --git a/development/sqlacodegen/tests/test_cli.py b/development/sqlacodegen/tests/test_cli.py new file mode 100644 index 000000000..6a176d8ce --- /dev/null +++ b/development/sqlacodegen/tests/test_cli.py @@ -0,0 +1,160 @@ +from __future__ import annotations + +import sqlite3 +import subprocess +import sys +from importlib.metadata import version +from pathlib import Path + +import pytest + +future_imports = "from __future__ import annotations\n\n" + + +@pytest.fixture +def db_path(tmp_path: Path) -> Path: + path = tmp_path / "test.db" + with sqlite3.connect(str(path)) as conn: + cursor = conn.cursor() + cursor.execute( + "CREATE TABLE foo (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL)" + ) + + return path + + +def test_cli_tables(db_path: Path, tmp_path: Path) -> None: + output_path = tmp_path / "outfile" + subprocess.run( + [ + "sqlacodegen", + f"sqlite:///{db_path}", + "--generator", + "tables", + "--outfile", + str(output_path), + ], + check=True, + ) + + assert ( + output_path.read_text() + == """\ +from sqlalchemy import Column, Integer, MetaData, Table, Text + +metadata = MetaData() + + +t_foo = Table( + 'foo', metadata, + Column('id', Integer, primary_key=True), + Column('name', Text, nullable=False) +) +""" + ) + + +def test_cli_declarative(db_path: Path, tmp_path: Path) -> None: + output_path = tmp_path / "outfile" + subprocess.run( + [ + "sqlacodegen", + f"sqlite:///{db_path}", + "--generator", + "declarative", + "--outfile", + str(output_path), + ], + check=True, + ) + + assert ( + output_path.read_text() + == """\ +from sqlalchemy import Integer, Text +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column + +class Base(DeclarativeBase): + pass + + +class Foo(Base): + __tablename__ = 'foo' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + name: Mapped[str] = mapped_column(Text) +""" + ) + + +def test_cli_dataclass(db_path: Path, tmp_path: Path) -> None: + output_path = tmp_path / "outfile" + subprocess.run( + [ + "sqlacodegen", + f"sqlite:///{db_path}", + "--generator", + "dataclasses", + "--outfile", + str(output_path), + ], + check=True, + ) + + assert ( + output_path.read_text() + == """\ +from sqlalchemy import Integer, Text +from sqlalchemy.orm import DeclarativeBase, Mapped, MappedAsDataclass, mapped_column + +class Base(MappedAsDataclass, DeclarativeBase): + pass + + +class Foo(Base): + __tablename__ = 'foo' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + name: Mapped[str] = mapped_column(Text) +""" + ) + + +def test_cli_sqlmodels(db_path: Path, tmp_path: Path) -> None: + output_path = tmp_path / "outfile" + subprocess.run( + [ + "sqlacodegen", + f"sqlite:///{db_path}", + "--generator", + "sqlmodels", + "--outfile", + str(output_path), + ], + check=True, + ) + + assert ( + output_path.read_text() + == """\ +from typing import Optional + +from sqlalchemy import Column, Integer, Text +from sqlmodel import Field, SQLModel + +class Foo(SQLModel, table=True): + id: Optional[int] = Field(default=None, sa_column=Column('id', Integer, \ +primary_key=True)) + name: str = Field(sa_column=Column('name', Text, nullable=False)) +""" + ) + + +def test_main() -> None: + expected_version = version("sqlacodegen") + completed = subprocess.run( + [sys.executable, "-m", "sqlacodegen", "--version"], + stdout=subprocess.PIPE, + check=True, + ) + assert completed.stdout.decode().strip() == expected_version diff --git a/development/sqlacodegen/tests/test_generator_dataclass.py b/development/sqlacodegen/tests/test_generator_dataclass.py new file mode 100644 index 000000000..ae7eab250 --- /dev/null +++ b/development/sqlacodegen/tests/test_generator_dataclass.py @@ -0,0 +1,270 @@ +from __future__ import annotations + +import pytest +from _pytest.fixtures import FixtureRequest +from sqlalchemy.dialects.postgresql import UUID +from sqlalchemy.engine import Engine +from sqlalchemy.schema import Column, ForeignKeyConstraint, MetaData, Table +from sqlalchemy.sql.expression import text +from sqlalchemy.types import INTEGER, VARCHAR + +from sqlacodegen.generators import CodeGenerator, DataclassGenerator + +from .conftest import validate_code + + +@pytest.fixture +def generator( + request: FixtureRequest, metadata: MetaData, engine: Engine +) -> CodeGenerator: + options = getattr(request, "param", []) + return DataclassGenerator(metadata, engine, options) + + +def test_basic_class(generator: CodeGenerator) -> None: + Table( + "simple", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("name", VARCHAR(20)), + ) + + validate_code( + generator.generate(), + """\ + from typing import Optional + + from sqlalchemy import Integer, String + from sqlalchemy.orm import DeclarativeBase, Mapped, MappedAsDataclass, \ +mapped_column + + class Base(MappedAsDataclass, DeclarativeBase): + pass + + + class Simple(Base): + __tablename__ = 'simple' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + name: Mapped[Optional[str]] = mapped_column(String(20)) + """, + ) + + +def test_mandatory_field_last(generator: CodeGenerator) -> None: + Table( + "simple", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("name", VARCHAR(20), server_default=text("foo")), + Column("age", INTEGER, nullable=False), + ) + + validate_code( + generator.generate(), + """\ + from typing import Optional + + from sqlalchemy import Integer, String, text + from sqlalchemy.orm import DeclarativeBase, Mapped, MappedAsDataclass, \ +mapped_column + + class Base(MappedAsDataclass, DeclarativeBase): + pass + + + class Simple(Base): + __tablename__ = 'simple' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + age: Mapped[int] = mapped_column(Integer) + name: Mapped[Optional[str]] = mapped_column(String(20), \ +server_default=text('foo')) + """, + ) + + +def test_onetomany_optional(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("container_id", INTEGER), + ForeignKeyConstraint(["container_id"], ["simple_containers.id"]), + ) + Table( + "simple_containers", + generator.metadata, + Column("id", INTEGER, primary_key=True), + ) + + validate_code( + generator.generate(), + """\ + from typing import List, Optional + + from sqlalchemy import ForeignKey, Integer + from sqlalchemy.orm import DeclarativeBase, Mapped, MappedAsDataclass, \ +mapped_column, relationship + + class Base(MappedAsDataclass, DeclarativeBase): + pass + + + class SimpleContainers(Base): + __tablename__ = 'simple_containers' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + + simple_items: Mapped[List['SimpleItems']] = relationship('SimpleItems', \ +back_populates='container') + + + class SimpleItems(Base): + __tablename__ = 'simple_items' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + container_id: Mapped[Optional[int]] = \ +mapped_column(ForeignKey('simple_containers.id')) + + container: Mapped['SimpleContainers'] = relationship('SimpleContainers', \ +back_populates='simple_items') + """, + ) + + +def test_manytomany(generator: CodeGenerator) -> None: + Table("simple_items", generator.metadata, Column("id", INTEGER, primary_key=True)) + Table( + "simple_containers", + generator.metadata, + Column("id", INTEGER, primary_key=True), + ) + Table( + "container_items", + generator.metadata, + Column("item_id", INTEGER), + Column("container_id", INTEGER), + ForeignKeyConstraint(["item_id"], ["simple_items.id"]), + ForeignKeyConstraint(["container_id"], ["simple_containers.id"]), + ) + + validate_code( + generator.generate(), + """\ + from typing import List + + from sqlalchemy import Column, ForeignKey, Integer, Table + from sqlalchemy.orm import DeclarativeBase, Mapped, MappedAsDataclass, \ +mapped_column, relationship + + class Base(MappedAsDataclass, DeclarativeBase): + pass + + + class SimpleContainers(Base): + __tablename__ = 'simple_containers' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + + item: Mapped[List['SimpleItems']] = relationship('SimpleItems', \ +secondary='container_items', back_populates='container') + + + class SimpleItems(Base): + __tablename__ = 'simple_items' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + + container: Mapped[List['SimpleContainers']] = \ +relationship('SimpleContainers', secondary='container_items', back_populates='item') + + + t_container_items = Table( + 'container_items', Base.metadata, + Column('item_id', ForeignKey('simple_items.id')), + Column('container_id', ForeignKey('simple_containers.id')) + ) + """, + ) + + +def test_named_foreign_key_constraints(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("container_id", INTEGER), + ForeignKeyConstraint( + ["container_id"], ["simple_containers.id"], name="foreignkeytest" + ), + ) + Table( + "simple_containers", + generator.metadata, + Column("id", INTEGER, primary_key=True), + ) + + validate_code( + generator.generate(), + """\ + from typing import List, Optional + + from sqlalchemy import ForeignKeyConstraint, Integer + from sqlalchemy.orm import DeclarativeBase, Mapped, MappedAsDataclass, \ +mapped_column, relationship + + class Base(MappedAsDataclass, DeclarativeBase): + pass + + + class SimpleContainers(Base): + __tablename__ = 'simple_containers' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + + simple_items: Mapped[List['SimpleItems']] = relationship('SimpleItems', \ +back_populates='container') + + + class SimpleItems(Base): + __tablename__ = 'simple_items' + __table_args__ = ( + ForeignKeyConstraint(['container_id'], ['simple_containers.id'], \ +name='foreignkeytest'), + ) + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + container_id: Mapped[Optional[int]] = mapped_column(Integer) + + container: Mapped['SimpleContainers'] = relationship('SimpleContainers', \ +back_populates='simple_items') + """, + ) + + +def test_uuid_type_annotation(generator: CodeGenerator) -> None: + Table( + "simple", + generator.metadata, + Column("id", UUID, primary_key=True), + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import UUID + from sqlalchemy.orm import DeclarativeBase, Mapped, MappedAsDataclass, \ +mapped_column + import uuid + + class Base(MappedAsDataclass, DeclarativeBase): + pass + + + class Simple(Base): + __tablename__ = 'simple' + + id: Mapped[uuid.UUID] = mapped_column(UUID, primary_key=True) + """, + ) diff --git a/development/sqlacodegen/tests/test_generator_declarative.py b/development/sqlacodegen/tests/test_generator_declarative.py new file mode 100644 index 000000000..d9bf7b539 --- /dev/null +++ b/development/sqlacodegen/tests/test_generator_declarative.py @@ -0,0 +1,1511 @@ +from __future__ import annotations + +import pytest +from _pytest.fixtures import FixtureRequest +from sqlalchemy import PrimaryKeyConstraint +from sqlalchemy.engine import Engine +from sqlalchemy.schema import ( + CheckConstraint, + Column, + ForeignKey, + ForeignKeyConstraint, + Index, + MetaData, + Table, + UniqueConstraint, +) +from sqlalchemy.sql.expression import text +from sqlalchemy.types import INTEGER, VARCHAR, Text + +from sqlacodegen.generators import CodeGenerator, DeclarativeGenerator + +from .conftest import validate_code + + +@pytest.fixture +def generator( + request: FixtureRequest, metadata: MetaData, engine: Engine +) -> CodeGenerator: + options = getattr(request, "param", []) + return DeclarativeGenerator(metadata, engine, options) + + +def test_indexes(generator: CodeGenerator) -> None: + simple_items = Table( + "simple_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("number", INTEGER), + Column("text", VARCHAR), + ) + simple_items.indexes.add(Index("idx_number", simple_items.c.number)) + simple_items.indexes.add( + Index("idx_text_number", simple_items.c.text, simple_items.c.number) + ) + simple_items.indexes.add(Index("idx_text", simple_items.c.text, unique=True)) + + validate_code( + generator.generate(), + """\ +from typing import Optional + +from sqlalchemy import Index, Integer, String +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column + +class Base(DeclarativeBase): + pass + + +class SimpleItems(Base): + __tablename__ = 'simple_items' + __table_args__ = ( + Index('idx_number', 'number'), + Index('idx_text', 'text', unique=True), + Index('idx_text_number', 'text', 'number') + ) + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + number: Mapped[Optional[int]] = mapped_column(Integer) + text: Mapped[Optional[str]] = mapped_column(String) + """, + ) + + +def test_constraints(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("number", INTEGER), + CheckConstraint("number > 0"), + UniqueConstraint("id", "number"), + ) + + validate_code( + generator.generate(), + """\ +from typing import Optional + +from sqlalchemy import CheckConstraint, Integer, UniqueConstraint +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column + +class Base(DeclarativeBase): + pass + + +class SimpleItems(Base): + __tablename__ = 'simple_items' + __table_args__ = ( + CheckConstraint('number > 0'), + UniqueConstraint('id', 'number') + ) + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + number: Mapped[Optional[int]] = mapped_column(Integer) + """, + ) + + +def test_onetomany(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("container_id", INTEGER), + ForeignKeyConstraint(["container_id"], ["simple_containers.id"]), + ) + Table( + "simple_containers", + generator.metadata, + Column("id", INTEGER, primary_key=True), + ) + + validate_code( + generator.generate(), + """\ +from typing import List, Optional + +from sqlalchemy import ForeignKey, Integer +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship + +class Base(DeclarativeBase): + pass + + +class SimpleContainers(Base): + __tablename__ = 'simple_containers' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + + simple_items: Mapped[List['SimpleItems']] = relationship('SimpleItems', \ +back_populates='container') + + +class SimpleItems(Base): + __tablename__ = 'simple_items' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + container_id: Mapped[Optional[int]] = \ +mapped_column(ForeignKey('simple_containers.id')) + + container: Mapped['SimpleContainers'] = relationship('SimpleContainers', \ +back_populates='simple_items') + """, + ) + + +def test_onetomany_selfref(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("parent_item_id", INTEGER), + ForeignKeyConstraint(["parent_item_id"], ["simple_items.id"]), + ) + + validate_code( + generator.generate(), + """\ +from typing import List, Optional + +from sqlalchemy import ForeignKey, Integer +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship + +class Base(DeclarativeBase): + pass + + +class SimpleItems(Base): + __tablename__ = 'simple_items' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + parent_item_id: Mapped[Optional[int]] = \ +mapped_column(ForeignKey('simple_items.id')) + + parent_item: Mapped['SimpleItems'] = relationship('SimpleItems', \ +remote_side=[id], back_populates='parent_item_reverse') + parent_item_reverse: Mapped[List['SimpleItems']] = relationship('SimpleItems', \ +remote_side=[parent_item_id], back_populates='parent_item') +""", + ) + + +def test_onetomany_selfref_multi(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("parent_item_id", INTEGER), + Column("top_item_id", INTEGER), + ForeignKeyConstraint(["parent_item_id"], ["simple_items.id"]), + ForeignKeyConstraint(["top_item_id"], ["simple_items.id"]), + ) + + validate_code( + generator.generate(), + """\ +from typing import List, Optional + +from sqlalchemy import ForeignKey, Integer +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship + +class Base(DeclarativeBase): + pass + + +class SimpleItems(Base): + __tablename__ = 'simple_items' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + parent_item_id: Mapped[Optional[int]] = \ +mapped_column(ForeignKey('simple_items.id')) + top_item_id: Mapped[Optional[int]] = mapped_column(ForeignKey('simple_items.id')) + + parent_item: Mapped['SimpleItems'] = relationship('SimpleItems', \ +remote_side=[id], foreign_keys=[parent_item_id], back_populates='parent_item_reverse') + parent_item_reverse: Mapped[List['SimpleItems']] = relationship('SimpleItems', \ +remote_side=[parent_item_id], foreign_keys=[parent_item_id], \ +back_populates='parent_item') + top_item: Mapped['SimpleItems'] = relationship('SimpleItems', remote_side=[id], \ +foreign_keys=[top_item_id], back_populates='top_item_reverse') + top_item_reverse: Mapped[List['SimpleItems']] = relationship('SimpleItems', \ +remote_side=[top_item_id], foreign_keys=[top_item_id], back_populates='top_item') + """, + ) + + +def test_onetomany_composite(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("container_id1", INTEGER), + Column("container_id2", INTEGER), + ForeignKeyConstraint( + ["container_id1", "container_id2"], + ["simple_containers.id1", "simple_containers.id2"], + ondelete="CASCADE", + onupdate="CASCADE", + ), + ) + Table( + "simple_containers", + generator.metadata, + Column("id1", INTEGER, primary_key=True), + Column("id2", INTEGER, primary_key=True), + ) + + validate_code( + generator.generate(), + """\ +from typing import List, Optional + +from sqlalchemy import ForeignKeyConstraint, Integer +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship + +class Base(DeclarativeBase): + pass + + +class SimpleContainers(Base): + __tablename__ = 'simple_containers' + + id1: Mapped[int] = mapped_column(Integer, primary_key=True) + id2: Mapped[int] = mapped_column(Integer, primary_key=True) + + simple_items: Mapped[List['SimpleItems']] = relationship('SimpleItems', \ +back_populates='simple_containers') + + +class SimpleItems(Base): + __tablename__ = 'simple_items' + __table_args__ = ( + ForeignKeyConstraint(['container_id1', 'container_id2'], \ +['simple_containers.id1', 'simple_containers.id2'], ondelete='CASCADE', \ +onupdate='CASCADE'), + ) + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + container_id1: Mapped[Optional[int]] = mapped_column(Integer) + container_id2: Mapped[Optional[int]] = mapped_column(Integer) + + simple_containers: Mapped['SimpleContainers'] = relationship('SimpleContainers', \ +back_populates='simple_items') + """, + ) + + +def test_onetomany_multiref(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("parent_container_id", INTEGER), + Column("top_container_id", INTEGER), + ForeignKeyConstraint(["parent_container_id"], ["simple_containers.id"]), + ForeignKeyConstraint(["top_container_id"], ["simple_containers.id"]), + ) + Table( + "simple_containers", + generator.metadata, + Column("id", INTEGER, primary_key=True), + ) + + validate_code( + generator.generate(), + """\ +from typing import List, Optional + +from sqlalchemy import ForeignKey, Integer +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship + +class Base(DeclarativeBase): + pass + + +class SimpleContainers(Base): + __tablename__ = 'simple_containers' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + + simple_items: Mapped[List['SimpleItems']] = relationship('SimpleItems', \ +foreign_keys='[SimpleItems.parent_container_id]', back_populates='parent_container') + simple_items_: Mapped[List['SimpleItems']] = relationship('SimpleItems', \ +foreign_keys='[SimpleItems.top_container_id]', back_populates='top_container') + + +class SimpleItems(Base): + __tablename__ = 'simple_items' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + parent_container_id: Mapped[Optional[int]] = \ +mapped_column(ForeignKey('simple_containers.id')) + top_container_id: Mapped[Optional[int]] = \ +mapped_column(ForeignKey('simple_containers.id')) + + parent_container: Mapped['SimpleContainers'] = relationship('SimpleContainers', \ +foreign_keys=[parent_container_id], back_populates='simple_items') + top_container: Mapped['SimpleContainers'] = relationship('SimpleContainers', \ +foreign_keys=[top_container_id], back_populates='simple_items_') + """, + ) + + +def test_onetoone(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("other_item_id", INTEGER), + ForeignKeyConstraint(["other_item_id"], ["other_items.id"]), + UniqueConstraint("other_item_id"), + ) + Table( + "other_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + ) + + validate_code( + generator.generate(), + """\ +from typing import Optional + +from sqlalchemy import ForeignKey, Integer +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship + +class Base(DeclarativeBase): + pass + + +class OtherItems(Base): + __tablename__ = 'other_items' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + + simple_items: Mapped['SimpleItems'] = relationship('SimpleItems', uselist=False, \ +back_populates='other_item') + + +class SimpleItems(Base): + __tablename__ = 'simple_items' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + other_item_id: Mapped[Optional[int]] = \ +mapped_column(ForeignKey('other_items.id'), unique=True) + + other_item: Mapped['OtherItems'] = relationship('OtherItems', \ +back_populates='simple_items') + """, + ) + + +def test_onetomany_noinflect(generator: CodeGenerator) -> None: + Table( + "oglkrogk", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("fehwiuhfiwID", INTEGER), + ForeignKeyConstraint(["fehwiuhfiwID"], ["fehwiuhfiw.id"]), + ) + Table("fehwiuhfiw", generator.metadata, Column("id", INTEGER, primary_key=True)) + + validate_code( + generator.generate(), + """\ +from typing import List, Optional + +from sqlalchemy import ForeignKey, Integer +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship + +class Base(DeclarativeBase): + pass + + +class Fehwiuhfiw(Base): + __tablename__ = 'fehwiuhfiw' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + + oglkrogk: Mapped[List['Oglkrogk']] = relationship('Oglkrogk', \ +back_populates='fehwiuhfiw') + + +class Oglkrogk(Base): + __tablename__ = 'oglkrogk' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + fehwiuhfiwID: Mapped[Optional[int]] = mapped_column(ForeignKey('fehwiuhfiw.id')) + + fehwiuhfiw: Mapped['Fehwiuhfiw'] = \ +relationship('Fehwiuhfiw', back_populates='oglkrogk') + """, + ) + + +def test_onetomany_conflicting_column(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("container_id", INTEGER), + ForeignKeyConstraint(["container_id"], ["simple_containers.id"]), + ) + Table( + "simple_containers", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("relationship", Text), + ) + + validate_code( + generator.generate(), + """\ +from typing import List, Optional + +from sqlalchemy import ForeignKey, Integer, Text +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship + +class Base(DeclarativeBase): + pass + + +class SimpleContainers(Base): + __tablename__ = 'simple_containers' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + relationship_: Mapped[Optional[str]] = mapped_column('relationship', Text) + + simple_items: Mapped[List['SimpleItems']] = relationship('SimpleItems', \ +back_populates='container') + + +class SimpleItems(Base): + __tablename__ = 'simple_items' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + container_id: Mapped[Optional[int]] = \ +mapped_column(ForeignKey('simple_containers.id')) + + container: Mapped['SimpleContainers'] = relationship('SimpleContainers', \ +back_populates='simple_items') + """, + ) + + +def test_onetomany_conflicting_relationship(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("relationship_id", INTEGER), + ForeignKeyConstraint(["relationship_id"], ["relationship.id"]), + ) + Table("relationship", generator.metadata, Column("id", INTEGER, primary_key=True)) + + validate_code( + generator.generate(), + """\ +from typing import List, Optional + +from sqlalchemy import ForeignKey, Integer +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship + +class Base(DeclarativeBase): + pass + + +class Relationship(Base): + __tablename__ = 'relationship' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + + simple_items: Mapped[List['SimpleItems']] = relationship('SimpleItems', \ +back_populates='relationship_') + + +class SimpleItems(Base): + __tablename__ = 'simple_items' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + relationship_id: Mapped[Optional[int]] = \ +mapped_column(ForeignKey('relationship.id')) + + relationship_: Mapped['Relationship'] = relationship('Relationship', \ +back_populates='simple_items') + """, + ) + + +@pytest.mark.parametrize("generator", [["nobidi"]], indirect=True) +def test_manytoone_nobidi(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("container_id", INTEGER), + ForeignKeyConstraint(["container_id"], ["simple_containers.id"]), + ) + Table( + "simple_containers", + generator.metadata, + Column("id", INTEGER, primary_key=True), + ) + + validate_code( + generator.generate(), + """\ +from typing import Optional + +from sqlalchemy import ForeignKey, Integer +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship + +class Base(DeclarativeBase): + pass + + +class SimpleContainers(Base): + __tablename__ = 'simple_containers' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + + +class SimpleItems(Base): + __tablename__ = 'simple_items' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + container_id: Mapped[Optional[int]] = \ +mapped_column(ForeignKey('simple_containers.id')) + + container: Mapped['SimpleContainers'] = relationship('SimpleContainers') +""", + ) + + +def test_manytomany(generator: CodeGenerator) -> None: + Table("left_table", generator.metadata, Column("id", INTEGER, primary_key=True)) + Table( + "right_table", + generator.metadata, + Column("id", INTEGER, primary_key=True), + ) + Table( + "association_table", + generator.metadata, + Column("left_id", INTEGER), + Column("right_id", INTEGER), + ForeignKeyConstraint(["left_id"], ["left_table.id"]), + ForeignKeyConstraint(["right_id"], ["right_table.id"]), + ) + + validate_code( + generator.generate(), + """\ +from typing import List + +from sqlalchemy import Column, ForeignKey, Integer, Table +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship + +class Base(DeclarativeBase): + pass + + +class LeftTable(Base): + __tablename__ = 'left_table' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + + right: Mapped[List['RightTable']] = relationship('RightTable', \ +secondary='association_table', back_populates='left') + + +class RightTable(Base): + __tablename__ = 'right_table' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + + left: Mapped[List['LeftTable']] = relationship('LeftTable', \ +secondary='association_table', back_populates='right') + + +t_association_table = Table( + 'association_table', Base.metadata, + Column('left_id', ForeignKey('left_table.id')), + Column('right_id', ForeignKey('right_table.id')) +) + """, + ) + + +@pytest.mark.parametrize("generator", [["nobidi"]], indirect=True) +def test_manytomany_nobidi(generator: CodeGenerator) -> None: + Table("simple_items", generator.metadata, Column("id", INTEGER, primary_key=True)) + Table( + "simple_containers", + generator.metadata, + Column("id", INTEGER, primary_key=True), + ) + Table( + "container_items", + generator.metadata, + Column("item_id", INTEGER), + Column("container_id", INTEGER), + ForeignKeyConstraint(["item_id"], ["simple_items.id"]), + ForeignKeyConstraint(["container_id"], ["simple_containers.id"]), + ) + + validate_code( + generator.generate(), + """\ +from typing import List + +from sqlalchemy import Column, ForeignKey, Integer, Table +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship + +class Base(DeclarativeBase): + pass + + +class SimpleContainers(Base): + __tablename__ = 'simple_containers' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + + item: Mapped[List['SimpleItems']] = relationship('SimpleItems', \ +secondary='container_items') + + +class SimpleItems(Base): + __tablename__ = 'simple_items' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + + +t_container_items = Table( + 'container_items', Base.metadata, + Column('item_id', ForeignKey('simple_items.id')), + Column('container_id', ForeignKey('simple_containers.id')) +) + """, + ) + + +def test_manytomany_selfref(generator: CodeGenerator) -> None: + Table("simple_items", generator.metadata, Column("id", INTEGER, primary_key=True)) + Table( + "child_items", + generator.metadata, + Column("parent_id", INTEGER), + Column("child_id", INTEGER), + ForeignKeyConstraint(["parent_id"], ["simple_items.id"]), + ForeignKeyConstraint(["child_id"], ["simple_items.id"]), + schema="otherschema", + ) + + validate_code( + generator.generate(), + """\ +from typing import List + +from sqlalchemy import Column, ForeignKey, Integer, Table +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship + +class Base(DeclarativeBase): + pass + + +class SimpleItems(Base): + __tablename__ = 'simple_items' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + + parent: Mapped[List['SimpleItems']] = relationship('SimpleItems', \ +secondary='otherschema.child_items', primaryjoin=lambda: SimpleItems.id \ +== t_child_items.c.child_id, \ +secondaryjoin=lambda: SimpleItems.id == \ +t_child_items.c.parent_id, back_populates='child') + child: Mapped[List['SimpleItems']] = \ +relationship('SimpleItems', secondary='otherschema.child_items', \ +primaryjoin=lambda: SimpleItems.id == t_child_items.c.parent_id, \ +secondaryjoin=lambda: SimpleItems.id == t_child_items.c.child_id, \ +back_populates='parent') + + +t_child_items = Table( + 'child_items', Base.metadata, + Column('parent_id', ForeignKey('simple_items.id')), + Column('child_id', ForeignKey('simple_items.id')), + schema='otherschema' +) + """, + ) + + +def test_manytomany_composite(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id1", INTEGER, primary_key=True), + Column("id2", INTEGER, primary_key=True), + ) + Table( + "simple_containers", + generator.metadata, + Column("id1", INTEGER, primary_key=True), + Column("id2", INTEGER, primary_key=True), + ) + Table( + "container_items", + generator.metadata, + Column("item_id1", INTEGER), + Column("item_id2", INTEGER), + Column("container_id1", INTEGER), + Column("container_id2", INTEGER), + ForeignKeyConstraint( + ["item_id1", "item_id2"], ["simple_items.id1", "simple_items.id2"] + ), + ForeignKeyConstraint( + ["container_id1", "container_id2"], + ["simple_containers.id1", "simple_containers.id2"], + ), + ) + + validate_code( + generator.generate(), + """\ +from typing import List + +from sqlalchemy import Column, ForeignKeyConstraint, Integer, Table +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship + +class Base(DeclarativeBase): + pass + + +class SimpleContainers(Base): + __tablename__ = 'simple_containers' + + id1: Mapped[int] = mapped_column(Integer, primary_key=True) + id2: Mapped[int] = mapped_column(Integer, primary_key=True) + + simple_items: Mapped[List['SimpleItems']] = relationship('SimpleItems', \ +secondary='container_items', back_populates='simple_containers') + + +class SimpleItems(Base): + __tablename__ = 'simple_items' + + id1: Mapped[int] = mapped_column(Integer, primary_key=True) + id2: Mapped[int] = mapped_column(Integer, primary_key=True) + + simple_containers: Mapped[List['SimpleContainers']] = \ +relationship('SimpleContainers', secondary='container_items', \ +back_populates='simple_items') + + +t_container_items = Table( + 'container_items', Base.metadata, + Column('item_id1', Integer), + Column('item_id2', Integer), + Column('container_id1', Integer), + Column('container_id2', Integer), + ForeignKeyConstraint(['container_id1', 'container_id2'], \ +['simple_containers.id1', 'simple_containers.id2']), + ForeignKeyConstraint(['item_id1', 'item_id2'], \ +['simple_items.id1', 'simple_items.id2']) +) + """, + ) + + +def test_joined_inheritance(generator: CodeGenerator) -> None: + Table( + "simple_sub_items", + generator.metadata, + Column("simple_items_id", INTEGER, primary_key=True), + Column("data3", INTEGER), + ForeignKeyConstraint(["simple_items_id"], ["simple_items.super_item_id"]), + ) + Table( + "simple_super_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("data1", INTEGER), + ) + Table( + "simple_items", + generator.metadata, + Column("super_item_id", INTEGER, primary_key=True), + Column("data2", INTEGER), + ForeignKeyConstraint(["super_item_id"], ["simple_super_items.id"]), + ) + + validate_code( + generator.generate(), + """\ +from typing import Optional + +from sqlalchemy import ForeignKey, Integer +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column + +class Base(DeclarativeBase): + pass + + +class SimpleSuperItems(Base): + __tablename__ = 'simple_super_items' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + data1: Mapped[Optional[int]] = mapped_column(Integer) + + +class SimpleItems(SimpleSuperItems): + __tablename__ = 'simple_items' + + super_item_id: Mapped[int] = mapped_column(ForeignKey('simple_super_items.id'), \ +primary_key=True) + data2: Mapped[Optional[int]] = mapped_column(Integer) + + +class SimpleSubItems(SimpleItems): + __tablename__ = 'simple_sub_items' + + simple_items_id: Mapped[int] = \ +mapped_column(ForeignKey('simple_items.super_item_id'), primary_key=True) + data3: Mapped[Optional[int]] = mapped_column(Integer) + """, + ) + + +def test_joined_inheritance_same_table_name(generator: CodeGenerator) -> None: + Table( + "simple", + generator.metadata, + Column("id", INTEGER, primary_key=True), + ) + Table( + "simple", + generator.metadata, + Column("id", INTEGER, ForeignKey("simple.id"), primary_key=True), + schema="altschema", + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import ForeignKey, Integer + from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column + + class Base(DeclarativeBase): + pass + + + class Simple(Base): + __tablename__ = 'simple' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + + + class Simple_(Simple): + __tablename__ = 'simple' + __table_args__ = {'schema': 'altschema'} + + id: Mapped[int] = mapped_column(ForeignKey('simple.id'), primary_key=True) + """, + ) + + +@pytest.mark.parametrize("generator", [["use_inflect"]], indirect=True) +def test_use_inflect(generator: CodeGenerator) -> None: + Table("simple_items", generator.metadata, Column("id", INTEGER, primary_key=True)) + + Table("singular", generator.metadata, Column("id", INTEGER, primary_key=True)) + + validate_code( + generator.generate(), + """\ +from sqlalchemy import Integer +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column + +class Base(DeclarativeBase): + pass + + +class SimpleItem(Base): + __tablename__ = 'simple_items' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + + +class Singular(Base): + __tablename__ = 'singular' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + """, + ) + + +@pytest.mark.parametrize("generator", [["use_inflect"]], indirect=True) +@pytest.mark.parametrize( + argnames=("table_name", "class_name", "relationship_name"), + argvalues=[ + ("manufacturers", "manufacturer", "manufacturer"), + ("statuses", "status", "status"), + ("studies", "study", "study"), + ("moose", "moose", "moose"), + ], + ids=[ + "test_inflect_manufacturer", + "test_inflect_status", + "test_inflect_study", + "test_inflect_moose", + ], +) +def test_use_inflect_plural( + generator: CodeGenerator, + table_name: str, + class_name: str, + relationship_name: str, +) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column(f"{relationship_name}_id", INTEGER), + ForeignKeyConstraint([f"{relationship_name}_id"], [f"{table_name}.id"]), + UniqueConstraint(f"{relationship_name}_id"), + ) + Table(table_name, generator.metadata, Column("id", INTEGER, primary_key=True)) + + validate_code( + generator.generate(), + f"""\ +from typing import Optional + +from sqlalchemy import ForeignKey, Integer +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship + +class Base(DeclarativeBase): + pass + + +class {class_name.capitalize()}(Base): + __tablename__ = '{table_name}' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + + simple_item: Mapped['SimpleItem'] = relationship('SimpleItem', uselist=False, \ +back_populates='{relationship_name}') + + +class SimpleItem(Base): + __tablename__ = 'simple_items' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + {relationship_name}_id: Mapped[Optional[int]] = \ +mapped_column(ForeignKey('{table_name}.id'), unique=True) + + {relationship_name}: Mapped['{class_name.capitalize()}'] = \ +relationship('{class_name.capitalize()}', back_populates='simple_item') + """, + ) + + +def test_table_kwargs(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + schema="testschema", + ) + + validate_code( + generator.generate(), + """\ +from sqlalchemy import Integer +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column + +class Base(DeclarativeBase): + pass + + +class SimpleItems(Base): + __tablename__ = 'simple_items' + __table_args__ = {'schema': 'testschema'} + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + """, + ) + + +def test_table_args_kwargs(generator: CodeGenerator) -> None: + simple_items = Table( + "simple_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("name", VARCHAR), + schema="testschema", + ) + simple_items.indexes.add(Index("testidx", simple_items.c.id, simple_items.c.name)) + + validate_code( + generator.generate(), + """\ +from typing import Optional + +from sqlalchemy import Index, Integer, String +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column + +class Base(DeclarativeBase): + pass + + +class SimpleItems(Base): + __tablename__ = 'simple_items' + __table_args__ = ( + Index('testidx', 'id', 'name'), + {'schema': 'testschema'} + ) + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + name: Mapped[Optional[str]] = mapped_column(String) + """, + ) + + +def test_foreign_key_schema(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("other_item_id", INTEGER), + ForeignKeyConstraint(["other_item_id"], ["otherschema.other_items.id"]), + ) + Table( + "other_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + schema="otherschema", + ) + + validate_code( + generator.generate(), + """\ +from typing import List, Optional + +from sqlalchemy import ForeignKey, Integer +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship + +class Base(DeclarativeBase): + pass + + +class OtherItems(Base): + __tablename__ = 'other_items' + __table_args__ = {'schema': 'otherschema'} + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + + simple_items: Mapped[List['SimpleItems']] = relationship('SimpleItems', \ +back_populates='other_item') + + +class SimpleItems(Base): + __tablename__ = 'simple_items' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + other_item_id: Mapped[Optional[int]] = \ +mapped_column(ForeignKey('otherschema.other_items.id')) + + other_item: Mapped['OtherItems'] = relationship('OtherItems', \ +back_populates='simple_items') + """, + ) + + +def test_invalid_attribute_names(generator: CodeGenerator) -> None: + Table( + "simple-items", + generator.metadata, + Column("id-test", INTEGER, primary_key=True), + Column("4test", INTEGER), + Column("_4test", INTEGER), + Column("def", INTEGER), + ) + + validate_code( + generator.generate(), + """\ +from typing import Optional + +from sqlalchemy import Integer +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column + +class Base(DeclarativeBase): + pass + + +class SimpleItems(Base): + __tablename__ = 'simple-items' + + id_test: Mapped[int] = mapped_column('id-test', Integer, primary_key=True) + _4test: Mapped[Optional[int]] = mapped_column('4test', Integer) + _4test_: Mapped[Optional[int]] = mapped_column('_4test', Integer) + def_: Mapped[Optional[int]] = mapped_column('def', Integer) + """, + ) + + +def test_pascal(generator: CodeGenerator) -> None: + Table( + "CustomerAPIPreference", + generator.metadata, + Column("id", INTEGER, primary_key=True), + ) + + validate_code( + generator.generate(), + """\ +from sqlalchemy import Integer +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column + +class Base(DeclarativeBase): + pass + + +class CustomerAPIPreference(Base): + __tablename__ = 'CustomerAPIPreference' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + """, + ) + + +def test_underscore(generator: CodeGenerator) -> None: + Table( + "customer_api_preference", + generator.metadata, + Column("id", INTEGER, primary_key=True), + ) + + validate_code( + generator.generate(), + """\ +from sqlalchemy import Integer +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column + +class Base(DeclarativeBase): + pass + + +class CustomerApiPreference(Base): + __tablename__ = 'customer_api_preference' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + """, + ) + + +def test_pascal_underscore(generator: CodeGenerator) -> None: + Table( + "customer_API_Preference", + generator.metadata, + Column("id", INTEGER, primary_key=True), + ) + + validate_code( + generator.generate(), + """\ +from sqlalchemy import Integer +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column + +class Base(DeclarativeBase): + pass + + +class CustomerAPIPreference(Base): + __tablename__ = 'customer_API_Preference' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + """, + ) + + +def test_pascal_multiple_underscore(generator: CodeGenerator) -> None: + Table( + "customer_API__Preference", + generator.metadata, + Column("id", INTEGER, primary_key=True), + ) + + validate_code( + generator.generate(), + """\ +from sqlalchemy import Integer +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column + +class Base(DeclarativeBase): + pass + + +class CustomerAPIPreference(Base): + __tablename__ = 'customer_API__Preference' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + """, + ) + + +@pytest.mark.parametrize( + "generator, nocomments", + [([], False), (["nocomments"], True)], + indirect=["generator"], +) +def test_column_comment(generator: CodeGenerator, nocomments: bool) -> None: + Table( + "simple", + generator.metadata, + Column("id", INTEGER, primary_key=True, comment="this is a 'comment'"), + ) + + comment_part = "" if nocomments else ", comment=\"this is a 'comment'\"" + validate_code( + generator.generate(), + f"""\ +from sqlalchemy import Integer +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column + +class Base(DeclarativeBase): + pass + + +class Simple(Base): + __tablename__ = 'simple' + + id: Mapped[int] = mapped_column(Integer, primary_key=True{comment_part}) +""", + ) + + +def test_table_comment(generator: CodeGenerator) -> None: + Table( + "simple", + generator.metadata, + Column("id", INTEGER, primary_key=True), + comment="this is a 'comment'", + ) + + validate_code( + generator.generate(), + """\ +from sqlalchemy import Integer +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column + +class Base(DeclarativeBase): + pass + + +class Simple(Base): + __tablename__ = 'simple' + __table_args__ = {'comment': "this is a 'comment'"} + + id: Mapped[int] = mapped_column(Integer, primary_key=True) +""", + ) + + +def test_metadata_column(generator: CodeGenerator) -> None: + Table( + "simple", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("metadata", VARCHAR), + ) + + validate_code( + generator.generate(), + """\ +from typing import Optional + +from sqlalchemy import Integer, String +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column + +class Base(DeclarativeBase): + pass + + +class Simple(Base): + __tablename__ = 'simple' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + metadata_: Mapped[Optional[str]] = mapped_column('metadata', String) +""", + ) + + +def test_invalid_variable_name_from_column(generator: CodeGenerator) -> None: + Table( + "simple", + generator.metadata, + Column(" id ", INTEGER, primary_key=True), + ) + + validate_code( + generator.generate(), + """\ +from sqlalchemy import Integer +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column + +class Base(DeclarativeBase): + pass + + +class Simple(Base): + __tablename__ = 'simple' + + id: Mapped[int] = mapped_column(' id ', Integer, primary_key=True) +""", + ) + + +def test_only_tables(generator: CodeGenerator) -> None: + Table("simple", generator.metadata, Column("id", INTEGER)) + + validate_code( + generator.generate(), + """\ +from sqlalchemy import Column, Integer, MetaData, Table + +metadata = MetaData() + + +t_simple = Table( + 'simple', metadata, + Column('id', Integer) +) + """, + ) + + +def test_named_constraints(generator: CodeGenerator) -> None: + Table( + "simple", + generator.metadata, + Column("id", INTEGER), + Column("text", VARCHAR), + CheckConstraint("id > 0", name="checktest"), + PrimaryKeyConstraint("id", name="primarytest"), + UniqueConstraint("text", name="uniquetest"), + ) + + validate_code( + generator.generate(), + """\ +from typing import Optional + +from sqlalchemy import CheckConstraint, Integer, PrimaryKeyConstraint, \ +String, UniqueConstraint +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column + +class Base(DeclarativeBase): + pass + + +class Simple(Base): + __tablename__ = 'simple' + __table_args__ = ( + CheckConstraint('id > 0', name='checktest'), + PrimaryKeyConstraint('id', name='primarytest'), + UniqueConstraint('text', name='uniquetest') + ) + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + text: Mapped[Optional[str]] = mapped_column(String) +""", + ) + + +def test_named_foreign_key_constraints(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("container_id", INTEGER), + ForeignKeyConstraint( + ["container_id"], ["simple_containers.id"], name="foreignkeytest" + ), + ) + Table( + "simple_containers", + generator.metadata, + Column("id", INTEGER, primary_key=True), + ) + + validate_code( + generator.generate(), + """\ +from typing import List, Optional + +from sqlalchemy import ForeignKeyConstraint, Integer +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship + +class Base(DeclarativeBase): + pass + + +class SimpleContainers(Base): + __tablename__ = 'simple_containers' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + + simple_items: Mapped[List['SimpleItems']] = relationship('SimpleItems', \ +back_populates='container') + + +class SimpleItems(Base): + __tablename__ = 'simple_items' + __table_args__ = ( + ForeignKeyConstraint(['container_id'], ['simple_containers.id'], \ +name='foreignkeytest'), + ) + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + container_id: Mapped[Optional[int]] = mapped_column(Integer) + + container: Mapped['SimpleContainers'] = relationship('SimpleContainers', \ +back_populates='simple_items') +""", + ) + + +# @pytest.mark.xfail(strict=True) +def test_colname_import_conflict(generator: CodeGenerator) -> None: + Table( + "simple", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("text", VARCHAR), + Column("textwithdefault", VARCHAR, server_default=text("'test'")), + ) + + validate_code( + generator.generate(), + """\ +from typing import Optional + +from sqlalchemy import Integer, String, text +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column + +class Base(DeclarativeBase): + pass + + +class Simple(Base): + __tablename__ = 'simple' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + text_: Mapped[Optional[str]] = mapped_column('text', String) + textwithdefault: Mapped[Optional[str]] = mapped_column(String, \ +server_default=text("'test'")) +""", + ) diff --git a/development/sqlacodegen/tests/test_generator_sqlmodel.py b/development/sqlacodegen/tests/test_generator_sqlmodel.py new file mode 100644 index 000000000..baf92dd6d --- /dev/null +++ b/development/sqlacodegen/tests/test_generator_sqlmodel.py @@ -0,0 +1,188 @@ +from __future__ import annotations + +import pytest +from _pytest.fixtures import FixtureRequest +from sqlalchemy.engine import Engine +from sqlalchemy.schema import ( + CheckConstraint, + Column, + ForeignKeyConstraint, + Index, + MetaData, + Table, + UniqueConstraint, +) +from sqlalchemy.types import INTEGER, VARCHAR + +from sqlacodegen.generators import CodeGenerator, SQLModelGenerator + +from .conftest import validate_code + + +@pytest.fixture +def generator( + request: FixtureRequest, metadata: MetaData, engine: Engine +) -> CodeGenerator: + options = getattr(request, "param", []) + return SQLModelGenerator(metadata, engine, options) + + +def test_indexes(generator: CodeGenerator) -> None: + simple_items = Table( + "item", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("number", INTEGER), + Column("text", VARCHAR), + ) + simple_items.indexes.add(Index("idx_number", simple_items.c.number)) + simple_items.indexes.add( + Index("idx_text_number", simple_items.c.text, simple_items.c.number) + ) + simple_items.indexes.add(Index("idx_text", simple_items.c.text, unique=True)) + + validate_code( + generator.generate(), + """\ + from typing import Optional + + from sqlalchemy import Column, Index, Integer, String + from sqlmodel import Field, SQLModel + + class Item(SQLModel, table=True): + __table_args__ = ( + Index('idx_number', 'number'), + Index('idx_text', 'text', unique=True), + Index('idx_text_number', 'text', 'number') + ) + + id: Optional[int] = Field(default=None, sa_column=Column(\ +'id', Integer, primary_key=True)) + number: Optional[int] = Field(default=None, sa_column=Column(\ +'number', Integer)) + text: Optional[str] = Field(default=None, sa_column=Column(\ +'text', String)) + """, + ) + + +def test_constraints(generator: CodeGenerator) -> None: + Table( + "simple_constraints", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("number", INTEGER), + CheckConstraint("number > 0"), + UniqueConstraint("id", "number"), + ) + + validate_code( + generator.generate(), + """\ + from typing import Optional + + from sqlalchemy import CheckConstraint, Column, Integer, UniqueConstraint + from sqlmodel import Field, SQLModel + + class SimpleConstraints(SQLModel, table=True): + __tablename__ = 'simple_constraints' + __table_args__ = ( + CheckConstraint('number > 0'), + UniqueConstraint('id', 'number') + ) + + id: Optional[int] = Field(default=None, sa_column=Column(\ +'id', Integer, primary_key=True)) + number: Optional[int] = Field(default=None, sa_column=Column(\ +'number', Integer)) + """, + ) + + +def test_onetomany(generator: CodeGenerator) -> None: + Table( + "simple_goods", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("container_id", INTEGER), + ForeignKeyConstraint(["container_id"], ["simple_containers.id"]), + ) + Table( + "simple_containers", + generator.metadata, + Column("id", INTEGER, primary_key=True), + ) + + validate_code( + generator.generate(), + """\ + from typing import List, Optional + + from sqlalchemy import Column, ForeignKey, Integer + from sqlmodel import Field, Relationship, SQLModel + + class SimpleContainers(SQLModel, table=True): + __tablename__ = 'simple_containers' + + id: Optional[int] = Field(default=None, sa_column=Column(\ +'id', Integer, primary_key=True)) + + simple_goods: List['SimpleGoods'] = Relationship(\ +back_populates='container') + + + class SimpleGoods(SQLModel, table=True): + __tablename__ = 'simple_goods' + + id: Optional[int] = Field(default=None, sa_column=Column(\ +'id', Integer, primary_key=True)) + container_id: Optional[int] = Field(default=None, sa_column=Column(\ +'container_id', ForeignKey('simple_containers.id'))) + + container: Optional['SimpleContainers'] = Relationship(\ +back_populates='simple_goods') + """, + ) + + +def test_onetoone(generator: CodeGenerator) -> None: + Table( + "simple_onetoone", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("other_item_id", INTEGER), + ForeignKeyConstraint(["other_item_id"], ["other_items.id"]), + UniqueConstraint("other_item_id"), + ) + Table("other_items", generator.metadata, Column("id", INTEGER, primary_key=True)) + + validate_code( + generator.generate(), + """\ + from typing import Optional + + from sqlalchemy import Column, ForeignKey, Integer + from sqlmodel import Field, Relationship, SQLModel + + class OtherItems(SQLModel, table=True): + __tablename__ = 'other_items' + + id: Optional[int] = Field(default=None, sa_column=Column(\ +'id', Integer, primary_key=True)) + + simple_onetoone: Optional['SimpleOnetoone'] = Relationship(\ +sa_relationship_kwargs={'uselist': False}, back_populates='other_item') + + + class SimpleOnetoone(SQLModel, table=True): + __tablename__ = 'simple_onetoone' + + id: Optional[int] = Field(default=None, sa_column=Column(\ +'id', Integer, primary_key=True)) + other_item_id: Optional[int] = Field(default=None, sa_column=Column(\ +'other_item_id', ForeignKey('other_items.id'), unique=True)) + + other_item: Optional['OtherItems'] = Relationship(\ +back_populates='simple_onetoone') + """, + ) diff --git a/development/sqlacodegen/tests/test_generator_tables.py b/development/sqlacodegen/tests/test_generator_tables.py new file mode 100644 index 000000000..bf6ff4eea --- /dev/null +++ b/development/sqlacodegen/tests/test_generator_tables.py @@ -0,0 +1,979 @@ +from __future__ import annotations + +from textwrap import dedent + +import pytest +from _pytest.fixtures import FixtureRequest +from sqlalchemy.dialects import mysql, postgresql +from sqlalchemy.engine import Engine +from sqlalchemy.schema import ( + CheckConstraint, + Column, + Computed, + ForeignKey, + Identity, + Index, + MetaData, + Table, + UniqueConstraint, +) +from sqlalchemy.sql.expression import text +from sqlalchemy.sql.sqltypes import NullType +from sqlalchemy.types import INTEGER, NUMERIC, SMALLINT, VARCHAR, Text + +from sqlacodegen.generators import CodeGenerator, TablesGenerator + +from .conftest import validate_code + + +@pytest.fixture +def generator( + request: FixtureRequest, metadata: MetaData, engine: Engine +) -> CodeGenerator: + options = getattr(request, "param", []) + return TablesGenerator(metadata, engine, options) + + +@pytest.mark.parametrize("engine", ["postgresql"], indirect=["engine"]) +def test_fancy_coltypes(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("enum", postgresql.ENUM("A", "B", name="blah")), + Column("bool", postgresql.BOOLEAN), + Column("number", NUMERIC(10, asdecimal=False)), + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Boolean, Column, Enum, MetaData, Numeric, Table + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('enum', Enum('A', 'B', name='blah')), + Column('bool', Boolean), + Column('number', Numeric(10, asdecimal=False)) + ) + """, + ) + + +def test_boolean_detection(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("bool1", INTEGER), + Column("bool2", SMALLINT), + Column("bool3", mysql.TINYINT), + CheckConstraint("simple_items.bool1 IN (0, 1)"), + CheckConstraint("simple_items.bool2 IN (0, 1)"), + CheckConstraint("simple_items.bool3 IN (0, 1)"), + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Boolean, Column, MetaData, Table + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('bool1', Boolean), + Column('bool2', Boolean), + Column('bool3', Boolean) + ) + """, + ) + + +@pytest.mark.parametrize("engine", ["postgresql"], indirect=["engine"]) +def test_arrays(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("dp_array", postgresql.ARRAY(postgresql.DOUBLE_PRECISION(precision=53))), + Column("int_array", postgresql.ARRAY(INTEGER)), + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import ARRAY, Column, Double, Integer, MetaData, Table + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('dp_array', ARRAY(Double(precision=53))), + Column('int_array', ARRAY(Integer())) + ) + """, + ) + + +@pytest.mark.parametrize("engine", ["postgresql"], indirect=["engine"]) +def test_jsonb(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("jsonb", postgresql.JSONB(astext_type=Text(50))), + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Column, MetaData, Table, Text + from sqlalchemy.dialects.postgresql import JSONB + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('jsonb', JSONB(astext_type=Text(length=50))) + ) + """, + ) + + +@pytest.mark.parametrize("engine", ["postgresql"], indirect=["engine"]) +def test_jsonb_default(generator: CodeGenerator) -> None: + Table("simple_items", generator.metadata, Column("jsonb", postgresql.JSONB)) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Column, MetaData, Table + from sqlalchemy.dialects.postgresql import JSONB + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('jsonb', JSONB) + ) + """, + ) + + +def test_enum_detection(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("enum", VARCHAR(255)), + CheckConstraint(r"simple_items.enum IN ('A', '\'B', 'C')"), + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Column, Enum, MetaData, Table + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('enum', Enum('A', "\\\\'B", 'C')) + ) + """, + ) + + +@pytest.mark.parametrize("engine", ["postgresql"], indirect=["engine"]) +def test_column_adaptation(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", postgresql.BIGINT), + Column("length", postgresql.DOUBLE_PRECISION), + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import BigInteger, Column, Double, MetaData, Table + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('id', BigInteger), + Column('length', Double) + ) + """, + ) + + +@pytest.mark.parametrize("engine", ["mysql"], indirect=["engine"]) +def test_mysql_column_types(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", mysql.INTEGER), + Column("name", mysql.VARCHAR(255)), + Column("set", mysql.SET("one", "two")), + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Column, Integer, MetaData, String, Table + from sqlalchemy.dialects.mysql import SET + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('id', Integer), + Column('name', String(255)), + Column('set', SET('one', 'two')) + ) + """, + ) + + +def test_constraints(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", INTEGER), + Column("number", INTEGER), + CheckConstraint("number > 0"), + UniqueConstraint("id", "number"), + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import CheckConstraint, Column, Integer, MetaData, Table, \ +UniqueConstraint + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('id', Integer), + Column('number', Integer), + CheckConstraint('number > 0'), + UniqueConstraint('id', 'number') + ) + """, + ) + + +def test_indexes(generator: CodeGenerator) -> None: + simple_items = Table( + "simple_items", + generator.metadata, + Column("id", INTEGER), + Column("number", INTEGER), + Column("text", VARCHAR), + Index("ix_empty"), + ) + simple_items.indexes.add(Index("ix_number", simple_items.c.number)) + simple_items.indexes.add( + Index( + "ix_text_number", + simple_items.c.text, + simple_items.c.number, + unique=True, + ) + ) + simple_items.indexes.add(Index("ix_text", simple_items.c.text, unique=True)) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Column, Index, Integer, MetaData, String, Table + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('id', Integer), + Column('number', Integer, index=True), + Column('text', String, unique=True, index=True), + Index('ix_empty'), + Index('ix_text_number', 'text', 'number', unique=True) + ) + """, + ) + + +def test_table_comment(generator: CodeGenerator) -> None: + Table( + "simple", + generator.metadata, + Column("id", INTEGER, primary_key=True), + comment="this is a 'comment'", + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Column, Integer, MetaData, Table + + metadata = MetaData() + + + t_simple = Table( + 'simple', metadata, + Column('id', Integer, primary_key=True), + comment="this is a 'comment'" + ) + """, + ) + + +def test_table_name_identifiers(generator: CodeGenerator) -> None: + Table( + "simple-items table", + generator.metadata, + Column("id", INTEGER, primary_key=True), + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Column, Integer, MetaData, Table + + metadata = MetaData() + + + t_simple_items_table = Table( + 'simple-items table', metadata, + Column('id', Integer, primary_key=True) + ) + """, + ) + + +@pytest.mark.parametrize("generator", [["noindexes"]], indirect=True) +def test_option_noindexes(generator: CodeGenerator) -> None: + simple_items = Table( + "simple_items", + generator.metadata, + Column("number", INTEGER), + CheckConstraint("number > 2"), + ) + simple_items.indexes.add(Index("idx_number", simple_items.c.number)) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import CheckConstraint, Column, Integer, MetaData, Table + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('number', Integer), + CheckConstraint('number > 2') + ) + """, + ) + + +@pytest.mark.parametrize("generator", [["noconstraints"]], indirect=True) +def test_option_noconstraints(generator: CodeGenerator) -> None: + simple_items = Table( + "simple_items", + generator.metadata, + Column("number", INTEGER), + CheckConstraint("number > 2"), + ) + simple_items.indexes.add(Index("ix_number", simple_items.c.number)) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Column, Integer, MetaData, Table + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('number', Integer, index=True) + ) + """, + ) + + +@pytest.mark.parametrize("generator", [["nocomments"]], indirect=True) +def test_option_nocomments(generator: CodeGenerator) -> None: + Table( + "simple", + generator.metadata, + Column("id", INTEGER, primary_key=True, comment="pk column comment"), + comment="this is a 'comment'", + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Column, Integer, MetaData, Table + + metadata = MetaData() + + + t_simple = Table( + 'simple', metadata, + Column('id', Integer, primary_key=True) + ) + """, + ) + + +@pytest.mark.parametrize( + "persisted, extra_args", + [(None, ""), (False, ", persisted=False"), (True, ", persisted=True")], +) +def test_computed_column( + generator: CodeGenerator, persisted: bool | None, extra_args: str +) -> None: + Table( + "computed", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("computed", INTEGER, Computed("1 + 2", persisted=persisted)), + ) + + validate_code( + generator.generate(), + f"""\ + from sqlalchemy import Column, Computed, Integer, MetaData, Table + + metadata = MetaData() + + + t_computed = Table( + 'computed', metadata, + Column('id', Integer, primary_key=True), + Column('computed', Integer, Computed('1 + 2'{extra_args})) + ) + """, + ) + + +def test_schema(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("name", VARCHAR), + schema="testschema", + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Column, MetaData, String, Table + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('name', String), + schema='testschema' + ) + """, + ) + + +def test_foreign_key_options(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column( + "name", + VARCHAR, + ForeignKey( + "simple_items.name", + ondelete="CASCADE", + onupdate="CASCADE", + deferrable=True, + initially="DEFERRED", + ), + ), + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Column, ForeignKey, MetaData, String, Table + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('name', String, ForeignKey('simple_items.name', \ +ondelete='CASCADE', onupdate='CASCADE', deferrable=True, initially='DEFERRED')) + ) + """, + ) + + +def test_pk_default(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column( + "id", + INTEGER, + primary_key=True, + server_default=text("uuid_generate_v4()"), + ), + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Column, Integer, MetaData, Table, text + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('id', Integer, primary_key=True, \ +server_default=text('uuid_generate_v4()')) + ) + """, + ) + + +@pytest.mark.parametrize("engine", ["mysql"], indirect=["engine"]) +def test_mysql_timestamp(generator: CodeGenerator) -> None: + Table( + "simple", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("timestamp", mysql.TIMESTAMP), + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Column, Integer, MetaData, TIMESTAMP, Table + + metadata = MetaData() + + + t_simple = Table( + 'simple', metadata, + Column('id', Integer, primary_key=True), + Column('timestamp', TIMESTAMP) + ) + """, + ) + + +@pytest.mark.parametrize("engine", ["mysql"], indirect=["engine"]) +def test_mysql_integer_display_width(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("number", mysql.INTEGER(11)), + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Column, Integer, MetaData, Table + from sqlalchemy.dialects.mysql import INTEGER + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('id', Integer, primary_key=True), + Column('number', INTEGER(11)) + ) + """, + ) + + +@pytest.mark.parametrize("engine", ["mysql"], indirect=["engine"]) +def test_mysql_tinytext(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("my_tinytext", mysql.TINYTEXT), + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Column, Integer, MetaData, Table + from sqlalchemy.dialects.mysql import TINYTEXT + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('id', Integer, primary_key=True), + Column('my_tinytext', TINYTEXT) + ) + """, + ) + + +@pytest.mark.parametrize("engine", ["mysql"], indirect=["engine"]) +def test_mysql_mediumtext(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("my_mediumtext", mysql.MEDIUMTEXT), + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Column, Integer, MetaData, Table + from sqlalchemy.dialects.mysql import MEDIUMTEXT + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('id', Integer, primary_key=True), + Column('my_mediumtext', MEDIUMTEXT) + ) + """, + ) + + +@pytest.mark.parametrize("engine", ["mysql"], indirect=["engine"]) +def test_mysql_longtext(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("my_longtext", mysql.LONGTEXT), + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Column, Integer, MetaData, Table + from sqlalchemy.dialects.mysql import LONGTEXT + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('id', Integer, primary_key=True), + Column('my_longtext', LONGTEXT) + ) + """, + ) + + +def test_schema_boolean(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("bool1", INTEGER), + CheckConstraint("testschema.simple_items.bool1 IN (0, 1)"), + schema="testschema", + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Boolean, Column, MetaData, Table + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('bool1', Boolean), + schema='testschema' + ) + """, + ) + + +def test_server_default_multiline(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column( + "id", + INTEGER, + primary_key=True, + server_default=text( + dedent( + """\ + /*Comment*/ + /*Next line*/ + something()""" + ) + ), + ), + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Column, Integer, MetaData, Table, text + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('id', Integer, primary_key=True, server_default=\ +text('/*Comment*/\\n/*Next line*/\\nsomething()')) + ) + """, + ) + + +def test_server_default_colon(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("problem", VARCHAR, server_default=text("':001'")), + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Column, MetaData, String, Table, text + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('problem', String, server_default=text("':001'")) + ) + """, + ) + + +def test_null_type(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("problem", NullType), + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Column, MetaData, Table + from sqlalchemy.sql.sqltypes import NullType + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('problem', NullType) + ) + """, + ) + + +def test_identity_column(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column( + "id", + INTEGER, + primary_key=True, + server_default=Identity(start=1, increment=2), + ), + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Column, Identity, Integer, MetaData, Table + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('id', Integer, Identity(start=1, increment=2), primary_key=True) + ) + """, + ) + + +def test_multiline_column_comment(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", INTEGER, comment="This\nis a multi-line\ncomment"), + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Column, Integer, MetaData, Table + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('id', Integer, comment='This\\nis a multi-line\\ncomment') + ) + """, + ) + + +def test_multiline_table_comment(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", INTEGER), + comment="This\nis a multi-line\ncomment", + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Column, Integer, MetaData, Table + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('id', Integer), + comment='This\\nis a multi-line\\ncomment' + ) + """, + ) + + +@pytest.mark.parametrize("engine", ["postgresql"], indirect=["engine"]) +def test_postgresql_sequence_standard_name(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column( + "id", + INTEGER, + primary_key=True, + server_default=text("nextval('simple_items_id_seq'::regclass)"), + ), + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Column, Integer, MetaData, Table + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('id', Integer, primary_key=True) + ) + """, + ) + + +@pytest.mark.parametrize("engine", ["postgresql"], indirect=["engine"]) +def test_postgresql_sequence_nonstandard_name(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column( + "id", + INTEGER, + primary_key=True, + server_default=text("nextval('test_seq'::regclass)"), + ), + ) + + validate_code( + generator.generate(), + """\ + from sqlalchemy import Column, Integer, MetaData, Sequence, Table + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('id', Integer, Sequence('test_seq'), primary_key=True) + ) + """, + ) + + +@pytest.mark.parametrize( + "schemaname, seqname", + [ + pytest.param("myschema", "test_seq"), + pytest.param("myschema", '"test_seq"'), + pytest.param('"my.schema"', "test_seq"), + pytest.param('"my.schema"', '"test_seq"'), + ], +) +@pytest.mark.parametrize("engine", ["postgresql"], indirect=["engine"]) +def test_postgresql_sequence_with_schema( + generator: CodeGenerator, schemaname: str, seqname: str +) -> None: + expected_schema = schemaname.strip('"') + Table( + "simple_items", + generator.metadata, + Column( + "id", + INTEGER, + primary_key=True, + server_default=text(f"nextval('{schemaname}.{seqname}'::regclass)"), + ), + schema=expected_schema, + ) + + validate_code( + generator.generate(), + f"""\ + from sqlalchemy import Column, Integer, MetaData, Sequence, Table + + metadata = MetaData() + + + t_simple_items = Table( + 'simple_items', metadata, + Column('id', Integer, Sequence('test_seq', \ +schema='{expected_schema}'), primary_key=True), + schema='{expected_schema}' + ) + """, + ) diff --git a/development/test-data/arXiv_archives.json b/development/test-data/arXiv_archives.json new file mode 100644 index 000000000..50c05c914 --- /dev/null +++ b/development/test-data/arXiv_archives.json @@ -0,0 +1,314 @@ +[ + { + "archive_id": "acc-phys", + "in_group": "physics", + "archive_name": "Accelerator Physics", + "start_date": "9411", + "end_date": "9609", + "subdivided": 0 + }, + { + "archive_id": "adap-org", + "in_group": "physics", + "archive_name": "Adaptation, Noise, and Self-Organizing Systems", + "start_date": "9303", + "end_date": "9912", + "subdivided": 0 + }, + { + "archive_id": "alg-geom", + "in_group": "math", + "archive_name": "Algebraic Geometry", + "start_date": "9202", + "end_date": "9712", + "subdivided": 0 + }, + { + "archive_id": "ao-sci", + "in_group": "physics", + "archive_name": "Atmospheric-Oceanic Sciences", + "start_date": "9502", + "end_date": "9609", + "subdivided": 0 + }, + { + "archive_id": "astro-ph", + "in_group": "physics", + "archive_name": "Astrophysics", + "start_date": "9204", + "end_date": "", + "subdivided": 0 + }, + { + "archive_id": "atom-ph", + "in_group": "physics", + "archive_name": "Atomic, Molecular and Optical Physics", + "start_date": "9509", + "end_date": "9609", + "subdivided": 0 + }, + { + "archive_id": "bayes-an", + "in_group": "physics", + "archive_name": "Bayesian Analysis", + "start_date": "9506", + "end_date": "9611", + "subdivided": 0 + }, + { + "archive_id": "chao-dyn", + "in_group": "physics", + "archive_name": "Chaotic Dynamics", + "start_date": "9301", + "end_date": "9912", + "subdivided": 0 + }, + { + "archive_id": "chem-ph", + "in_group": "physics", + "archive_name": "Chemical Physics", + "start_date": "9403", + "end_date": "9609", + "subdivided": 0 + }, + { + "archive_id": "cmp-lg", + "in_group": "cs", + "archive_name": "Computation and Language", + "start_date": "9404", + "end_date": "9809", + "subdivided": 0 + }, + { + "archive_id": "comp-gas", + "in_group": "physics", + "archive_name": "Cellular Automata and Lattice Gases", + "start_date": "9302", + "end_date": "9912", + "subdivided": 0 + }, + { + "archive_id": "cond-mat", + "in_group": "physics", + "archive_name": "Condensed Matter", + "start_date": "9204", + "end_date": "", + "subdivided": 1 + }, + { + "archive_id": "cs", + "in_group": "cs", + "archive_name": "Computer Science", + "start_date": "9301", + "end_date": "", + "subdivided": 2 + }, + { + "archive_id": "dg-ga", + "in_group": "math", + "archive_name": "Differential Geometry", + "start_date": "9406", + "end_date": "9712", + "subdivided": 0 + }, + { + "archive_id": "econ", + "in_group": "econ", + "archive_name": "Economics", + "start_date": "1709", + "end_date": "", + "subdivided": 2 + }, + { + "archive_id": "eess", + "in_group": "eess", + "archive_name": "Electrical Engineering and Systems Science", + "start_date": "1709", + "end_date": "", + "subdivided": 2 + }, + { + "archive_id": "funct-an", + "in_group": "math", + "archive_name": "Functional Analysis", + "start_date": "9204", + "end_date": "9712", + "subdivided": 0 + }, + { + "archive_id": "gr-qc", + "in_group": "physics", + "archive_name": "General Relativity and Quantum Cosmology", + "start_date": "9207", + "end_date": "", + "subdivided": 0 + }, + { + "archive_id": "hep-ex", + "in_group": "physics", + "archive_name": "High Energy Physics - Experiment", + "start_date": "9404", + "end_date": "", + "subdivided": 0 + }, + { + "archive_id": "hep-lat", + "in_group": "physics", + "archive_name": "High Energy Physics - Lattice", + "start_date": "9202", + "end_date": "", + "subdivided": 0 + }, + { + "archive_id": "hep-ph", + "in_group": "physics", + "archive_name": "High Energy Physics - Phenomenology", + "start_date": "9203", + "end_date": "", + "subdivided": 0 + }, + { + "archive_id": "hep-th", + "in_group": "physics", + "archive_name": "High Energy Physics - Theory", + "start_date": "9108", + "end_date": "", + "subdivided": 0 + }, + { + "archive_id": "math", + "in_group": "math", + "archive_name": "Mathematics", + "start_date": "9202", + "end_date": "", + "subdivided": 2 + }, + { + "archive_id": "math-ph", + "in_group": "physics", + "archive_name": "Mathematical Physics", + "start_date": "9609", + "end_date": "", + "subdivided": 0 + }, + { + "archive_id": "mtrl-th", + "in_group": "physics", + "archive_name": "Materials Theory", + "start_date": "9411", + "end_date": "9609", + "subdivided": 0 + }, + { + "archive_id": "nlin", + "in_group": "physics", + "archive_name": "Nonlinear Sciences", + "start_date": "9301", + "end_date": "", + "subdivided": 2 + }, + { + "archive_id": "nucl-ex", + "in_group": "physics", + "archive_name": "Nuclear Experiment", + "start_date": "9412", + "end_date": "", + "subdivided": 0 + }, + { + "archive_id": "nucl-th", + "in_group": "physics", + "archive_name": "Nuclear Theory", + "start_date": "9210", + "end_date": "", + "subdivided": 0 + }, + { + "archive_id": "patt-sol", + "in_group": "physics", + "archive_name": "Pattern Formation and Solitons", + "start_date": "9302", + "end_date": "9912", + "subdivided": 0 + }, + { + "archive_id": "physics", + "in_group": "physics", + "archive_name": "Physics", + "start_date": "9610", + "end_date": "", + "subdivided": 2 + }, + { + "archive_id": "plasm-ph", + "in_group": "physics", + "archive_name": "Plasma Physics", + "start_date": "9509", + "end_date": "9609", + "subdivided": 0 + }, + { + "archive_id": "q-alg", + "in_group": "math", + "archive_name": "Quantum Algebra and Topology", + "start_date": "9412", + "end_date": "9712", + "subdivided": 0 + }, + { + "archive_id": "q-bio", + "in_group": "q-bio", + "archive_name": "Quantitative Biology", + "start_date": "0309", + "end_date": "", + "subdivided": 2 + }, + { + "archive_id": "q-fin", + "in_group": "q-fin", + "archive_name": "Quantitative Finance", + "start_date": "0812", + "end_date": "", + "subdivided": 2 + }, + { + "archive_id": "quant-ph", + "in_group": "physics", + "archive_name": "Quantum Physics", + "start_date": "9412", + "end_date": "", + "subdivided": 0 + }, + { + "archive_id": "solv-int", + "in_group": "physics", + "archive_name": "Exactly Solvable and Integrable Systems", + "start_date": "9304", + "end_date": "9912", + "subdivided": 0 + }, + { + "archive_id": "stat", + "in_group": "stat", + "archive_name": "Statistics", + "start_date": "0704", + "end_date": "", + "subdivided": 2 + }, + { + "archive_id": "supr-con", + "in_group": "physics", + "archive_name": "Superconductivity", + "start_date": "9411", + "end_date": "9609", + "subdivided": 0 + }, + { + "archive_id": "test", + "in_group": "test", + "archive_name": "Test", + "start_date": "9502", + "end_date": "", + "subdivided": 1 + } +] \ No newline at end of file diff --git a/development/test-data/arXiv_categories.json b/development/test-data/arXiv_categories.json new file mode 100644 index 000000000..a1599dc7f --- /dev/null +++ b/development/test-data/arXiv_categories.json @@ -0,0 +1,2125 @@ +[ + { + "archive": "acc-phys", + "subject_class": "", + "definitive": 1, + "active": 0, + "category_name": "Accelerator Physics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "acc-phys" + }, + { + "archive": "adap-org", + "subject_class": "", + "definitive": 1, + "active": 0, + "category_name": "Adaptation, Noise, and Self-Organizing Systems", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "adap-org" + }, + { + "archive": "alg-geom", + "subject_class": "", + "definitive": 1, + "active": 0, + "category_name": "Algebraic Geometry", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "alg-geom" + }, + { + "archive": "ao-sci", + "subject_class": "", + "definitive": 1, + "active": 0, + "category_name": "Atmospheric-Oceanic Sciences", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "ao-sci" + }, + { + "archive": "astro-ph", + "subject_class": "", + "definitive": 1, + "active": 1, + "category_name": "Astrophysics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "astro-ph" + }, + { + "archive": "astro-ph", + "subject_class": "CO", + "definitive": 1, + "active": 1, + "category_name": "Cosmology and Nongalactic Astrophysics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "astro-ph" + }, + { + "archive": "astro-ph", + "subject_class": "EP", + "definitive": 1, + "active": 1, + "category_name": "Earth and Planetary Astrophysics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "astro-ph" + }, + { + "archive": "astro-ph", + "subject_class": "GA", + "definitive": 1, + "active": 1, + "category_name": "Astrophysics of Galaxies", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "astro-ph" + }, + { + "archive": "astro-ph", + "subject_class": "HE", + "definitive": 1, + "active": 1, + "category_name": "High Energy Astrophysical Phenomena", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "astro-ph" + }, + { + "archive": "astro-ph", + "subject_class": "IM", + "definitive": 1, + "active": 1, + "category_name": "Instrumentation and Methods for Astrophysics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "astro-ph" + }, + { + "archive": "astro-ph", + "subject_class": "SR", + "definitive": 1, + "active": 1, + "category_name": "Solar and Stellar Astrophysics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "astro-ph" + }, + { + "archive": "atom-ph", + "subject_class": "", + "definitive": 1, + "active": 0, + "category_name": "Atomic, Molecular and Optical Physics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "atom-ph" + }, + { + "archive": "bayes-an", + "subject_class": "", + "definitive": 1, + "active": 0, + "category_name": "Bayesian Analysis", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "bayes-an" + }, + { + "archive": "chao-dyn", + "subject_class": "", + "definitive": 1, + "active": 0, + "category_name": "Chaotic Dynamics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "chao-dyn" + }, + { + "archive": "chem-ph", + "subject_class": "", + "definitive": 1, + "active": 0, + "category_name": "Chemical Physics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "chem-ph" + }, + { + "archive": "cmp-lg", + "subject_class": "", + "definitive": 1, + "active": 0, + "category_name": "Computation and Language", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cmp-lg" + }, + { + "archive": "comp-gas", + "subject_class": "", + "definitive": 1, + "active": 0, + "category_name": "Cellular Automata and Lattice Gases", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "comp-gas" + }, + { + "archive": "cond-mat", + "subject_class": "", + "definitive": 0, + "active": 1, + "category_name": "Condensed Matter", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cond-mat" + }, + { + "archive": "cond-mat", + "subject_class": "dis-nn", + "definitive": 1, + "active": 1, + "category_name": "Disordered Systems and Neural Networks", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cond-mat" + }, + { + "archive": "cond-mat", + "subject_class": "mes-hall", + "definitive": 1, + "active": 1, + "category_name": "Mesoscale and Nanoscale Physics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cond-mat" + }, + { + "archive": "cond-mat", + "subject_class": "mtrl-sci", + "definitive": 1, + "active": 1, + "category_name": "Materials Science", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cond-mat" + }, + { + "archive": "cond-mat", + "subject_class": "none", + "definitive": 1, + "active": 0, + "category_name": "Condensed Matter", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cond-mat" + }, + { + "archive": "cond-mat", + "subject_class": "other", + "definitive": 1, + "active": 1, + "category_name": "Other Condensed Matter", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cond-mat" + }, + { + "archive": "cond-mat", + "subject_class": "quant-gas", + "definitive": 1, + "active": 1, + "category_name": "Quantum Gases", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cond-mat" + }, + { + "archive": "cond-mat", + "subject_class": "soft", + "definitive": 1, + "active": 1, + "category_name": "Soft Condensed Matter", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cond-mat" + }, + { + "archive": "cond-mat", + "subject_class": "stat-mech", + "definitive": 1, + "active": 1, + "category_name": "Statistical Mechanics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cond-mat" + }, + { + "archive": "cond-mat", + "subject_class": "str-el", + "definitive": 1, + "active": 1, + "category_name": "Strongly Correlated Electrons", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cond-mat" + }, + { + "archive": "cond-mat", + "subject_class": "supr-con", + "definitive": 1, + "active": 1, + "category_name": "Superconductivity", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cond-mat" + }, + { + "archive": "cs", + "subject_class": "", + "definitive": 0, + "active": 1, + "category_name": "Computer Science", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "AI", + "definitive": 1, + "active": 1, + "category_name": "Artificial Intelligence", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "AR", + "definitive": 1, + "active": 1, + "category_name": "Hardware Architecture", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "CC", + "definitive": 1, + "active": 1, + "category_name": "Computational Complexity", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "CE", + "definitive": 1, + "active": 1, + "category_name": "Computational Engineering, Finance, and Science", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "CG", + "definitive": 1, + "active": 1, + "category_name": "Computational Geometry", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "CL", + "definitive": 1, + "active": 1, + "category_name": "Computation and Language", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "CR", + "definitive": 1, + "active": 1, + "category_name": "Cryptography and Security", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "CV", + "definitive": 1, + "active": 1, + "category_name": "Computer Vision and Pattern Recognition", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "CY", + "definitive": 1, + "active": 1, + "category_name": "Computers and Society", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "DB", + "definitive": 1, + "active": 1, + "category_name": "Databases", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "DC", + "definitive": 1, + "active": 1, + "category_name": "Distributed, Parallel, and Cluster Computing", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "DL", + "definitive": 1, + "active": 1, + "category_name": "Digital Libraries", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "DM", + "definitive": 1, + "active": 1, + "category_name": "Discrete Mathematics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "DS", + "definitive": 1, + "active": 1, + "category_name": "Data Structures and Algorithms", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "ET", + "definitive": 1, + "active": 1, + "category_name": "Emerging Technologies", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "FL", + "definitive": 1, + "active": 1, + "category_name": "Formal Languages and Automata Theory", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "GL", + "definitive": 1, + "active": 1, + "category_name": "General Literature", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "GR", + "definitive": 1, + "active": 1, + "category_name": "Graphics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "GT", + "definitive": 1, + "active": 1, + "category_name": "Computer Science and Game Theory", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "HC", + "definitive": 1, + "active": 1, + "category_name": "Human-Computer Interaction", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "IR", + "definitive": 1, + "active": 1, + "category_name": "Information Retrieval", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "IT", + "definitive": 1, + "active": 1, + "category_name": "Information Theory", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "LG", + "definitive": 1, + "active": 1, + "category_name": "Learning", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "LO", + "definitive": 1, + "active": 1, + "category_name": "Logic in Computer Science", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "MA", + "definitive": 1, + "active": 1, + "category_name": "Multiagent Systems", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "MM", + "definitive": 1, + "active": 1, + "category_name": "Multimedia", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "MS", + "definitive": 1, + "active": 1, + "category_name": "Mathematical Software", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "NA", + "definitive": 1, + "active": 1, + "category_name": "Numerical Analysis", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "NE", + "definitive": 1, + "active": 1, + "category_name": "Neural and Evolutionary Computing", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "NI", + "definitive": 1, + "active": 1, + "category_name": "Networking and Internet Architecture", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "OH", + "definitive": 1, + "active": 1, + "category_name": "Other Computer Science", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "OS", + "definitive": 1, + "active": 1, + "category_name": "Operating Systems", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "PF", + "definitive": 1, + "active": 1, + "category_name": "Performance", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "PL", + "definitive": 1, + "active": 1, + "category_name": "Programming Languages", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "RO", + "definitive": 1, + "active": 1, + "category_name": "Robotics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "SC", + "definitive": 1, + "active": 1, + "category_name": "Symbolic Computation", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "SD", + "definitive": 1, + "active": 1, + "category_name": "Sound", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "SE", + "definitive": 1, + "active": 1, + "category_name": "Software Engineering", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "SI", + "definitive": 1, + "active": 1, + "category_name": "Social and Information Networks", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "cs", + "subject_class": "SY", + "definitive": 1, + "active": 1, + "category_name": "Systems and Control", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "cs" + }, + { + "archive": "dg-ga", + "subject_class": "", + "definitive": 1, + "active": 0, + "category_name": "Differential Geometry", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "dg-ga" + }, + { + "archive": "econ", + "subject_class": "", + "definitive": 0, + "active": 1, + "category_name": "Economics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "econ" + }, + { + "archive": "econ", + "subject_class": "EM", + "definitive": 1, + "active": 1, + "category_name": "Econometrics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "econ" + }, + { + "archive": "econ", + "subject_class": "GN", + "definitive": 1, + "active": 1, + "category_name": "General Economics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "econ" + }, + { + "archive": "econ", + "subject_class": "TH", + "definitive": 1, + "active": 1, + "category_name": "Theoretical Economics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "econ" + }, + { + "archive": "eess", + "subject_class": "", + "definitive": 0, + "active": 1, + "category_name": "Electrical Engineering and Systems Science", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "eess" + }, + { + "archive": "eess", + "subject_class": "AS", + "definitive": 1, + "active": 1, + "category_name": "Audio and Speech Processing", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "eess" + }, + { + "archive": "eess", + "subject_class": "IV", + "definitive": 1, + "active": 1, + "category_name": "Image and Video Processing", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "eess" + }, + { + "archive": "eess", + "subject_class": "SP", + "definitive": 1, + "active": 1, + "category_name": "Signal Processing", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "eess" + }, + { + "archive": "eess", + "subject_class": "SY", + "definitive": 1, + "active": 1, + "category_name": "Systems and Control", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "eess" + }, + { + "archive": "funct-an", + "subject_class": "", + "definitive": 1, + "active": 0, + "category_name": "Functional Analysis", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "funct-an" + }, + { + "archive": "gr-qc", + "subject_class": "", + "definitive": 1, + "active": 1, + "category_name": "General Relativity and Quantum Cosmology", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "gr-qc" + }, + { + "archive": "hep-ex", + "subject_class": "", + "definitive": 1, + "active": 1, + "category_name": "High Energy Physics - Experiment", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "hep-ex" + }, + { + "archive": "hep-lat", + "subject_class": "", + "definitive": 1, + "active": 1, + "category_name": "High Energy Physics - Lattice", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "hep-lat" + }, + { + "archive": "hep-ph", + "subject_class": "", + "definitive": 1, + "active": 1, + "category_name": "High Energy Physics - Phenomenology", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "hep-ph" + }, + { + "archive": "hep-th", + "subject_class": "", + "definitive": 1, + "active": 1, + "category_name": "High Energy Physics - Theory", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "hep-th" + }, + { + "archive": "math", + "subject_class": "", + "definitive": 0, + "active": 1, + "category_name": "Mathematics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "AC", + "definitive": 1, + "active": 1, + "category_name": "Commutative Algebra", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "AG", + "definitive": 1, + "active": 1, + "category_name": "Algebraic Geometry", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "AP", + "definitive": 1, + "active": 1, + "category_name": "Analysis of PDEs", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "AT", + "definitive": 1, + "active": 1, + "category_name": "Algebraic Topology", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "CA", + "definitive": 1, + "active": 1, + "category_name": "Classical Analysis and ODEs", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "CO", + "definitive": 1, + "active": 1, + "category_name": "Combinatorics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "CT", + "definitive": 1, + "active": 1, + "category_name": "Category Theory", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "CV", + "definitive": 1, + "active": 1, + "category_name": "Complex Variables", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "DG", + "definitive": 1, + "active": 1, + "category_name": "Differential Geometry", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "DS", + "definitive": 1, + "active": 1, + "category_name": "Dynamical Systems", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "FA", + "definitive": 1, + "active": 1, + "category_name": "Functional Analysis", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "GM", + "definitive": 1, + "active": 1, + "category_name": "General Mathematics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math.GM" + }, + { + "archive": "math", + "subject_class": "GN", + "definitive": 1, + "active": 1, + "category_name": "General Topology", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "GR", + "definitive": 1, + "active": 1, + "category_name": "Group Theory", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "GT", + "definitive": 1, + "active": 1, + "category_name": "Geometric Topology", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "HO", + "definitive": 1, + "active": 1, + "category_name": "History and Overview", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "IT", + "definitive": 1, + "active": 1, + "category_name": "Information Theory", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "KT", + "definitive": 1, + "active": 1, + "category_name": "K-Theory and Homology", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "LO", + "definitive": 1, + "active": 1, + "category_name": "Logic", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "MG", + "definitive": 1, + "active": 1, + "category_name": "Metric Geometry", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "MP", + "definitive": 1, + "active": 1, + "category_name": "Mathematical Physics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "NA", + "definitive": 1, + "active": 1, + "category_name": "Numerical Analysis", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "NT", + "definitive": 1, + "active": 1, + "category_name": "Number Theory", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "OA", + "definitive": 1, + "active": 1, + "category_name": "Operator Algebras", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "OC", + "definitive": 1, + "active": 1, + "category_name": "Optimization and Control", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "PR", + "definitive": 1, + "active": 1, + "category_name": "Probability", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "QA", + "definitive": 1, + "active": 1, + "category_name": "Quantum Algebra", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "RA", + "definitive": 1, + "active": 1, + "category_name": "Rings and Algebras", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "RT", + "definitive": 1, + "active": 1, + "category_name": "Representation Theory", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "SG", + "definitive": 1, + "active": 1, + "category_name": "Symplectic Geometry", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "SP", + "definitive": 1, + "active": 1, + "category_name": "Spectral Theory", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math", + "subject_class": "ST", + "definitive": 1, + "active": 1, + "category_name": "Statistics Theory", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math" + }, + { + "archive": "math-ph", + "subject_class": "", + "definitive": 1, + "active": 1, + "category_name": "Mathematical Physics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "math-ph" + }, + { + "archive": "mtrl-th", + "subject_class": "", + "definitive": 1, + "active": 0, + "category_name": "Materials Theory", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "mtrl-th" + }, + { + "archive": "nlin", + "subject_class": "", + "definitive": 0, + "active": 1, + "category_name": "Nonlinear Sciences", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "nlin" + }, + { + "archive": "nlin", + "subject_class": "AO", + "definitive": 1, + "active": 1, + "category_name": "Adaptation and Self-Organizing Systems", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "nlin" + }, + { + "archive": "nlin", + "subject_class": "CD", + "definitive": 1, + "active": 1, + "category_name": "Chaotic Dynamics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "nlin" + }, + { + "archive": "nlin", + "subject_class": "CG", + "definitive": 1, + "active": 1, + "category_name": "Cellular Automata and Lattice Gases", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "nlin" + }, + { + "archive": "nlin", + "subject_class": "PS", + "definitive": 1, + "active": 1, + "category_name": "Pattern Formation and Solitons", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "nlin" + }, + { + "archive": "nlin", + "subject_class": "SI", + "definitive": 1, + "active": 1, + "category_name": "Exactly Solvable and Integrable Systems", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "nlin" + }, + { + "archive": "nucl-ex", + "subject_class": "", + "definitive": 1, + "active": 1, + "category_name": "Nuclear Experiment", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "nucl-ex" + }, + { + "archive": "nucl-th", + "subject_class": "", + "definitive": 1, + "active": 1, + "category_name": "Nuclear Theory", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "nucl-th" + }, + { + "archive": "patt-sol", + "subject_class": "", + "definitive": 1, + "active": 0, + "category_name": "Pattern Formation and Solitons", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "patt-sol" + }, + { + "archive": "physics", + "subject_class": "", + "definitive": 0, + "active": 1, + "category_name": "Physics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "physics" + }, + { + "archive": "physics", + "subject_class": "acc-ph", + "definitive": 1, + "active": 1, + "category_name": "Accelerator Physics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "physics.acc-ph" + }, + { + "archive": "physics", + "subject_class": "ao-ph", + "definitive": 1, + "active": 1, + "category_name": "Atmospheric and Oceanic Physics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "physics.ao-ph" + }, + { + "archive": "physics", + "subject_class": "app-ph", + "definitive": 1, + "active": 1, + "category_name": "Applied Physics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "physics" + }, + { + "archive": "physics", + "subject_class": "atm-clus", + "definitive": 1, + "active": 1, + "category_name": "Atomic and Molecular Clusters", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "physics.atm-clus" + }, + { + "archive": "physics", + "subject_class": "atom-ph", + "definitive": 1, + "active": 1, + "category_name": "Atomic Physics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "physics.atom-ph" + }, + { + "archive": "physics", + "subject_class": "bio-ph", + "definitive": 1, + "active": 1, + "category_name": "Biological Physics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "physics.bio-ph" + }, + { + "archive": "physics", + "subject_class": "chem-ph", + "definitive": 1, + "active": 1, + "category_name": "Chemical Physics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "physics.chem-ph" + }, + { + "archive": "physics", + "subject_class": "class-ph", + "definitive": 1, + "active": 1, + "category_name": "Classical Physics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "physics.class-ph" + }, + { + "archive": "physics", + "subject_class": "comp-ph", + "definitive": 1, + "active": 1, + "category_name": "Computational Physics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "physics.comp-ph" + }, + { + "archive": "physics", + "subject_class": "data-an", + "definitive": 1, + "active": 1, + "category_name": "Data Analysis, Statistics and Probability", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "physics.data-an" + }, + { + "archive": "physics", + "subject_class": "ed-ph", + "definitive": 1, + "active": 1, + "category_name": "Physics Education", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "physics.ed-ph" + }, + { + "archive": "physics", + "subject_class": "flu-dyn", + "definitive": 1, + "active": 1, + "category_name": "Fluid Dynamics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "physics.flu-dyn" + }, + { + "archive": "physics", + "subject_class": "gen-ph", + "definitive": 1, + "active": 1, + "category_name": "General Physics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "physics.gen-ph" + }, + { + "archive": "physics", + "subject_class": "geo-ph", + "definitive": 1, + "active": 1, + "category_name": "Geophysics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "physics.geo-ph" + }, + { + "archive": "physics", + "subject_class": "hist-ph", + "definitive": 1, + "active": 1, + "category_name": "History and Philosophy of Physics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "physics.hist-ph" + }, + { + "archive": "physics", + "subject_class": "ins-det", + "definitive": 1, + "active": 1, + "category_name": "Instrumentation and Detectors", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "physics.ins-det" + }, + { + "archive": "physics", + "subject_class": "med-ph", + "definitive": 1, + "active": 1, + "category_name": "Medical Physics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "physics.med-ph" + }, + { + "archive": "physics", + "subject_class": "optics", + "definitive": 1, + "active": 1, + "category_name": "Optics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "physics.optics" + }, + { + "archive": "physics", + "subject_class": "plasm-ph", + "definitive": 1, + "active": 1, + "category_name": "Plasma Physics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "physics.plasm-ph" + }, + { + "archive": "physics", + "subject_class": "pop-ph", + "definitive": 1, + "active": 1, + "category_name": "Popular Physics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "physics.pop-ph" + }, + { + "archive": "physics", + "subject_class": "soc-ph", + "definitive": 1, + "active": 1, + "category_name": "Physics and Society", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "physics.soc-ph" + }, + { + "archive": "physics", + "subject_class": "space-ph", + "definitive": 1, + "active": 1, + "category_name": "Space Physics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "physics.space-ph" + }, + { + "archive": "plasm-ph", + "subject_class": "", + "definitive": 1, + "active": 0, + "category_name": "Plasma Physics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "plasm-ph" + }, + { + "archive": "q-alg", + "subject_class": "", + "definitive": 1, + "active": 0, + "category_name": "Quantum Algebra and Topology", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "q-alg" + }, + { + "archive": "q-bio", + "subject_class": "", + "definitive": 0, + "active": 1, + "category_name": "Quantitative Biology", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "q-bio" + }, + { + "archive": "q-bio", + "subject_class": "BM", + "definitive": 1, + "active": 1, + "category_name": "Biomolecules", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "q-bio" + }, + { + "archive": "q-bio", + "subject_class": "CB", + "definitive": 1, + "active": 1, + "category_name": "Cell Behavior", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "q-bio" + }, + { + "archive": "q-bio", + "subject_class": "GN", + "definitive": 1, + "active": 1, + "category_name": "Genomics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "q-bio" + }, + { + "archive": "q-bio", + "subject_class": "MN", + "definitive": 1, + "active": 1, + "category_name": "Molecular Networks", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "q-bio" + }, + { + "archive": "q-bio", + "subject_class": "NC", + "definitive": 1, + "active": 1, + "category_name": "Neurons and Cognition", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "q-bio" + }, + { + "archive": "q-bio", + "subject_class": "OT", + "definitive": 1, + "active": 1, + "category_name": "Other Quantitative Biology", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "q-bio" + }, + { + "archive": "q-bio", + "subject_class": "PE", + "definitive": 1, + "active": 1, + "category_name": "Populations and Evolution", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "q-bio" + }, + { + "archive": "q-bio", + "subject_class": "QM", + "definitive": 1, + "active": 1, + "category_name": "Quantitative Methods", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "q-bio" + }, + { + "archive": "q-bio", + "subject_class": "SC", + "definitive": 1, + "active": 1, + "category_name": "Subcellular Processes", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "q-bio" + }, + { + "archive": "q-bio", + "subject_class": "TO", + "definitive": 1, + "active": 1, + "category_name": "Tissues and Organs", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "q-bio" + }, + { + "archive": "q-fin", + "subject_class": "", + "definitive": 0, + "active": 1, + "category_name": "Quantitative Finance", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "q-fin" + }, + { + "archive": "q-fin", + "subject_class": "CP", + "definitive": 1, + "active": 1, + "category_name": "Computational Finance", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "q-fin" + }, + { + "archive": "q-fin", + "subject_class": "EC", + "definitive": 1, + "active": 1, + "category_name": "Economics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "q-fin" + }, + { + "archive": "q-fin", + "subject_class": "GN", + "definitive": 1, + "active": 1, + "category_name": "General Finance", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "q-fin" + }, + { + "archive": "q-fin", + "subject_class": "MF", + "definitive": 1, + "active": 1, + "category_name": "Mathematical Finance", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "q-fin" + }, + { + "archive": "q-fin", + "subject_class": "PM", + "definitive": 1, + "active": 1, + "category_name": "Portfolio Management", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "q-fin" + }, + { + "archive": "q-fin", + "subject_class": "PR", + "definitive": 1, + "active": 1, + "category_name": "Pricing of Securities", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "q-fin" + }, + { + "archive": "q-fin", + "subject_class": "RM", + "definitive": 1, + "active": 1, + "category_name": "Risk Management", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "q-fin" + }, + { + "archive": "q-fin", + "subject_class": "ST", + "definitive": 1, + "active": 1, + "category_name": "Statistical Finance", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "q-fin" + }, + { + "archive": "q-fin", + "subject_class": "TR", + "definitive": 1, + "active": 1, + "category_name": "Trading and Market Microstructure", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "q-fin" + }, + { + "archive": "quant-ph", + "subject_class": "", + "definitive": 1, + "active": 1, + "category_name": "Quantum Physics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "quant-ph" + }, + { + "archive": "solv-int", + "subject_class": "", + "definitive": 1, + "active": 0, + "category_name": "Exactly Solvable and Integrable Systems", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "solv-int" + }, + { + "archive": "stat", + "subject_class": "", + "definitive": 0, + "active": 1, + "category_name": "Statistics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "stat" + }, + { + "archive": "stat", + "subject_class": "AP", + "definitive": 1, + "active": 1, + "category_name": "Applications", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "stat" + }, + { + "archive": "stat", + "subject_class": "CO", + "definitive": 1, + "active": 1, + "category_name": "Computation", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "stat" + }, + { + "archive": "stat", + "subject_class": "ME", + "definitive": 1, + "active": 1, + "category_name": "Methodology", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "stat" + }, + { + "archive": "stat", + "subject_class": "ML", + "definitive": 1, + "active": 1, + "category_name": "Machine Learning", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "stat" + }, + { + "archive": "stat", + "subject_class": "OT", + "definitive": 1, + "active": 1, + "category_name": "Other Statistics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "stat" + }, + { + "archive": "stat", + "subject_class": "TH", + "definitive": 1, + "active": 1, + "category_name": "Statistics Theory", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "stat" + }, + { + "archive": "supr-con", + "subject_class": "", + "definitive": 1, + "active": 0, + "category_name": "Superconductivity", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "supr-con" + }, + { + "archive": "test", + "subject_class": "", + "definitive": 0, + "active": 1, + "category_name": "Test", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "test" + }, + { + "archive": "test", + "subject_class": "dis-nn", + "definitive": 1, + "active": 1, + "category_name": "Test Disruptive Networks", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "test" + }, + { + "archive": "test", + "subject_class": "mes-hall", + "definitive": 1, + "active": 1, + "category_name": "Test Hall", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "test" + }, + { + "archive": "test", + "subject_class": "mtrl-sci", + "definitive": 1, + "active": 1, + "category_name": "Test Mtrl-Sci", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "test" + }, + { + "archive": "test", + "subject_class": "soft", + "definitive": 1, + "active": 1, + "category_name": "Test Soft", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "test" + }, + { + "archive": "test", + "subject_class": "stat-mech", + "definitive": 1, + "active": 1, + "category_name": "Test Mechanics", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "test" + }, + { + "archive": "test", + "subject_class": "str-el", + "definitive": 1, + "active": 1, + "category_name": "Test Electrons", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "test" + }, + { + "archive": "test", + "subject_class": "supr-con", + "definitive": 1, + "active": 1, + "category_name": "Test Superconductivity", + "endorse_all": "d", + "endorse_email": "d", + "papers_to_endorse": 0, + "endorsement_domain": "test" + } +] \ No newline at end of file diff --git a/development/test-data/arXiv_endorsement_domains.json b/development/test-data/arXiv_endorsement_domains.json new file mode 100644 index 000000000..75b3d798b --- /dev/null +++ b/development/test-data/arXiv_endorsement_domains.json @@ -0,0 +1,436 @@ +[ + { + "endorsement_domain": "acc-phys", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "adap-org", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "alg-geom", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "ao-sci", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "astro-ph", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "atom-ph", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "bayes-an", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "chao-dyn", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "chem-ph", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "cmp-lg", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "comp-gas", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "cond-mat", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "cs", + "endorse_all": "n", + "mods_endorse_all": "y", + "endorse_email": "y", + "papers_to_endorse": 3 + }, + { + "endorsement_domain": "dg-ga", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "econ", + "endorse_all": "n", + "mods_endorse_all": "y", + "endorse_email": "y", + "papers_to_endorse": 3 + }, + { + "endorsement_domain": "eess", + "endorse_all": "n", + "mods_endorse_all": "y", + "endorse_email": "y", + "papers_to_endorse": 3 + }, + { + "endorsement_domain": "funct-an", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "gr-qc", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "hep-ex", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "hep-lat", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "hep-ph", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "hep-th", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "math", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "math-ph", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "math.GM", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 2 + }, + { + "endorsement_domain": "mtrl-th", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "nlin", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "nucl-ex", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "nucl-th", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "patt-sol", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "phys-lib", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "physics", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "physics.acc-ph", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 2 + }, + { + "endorsement_domain": "physics.ao-ph", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 2 + }, + { + "endorsement_domain": "physics.atm-clus", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 2 + }, + { + "endorsement_domain": "physics.atom-ph", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 2 + }, + { + "endorsement_domain": "physics.bio-ph", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 2 + }, + { + "endorsement_domain": "physics.chem-ph", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 2 + }, + { + "endorsement_domain": "physics.class-ph", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 2 + }, + { + "endorsement_domain": "physics.comp-ph", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 2 + }, + { + "endorsement_domain": "physics.data-an", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 2 + }, + { + "endorsement_domain": "physics.ed-ph", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 2 + }, + { + "endorsement_domain": "physics.flu-dyn", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 2 + }, + { + "endorsement_domain": "physics.gen-ph", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 2 + }, + { + "endorsement_domain": "physics.geo-ph", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 2 + }, + { + "endorsement_domain": "physics.hist-ph", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 2 + }, + { + "endorsement_domain": "physics.ins-det", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 2 + }, + { + "endorsement_domain": "physics.med-ph", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 2 + }, + { + "endorsement_domain": "physics.optics", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 2 + }, + { + "endorsement_domain": "physics.plasm-ph", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 2 + }, + { + "endorsement_domain": "physics.pop-ph", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 2 + }, + { + "endorsement_domain": "physics.soc-ph", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 2 + }, + { + "endorsement_domain": "physics.space-ph", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 2 + }, + { + "endorsement_domain": "plasm-ph", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "q-alg", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "q-bio", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 2 + }, + { + "endorsement_domain": "q-fin", + "endorse_all": "n", + "mods_endorse_all": "y", + "endorse_email": "y", + "papers_to_endorse": 2 + }, + { + "endorsement_domain": "quant-ph", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "solv-int", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "stat", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 2 + }, + { + "endorsement_domain": "supr-con", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + }, + { + "endorsement_domain": "test", + "endorse_all": "n", + "mods_endorse_all": "n", + "endorse_email": "y", + "papers_to_endorse": 4 + } +] \ No newline at end of file diff --git a/development/test-data/arXiv_groups.json b/development/test-data/arXiv_groups.json new file mode 100644 index 000000000..a892e375c --- /dev/null +++ b/development/test-data/arXiv_groups.json @@ -0,0 +1,47 @@ +[ + { + "group_id": "cs", + "group_name": "Computer Science", + "start_year": "1993" + }, + { + "group_id": "econ", + "group_name": "Economics", + "start_year": "2017" + }, + { + "group_id": "eess", + "group_name": "Electrical Engineering and Systems Science", + "start_year": "2017" + }, + { + "group_id": "math", + "group_name": "Mathematics", + "start_year": "1992" + }, + { + "group_id": "physics", + "group_name": "Physics", + "start_year": "1991" + }, + { + "group_id": "q-bio", + "group_name": "Quantitative Biology", + "start_year": "1992" + }, + { + "group_id": "q-fin", + "group_name": "Quantitative Finance", + "start_year": "1997" + }, + { + "group_id": "stat", + "group_name": "Statistics", + "start_year": "1999" + }, + { + "group_id": "test", + "group_name": "Test", + "start_year": "1995" + } +] \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index 24f092a3f..ba8f84279 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2,90 +2,147 @@ [[package]] name = "alabaster" -version = "0.7.16" +version = "1.0.0" description = "A light, configurable Sphinx theme" optional = true -python-versions = ">=3.9" +python-versions = ">=3.10" files = [ - {file = "alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92"}, - {file = "alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65"}, + {file = "alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b"}, + {file = "alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e"}, ] [[package]] name = "attrs" -version = "23.2.0" +version = "24.2.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" files = [ - {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, - {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, + {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, + {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, ] [package.extras] -cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[tests]", "pre-commit"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] -tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] -tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] +benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] + +[[package]] +name = "autopep8" +version = "2.3.1" +description = "A tool that automatically formats Python code to conform to the PEP 8 style guide" +optional = false +python-versions = ">=3.8" +files = [ + {file = "autopep8-2.3.1-py2.py3-none-any.whl", hash = "sha256:a203fe0fcad7939987422140ab17a930f684763bf7335bdb6709991dd7ef6c2d"}, + {file = "autopep8-2.3.1.tar.gz", hash = "sha256:8d6c87eba648fdcfc83e29b788910b8643171c395d9c4bcf115ece035b9c9dda"}, +] + +[package.dependencies] +pycodestyle = ">=2.12.0" [[package]] name = "babel" -version = "2.15.0" +version = "2.16.0" description = "Internationalization utilities" optional = true python-versions = ">=3.8" files = [ - {file = "Babel-2.15.0-py3-none-any.whl", hash = "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb"}, - {file = "babel-2.15.0.tar.gz", hash = "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"}, + {file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"}, + {file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"}, ] [package.extras] dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] +[[package]] +name = "black" +version = "24.10.0" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.9" +files = [ + {file = "black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812"}, + {file = "black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea"}, + {file = "black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f"}, + {file = "black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e"}, + {file = "black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad"}, + {file = "black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50"}, + {file = "black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392"}, + {file = "black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175"}, + {file = "black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3"}, + {file = "black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65"}, + {file = "black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f"}, + {file = "black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8"}, + {file = "black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981"}, + {file = "black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b"}, + {file = "black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2"}, + {file = "black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b"}, + {file = "black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd"}, + {file = "black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f"}, + {file = "black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800"}, + {file = "black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7"}, + {file = "black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d"}, + {file = "black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.10)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + [[package]] name = "bleach" -version = "6.1.0" +version = "6.2.0" description = "An easy safelist-based HTML-sanitizing tool." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "bleach-6.1.0-py3-none-any.whl", hash = "sha256:3225f354cfc436b9789c66c4ee030194bee0568fbf9cbdad3bc8b5c26c5f12b6"}, - {file = "bleach-6.1.0.tar.gz", hash = "sha256:0a31f1837963c41d46bbf1331b8778e1308ea0791db03cc4e7357b97cf42a8fe"}, + {file = "bleach-6.2.0-py3-none-any.whl", hash = "sha256:117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e"}, + {file = "bleach-6.2.0.tar.gz", hash = "sha256:123e894118b8a599fd80d3ec1a6d4cc7ce4e5882b1317a7e1ba69b56e95f991f"}, ] [package.dependencies] -six = ">=1.9.0" webencodings = "*" [package.extras] -css = ["tinycss2 (>=1.1.0,<1.3)"] +css = ["tinycss2 (>=1.1.0,<1.5)"] [[package]] name = "blinker" -version = "1.8.2" +version = "1.9.0" description = "Fast, simple object-to-object and broadcast signaling" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "blinker-1.8.2-py3-none-any.whl", hash = "sha256:1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01"}, - {file = "blinker-1.8.2.tar.gz", hash = "sha256:8f77b09d3bf7c795e969e9486f39c2c5e9c39d4ee07424be2bc594ece9642d83"}, + {file = "blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc"}, + {file = "blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf"}, ] [[package]] name = "boto3" -version = "1.34.108" +version = "1.35.80" description = "The AWS SDK for Python" optional = false python-versions = ">=3.8" files = [ - {file = "boto3-1.34.108-py3-none-any.whl", hash = "sha256:3601267d76cac17f1d4595c3d8d968dc15be074b79bfa3985187a02b328a0a5f"}, - {file = "boto3-1.34.108.tar.gz", hash = "sha256:677723295151d29ff9b363598a20c1997c4e2af7e50669d9e428b757fe586a10"}, + {file = "boto3-1.35.80-py3-none-any.whl", hash = "sha256:21a3b18c3a7fd20e463708fe3fa035983105dc7f3a1c274e1903e1583ab91159"}, + {file = "boto3-1.35.80.tar.gz", hash = "sha256:50dae461ab5fbedfb81b690895d48a918fed0d5fdff37be1c4232770c0dc9712"}, ] [package.dependencies] -botocore = ">=1.34.108,<1.35.0" +botocore = ">=1.35.80,<1.36.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.10.0,<0.11.0" @@ -94,13 +151,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.34.108" +version = "1.35.80" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.8" files = [ - {file = "botocore-1.34.108-py3-none-any.whl", hash = "sha256:b1b9d00804267669c5fcc36489269f7e9c43580c30f0885fbf669cf73cec720b"}, - {file = "botocore-1.34.108.tar.gz", hash = "sha256:384c9408c447631475dc41fdc9bf2e0f30c29c420d96bfe8b468bdc2bace3e13"}, + {file = "botocore-1.35.80-py3-none-any.whl", hash = "sha256:36e589dccb62380abd628b08fecfa2f7c89b99f41ec9fc42c467c94008c0be4a"}, + {file = "botocore-1.35.80.tar.gz", hash = "sha256:b8dfceca58891cb2711bd6455ec4f7159051f3796e0f64adef9bb334f19d8a92"}, ] [package.dependencies] @@ -109,89 +166,104 @@ python-dateutil = ">=2.1,<3.0.0" urllib3 = {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""} [package.extras] -crt = ["awscrt (==0.20.9)"] +crt = ["awscrt (==0.22.0)"] [[package]] name = "cachetools" -version = "5.3.3" +version = "5.5.0" description = "Extensible memoizing collections and decorators" optional = false python-versions = ">=3.7" files = [ - {file = "cachetools-5.3.3-py3-none-any.whl", hash = "sha256:0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945"}, - {file = "cachetools-5.3.3.tar.gz", hash = "sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105"}, + {file = "cachetools-5.5.0-py3-none-any.whl", hash = "sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292"}, + {file = "cachetools-5.5.0.tar.gz", hash = "sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a"}, ] [[package]] name = "certifi" -version = "2024.7.4" +version = "2024.8.30" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, - {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, ] [[package]] name = "cffi" -version = "1.16.0" +version = "1.17.1" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" files = [ - {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, - {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, - {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, - {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, - {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, - {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, - {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, - {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, - {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, - {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, - {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, - {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, - {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, - {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, - {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, + {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, + {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, + {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, + {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, + {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, + {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, + {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, + {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, + {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, + {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, + {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, ] [package.dependencies] @@ -199,101 +271,116 @@ pycparser = "*" [[package]] name = "charset-normalizer" -version = "3.3.2" +version = "3.4.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, - {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, + {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, + {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, ] [[package]] @@ -310,6 +397,23 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} +[[package]] +name = "cloudevents" +version = "1.11.0" +description = "CloudEvents Python SDK" +optional = false +python-versions = "*" +files = [ + {file = "cloudevents-1.11.0-py3-none-any.whl", hash = "sha256:77edb4f2b01f405c44ea77120c3213418dbc63d8859f98e9e85de875502b8a76"}, + {file = "cloudevents-1.11.0.tar.gz", hash = "sha256:5be990583e99f3b08af5a709460e20b25cb169270227957a20b47a6ec8635e66"}, +] + +[package.dependencies] +deprecation = ">=2.0,<3.0" + +[package.extras] +pydantic = ["pydantic (>=1.0.0,<3.0)"] + [[package]] name = "colorama" version = "0.4.6" @@ -323,63 +427,73 @@ files = [ [[package]] name = "coverage" -version = "7.5.1" +version = "7.6.9" description = "Code coverage measurement for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "coverage-7.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0884920835a033b78d1c73b6d3bbcda8161a900f38a488829a83982925f6c2e"}, - {file = "coverage-7.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:39afcd3d4339329c5f58de48a52f6e4e50f6578dd6099961cf22228feb25f38f"}, - {file = "coverage-7.5.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a7b0ceee8147444347da6a66be737c9d78f3353b0681715b668b72e79203e4a"}, - {file = "coverage-7.5.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a9ca3f2fae0088c3c71d743d85404cec8df9be818a005ea065495bedc33da35"}, - {file = "coverage-7.5.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd215c0c7d7aab005221608a3c2b46f58c0285a819565887ee0b718c052aa4e"}, - {file = "coverage-7.5.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4bf0655ab60d754491004a5efd7f9cccefcc1081a74c9ef2da4735d6ee4a6223"}, - {file = "coverage-7.5.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:61c4bf1ba021817de12b813338c9be9f0ad5b1e781b9b340a6d29fc13e7c1b5e"}, - {file = "coverage-7.5.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:db66fc317a046556a96b453a58eced5024af4582a8dbdc0c23ca4dbc0d5b3146"}, - {file = "coverage-7.5.1-cp310-cp310-win32.whl", hash = "sha256:b016ea6b959d3b9556cb401c55a37547135a587db0115635a443b2ce8f1c7228"}, - {file = "coverage-7.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:df4e745a81c110e7446b1cc8131bf986157770fa405fe90e15e850aaf7619bc8"}, - {file = "coverage-7.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:796a79f63eca8814ca3317a1ea443645c9ff0d18b188de470ed7ccd45ae79428"}, - {file = "coverage-7.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4fc84a37bfd98db31beae3c2748811a3fa72bf2007ff7902f68746d9757f3746"}, - {file = "coverage-7.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6175d1a0559986c6ee3f7fccfc4a90ecd12ba0a383dcc2da30c2b9918d67d8a3"}, - {file = "coverage-7.5.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fc81d5878cd6274ce971e0a3a18a8803c3fe25457165314271cf78e3aae3aa2"}, - {file = "coverage-7.5.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:556cf1a7cbc8028cb60e1ff0be806be2eded2daf8129b8811c63e2b9a6c43bca"}, - {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9981706d300c18d8b220995ad22627647be11a4276721c10911e0e9fa44c83e8"}, - {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d7fed867ee50edf1a0b4a11e8e5d0895150e572af1cd6d315d557758bfa9c057"}, - {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ef48e2707fb320c8f139424a596f5b69955a85b178f15af261bab871873bb987"}, - {file = "coverage-7.5.1-cp311-cp311-win32.whl", hash = "sha256:9314d5678dcc665330df5b69c1e726a0e49b27df0461c08ca12674bcc19ef136"}, - {file = "coverage-7.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:5fa567e99765fe98f4e7d7394ce623e794d7cabb170f2ca2ac5a4174437e90dd"}, - {file = "coverage-7.5.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b6cf3764c030e5338e7f61f95bd21147963cf6aa16e09d2f74f1fa52013c1206"}, - {file = "coverage-7.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ec92012fefebee89a6b9c79bc39051a6cb3891d562b9270ab10ecfdadbc0c34"}, - {file = "coverage-7.5.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16db7f26000a07efcf6aea00316f6ac57e7d9a96501e990a36f40c965ec7a95d"}, - {file = "coverage-7.5.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:beccf7b8a10b09c4ae543582c1319c6df47d78fd732f854ac68d518ee1fb97fa"}, - {file = "coverage-7.5.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8748731ad392d736cc9ccac03c9845b13bb07d020a33423fa5b3a36521ac6e4e"}, - {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7352b9161b33fd0b643ccd1f21f3a3908daaddf414f1c6cb9d3a2fd618bf2572"}, - {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:7a588d39e0925f6a2bff87154752481273cdb1736270642aeb3635cb9b4cad07"}, - {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:68f962d9b72ce69ea8621f57551b2fa9c70509af757ee3b8105d4f51b92b41a7"}, - {file = "coverage-7.5.1-cp312-cp312-win32.whl", hash = "sha256:f152cbf5b88aaeb836127d920dd0f5e7edff5a66f10c079157306c4343d86c19"}, - {file = "coverage-7.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:5a5740d1fb60ddf268a3811bcd353de34eb56dc24e8f52a7f05ee513b2d4f596"}, - {file = "coverage-7.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e2213def81a50519d7cc56ed643c9e93e0247f5bbe0d1247d15fa520814a7cd7"}, - {file = "coverage-7.5.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5037f8fcc2a95b1f0e80585bd9d1ec31068a9bcb157d9750a172836e98bc7a90"}, - {file = "coverage-7.5.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3721c2c9e4c4953a41a26c14f4cef64330392a6d2d675c8b1db3b645e31f0e"}, - {file = "coverage-7.5.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca498687ca46a62ae590253fba634a1fe9836bc56f626852fb2720f334c9e4e5"}, - {file = "coverage-7.5.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0cdcbc320b14c3e5877ee79e649677cb7d89ef588852e9583e6b24c2e5072661"}, - {file = "coverage-7.5.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:57e0204b5b745594e5bc14b9b50006da722827f0b8c776949f1135677e88d0b8"}, - {file = "coverage-7.5.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fe7502616b67b234482c3ce276ff26f39ffe88adca2acf0261df4b8454668b4"}, - {file = "coverage-7.5.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:9e78295f4144f9dacfed4f92935fbe1780021247c2fabf73a819b17f0ccfff8d"}, - {file = "coverage-7.5.1-cp38-cp38-win32.whl", hash = "sha256:1434e088b41594baa71188a17533083eabf5609e8e72f16ce8c186001e6b8c41"}, - {file = "coverage-7.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:0646599e9b139988b63704d704af8e8df7fa4cbc4a1f33df69d97f36cb0a38de"}, - {file = "coverage-7.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4cc37def103a2725bc672f84bd939a6fe4522310503207aae4d56351644682f1"}, - {file = "coverage-7.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fc0b4d8bfeabd25ea75e94632f5b6e047eef8adaed0c2161ada1e922e7f7cece"}, - {file = "coverage-7.5.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d0a0f5e06881ecedfe6f3dd2f56dcb057b6dbeb3327fd32d4b12854df36bf26"}, - {file = "coverage-7.5.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9735317685ba6ec7e3754798c8871c2f49aa5e687cc794a0b1d284b2389d1bd5"}, - {file = "coverage-7.5.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d21918e9ef11edf36764b93101e2ae8cc82aa5efdc7c5a4e9c6c35a48496d601"}, - {file = "coverage-7.5.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c3e757949f268364b96ca894b4c342b41dc6f8f8b66c37878aacef5930db61be"}, - {file = "coverage-7.5.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:79afb6197e2f7f60c4824dd4b2d4c2ec5801ceb6ba9ce5d2c3080e5660d51a4f"}, - {file = "coverage-7.5.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d1d0d98d95dd18fe29dc66808e1accf59f037d5716f86a501fc0256455219668"}, - {file = "coverage-7.5.1-cp39-cp39-win32.whl", hash = "sha256:1cc0fe9b0b3a8364093c53b0b4c0c2dd4bb23acbec4c9240b5f284095ccf7981"}, - {file = "coverage-7.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:dde0070c40ea8bb3641e811c1cfbf18e265d024deff6de52c5950677a8fb1e0f"}, - {file = "coverage-7.5.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:6537e7c10cc47c595828b8a8be04c72144725c383c4702703ff4e42e44577312"}, - {file = "coverage-7.5.1.tar.gz", hash = "sha256:54de9ef3a9da981f7af93eafde4ede199e0846cd819eb27c88e2b712aae9708c"}, + {file = "coverage-7.6.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:85d9636f72e8991a1706b2b55b06c27545448baf9f6dbf51c4004609aacd7dcb"}, + {file = "coverage-7.6.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:608a7fd78c67bee8936378299a6cb9f5149bb80238c7a566fc3e6717a4e68710"}, + {file = "coverage-7.6.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96d636c77af18b5cb664ddf12dab9b15a0cfe9c0bde715da38698c8cea748bfa"}, + {file = "coverage-7.6.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d75cded8a3cff93da9edc31446872d2997e327921d8eed86641efafd350e1df1"}, + {file = "coverage-7.6.9-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7b15f589593110ae767ce997775d645b47e5cbbf54fd322f8ebea6277466cec"}, + {file = "coverage-7.6.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:44349150f6811b44b25574839b39ae35291f6496eb795b7366fef3bd3cf112d3"}, + {file = "coverage-7.6.9-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:d891c136b5b310d0e702e186d70cd16d1119ea8927347045124cb286b29297e5"}, + {file = "coverage-7.6.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:db1dab894cc139f67822a92910466531de5ea6034ddfd2b11c0d4c6257168073"}, + {file = "coverage-7.6.9-cp310-cp310-win32.whl", hash = "sha256:41ff7b0da5af71a51b53f501a3bac65fb0ec311ebed1632e58fc6107f03b9198"}, + {file = "coverage-7.6.9-cp310-cp310-win_amd64.whl", hash = "sha256:35371f8438028fdccfaf3570b31d98e8d9eda8bb1d6ab9473f5a390969e98717"}, + {file = "coverage-7.6.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:932fc826442132dde42ee52cf66d941f581c685a6313feebed358411238f60f9"}, + {file = "coverage-7.6.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:085161be5f3b30fd9b3e7b9a8c301f935c8313dcf928a07b116324abea2c1c2c"}, + {file = "coverage-7.6.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ccc660a77e1c2bf24ddbce969af9447a9474790160cfb23de6be4fa88e3951c7"}, + {file = "coverage-7.6.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c69e42c892c018cd3c8d90da61d845f50a8243062b19d228189b0224150018a9"}, + {file = "coverage-7.6.9-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0824a28ec542a0be22f60c6ac36d679e0e262e5353203bea81d44ee81fe9c6d4"}, + {file = "coverage-7.6.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4401ae5fc52ad8d26d2a5d8a7428b0f0c72431683f8e63e42e70606374c311a1"}, + {file = "coverage-7.6.9-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:98caba4476a6c8d59ec1eb00c7dd862ba9beca34085642d46ed503cc2d440d4b"}, + {file = "coverage-7.6.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ee5defd1733fd6ec08b168bd4f5387d5b322f45ca9e0e6c817ea6c4cd36313e3"}, + {file = "coverage-7.6.9-cp311-cp311-win32.whl", hash = "sha256:f2d1ec60d6d256bdf298cb86b78dd715980828f50c46701abc3b0a2b3f8a0dc0"}, + {file = "coverage-7.6.9-cp311-cp311-win_amd64.whl", hash = "sha256:0d59fd927b1f04de57a2ba0137166d31c1a6dd9e764ad4af552912d70428c92b"}, + {file = "coverage-7.6.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:99e266ae0b5d15f1ca8d278a668df6f51cc4b854513daab5cae695ed7b721cf8"}, + {file = "coverage-7.6.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9901d36492009a0a9b94b20e52ebfc8453bf49bb2b27bca2c9706f8b4f5a554a"}, + {file = "coverage-7.6.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abd3e72dd5b97e3af4246cdada7738ef0e608168de952b837b8dd7e90341f015"}, + {file = "coverage-7.6.9-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff74026a461eb0660366fb01c650c1d00f833a086b336bdad7ab00cc952072b3"}, + {file = "coverage-7.6.9-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65dad5a248823a4996724a88eb51d4b31587aa7aa428562dbe459c684e5787ae"}, + {file = "coverage-7.6.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:22be16571504c9ccea919fcedb459d5ab20d41172056206eb2994e2ff06118a4"}, + {file = "coverage-7.6.9-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f957943bc718b87144ecaee70762bc2bc3f1a7a53c7b861103546d3a403f0a6"}, + {file = "coverage-7.6.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ae1387db4aecb1f485fb70a6c0148c6cdaebb6038f1d40089b1fc84a5db556f"}, + {file = "coverage-7.6.9-cp312-cp312-win32.whl", hash = "sha256:1a330812d9cc7ac2182586f6d41b4d0fadf9be9049f350e0efb275c8ee8eb692"}, + {file = "coverage-7.6.9-cp312-cp312-win_amd64.whl", hash = "sha256:b12c6b18269ca471eedd41c1b6a1065b2f7827508edb9a7ed5555e9a56dcfc97"}, + {file = "coverage-7.6.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:899b8cd4781c400454f2f64f7776a5d87bbd7b3e7f7bda0cb18f857bb1334664"}, + {file = "coverage-7.6.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:61f70dc68bd36810972e55bbbe83674ea073dd1dcc121040a08cdf3416c5349c"}, + {file = "coverage-7.6.9-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a289d23d4c46f1a82d5db4abeb40b9b5be91731ee19a379d15790e53031c014"}, + {file = "coverage-7.6.9-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e216d8044a356fc0337c7a2a0536d6de07888d7bcda76febcb8adc50bdbbd00"}, + {file = "coverage-7.6.9-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c026eb44f744acaa2bda7493dad903aa5bf5fc4f2554293a798d5606710055d"}, + {file = "coverage-7.6.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e77363e8425325384f9d49272c54045bbed2f478e9dd698dbc65dbc37860eb0a"}, + {file = "coverage-7.6.9-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:777abfab476cf83b5177b84d7486497e034eb9eaea0d746ce0c1268c71652077"}, + {file = "coverage-7.6.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:447af20e25fdbe16f26e84eb714ba21d98868705cb138252d28bc400381f6ffb"}, + {file = "coverage-7.6.9-cp313-cp313-win32.whl", hash = "sha256:d872ec5aeb086cbea771c573600d47944eea2dcba8be5f3ee649bfe3cb8dc9ba"}, + {file = "coverage-7.6.9-cp313-cp313-win_amd64.whl", hash = "sha256:fd1213c86e48dfdc5a0cc676551db467495a95a662d2396ecd58e719191446e1"}, + {file = "coverage-7.6.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:ba9e7484d286cd5a43744e5f47b0b3fb457865baf07bafc6bee91896364e1419"}, + {file = "coverage-7.6.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e5ea1cf0872ee455c03e5674b5bca5e3e68e159379c1af0903e89f5eba9ccc3a"}, + {file = "coverage-7.6.9-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d10e07aa2b91835d6abec555ec8b2733347956991901eea6ffac295f83a30e4"}, + {file = "coverage-7.6.9-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:13a9e2d3ee855db3dd6ea1ba5203316a1b1fd8eaeffc37c5b54987e61e4194ae"}, + {file = "coverage-7.6.9-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c38bf15a40ccf5619fa2fe8f26106c7e8e080d7760aeccb3722664c8656b030"}, + {file = "coverage-7.6.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d5275455b3e4627c8e7154feaf7ee0743c2e7af82f6e3b561967b1cca755a0be"}, + {file = "coverage-7.6.9-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8f8770dfc6e2c6a2d4569f411015c8d751c980d17a14b0530da2d7f27ffdd88e"}, + {file = "coverage-7.6.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8d2dfa71665a29b153a9681edb1c8d9c1ea50dfc2375fb4dac99ea7e21a0bcd9"}, + {file = "coverage-7.6.9-cp313-cp313t-win32.whl", hash = "sha256:5e6b86b5847a016d0fbd31ffe1001b63355ed309651851295315031ea7eb5a9b"}, + {file = "coverage-7.6.9-cp313-cp313t-win_amd64.whl", hash = "sha256:97ddc94d46088304772d21b060041c97fc16bdda13c6c7f9d8fcd8d5ae0d8611"}, + {file = "coverage-7.6.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:adb697c0bd35100dc690de83154627fbab1f4f3c0386df266dded865fc50a902"}, + {file = "coverage-7.6.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:be57b6d56e49c2739cdf776839a92330e933dd5e5d929966fbbd380c77f060be"}, + {file = "coverage-7.6.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1592791f8204ae9166de22ba7e6705fa4ebd02936c09436a1bb85aabca3e599"}, + {file = "coverage-7.6.9-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e12ae8cc979cf83d258acb5e1f1cf2f3f83524d1564a49d20b8bec14b637f08"}, + {file = "coverage-7.6.9-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb5555cff66c4d3d6213a296b360f9e1a8e323e74e0426b6c10ed7f4d021e464"}, + {file = "coverage-7.6.9-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:b9389a429e0e5142e69d5bf4a435dd688c14478a19bb901735cdf75e57b13845"}, + {file = "coverage-7.6.9-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:592ac539812e9b46046620341498caf09ca21023c41c893e1eb9dbda00a70cbf"}, + {file = "coverage-7.6.9-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a27801adef24cc30871da98a105f77995e13a25a505a0161911f6aafbd66e678"}, + {file = "coverage-7.6.9-cp39-cp39-win32.whl", hash = "sha256:8e3c3e38930cfb729cb8137d7f055e5a473ddaf1217966aa6238c88bd9fd50e6"}, + {file = "coverage-7.6.9-cp39-cp39-win_amd64.whl", hash = "sha256:e28bf44afa2b187cc9f41749138a64435bf340adfcacb5b2290c070ce99839d4"}, + {file = "coverage-7.6.9-pp39.pp310-none-any.whl", hash = "sha256:f3ca78518bc6bc92828cd11867b121891d75cae4ea9e908d72030609b996db1b"}, + {file = "coverage-7.6.9.tar.gz", hash = "sha256:4a8d8977b0c6ef5aeadcb644da9e69ae0dcfe66ec7f368c89c72e058bd71164d"}, ] [package.extras] @@ -387,51 +501,51 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "43.0.1" +version = "44.0.0" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false -python-versions = ">=3.7" -files = [ - {file = "cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a"}, - {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042"}, - {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494"}, - {file = "cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2"}, - {file = "cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d"}, - {file = "cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1"}, - {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa"}, - {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4"}, - {file = "cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47"}, - {file = "cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2"}, - {file = "cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d"}, +python-versions = "!=3.9.0,!=3.9.1,>=3.7" +files = [ + {file = "cryptography-44.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123"}, + {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092"}, + {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f"}, + {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb"}, + {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b"}, + {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543"}, + {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e"}, + {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e"}, + {file = "cryptography-44.0.0-cp37-abi3-win32.whl", hash = "sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053"}, + {file = "cryptography-44.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:abc998e0c0eee3c8a1904221d3f67dcfa76422b23620173e28c11d3e626c21bd"}, + {file = "cryptography-44.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:660cb7312a08bc38be15b696462fa7cc7cd85c3ed9c576e81f4dc4d8b2b31591"}, + {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7"}, + {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc"}, + {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289"}, + {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7"}, + {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c"}, + {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64"}, + {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285"}, + {file = "cryptography-44.0.0-cp39-abi3-win32.whl", hash = "sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417"}, + {file = "cryptography-44.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:708ee5f1bafe76d041b53a4f95eb28cdeb8d18da17e597d46d7833ee59b97ede"}, + {file = "cryptography-44.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:37d76e6863da3774cd9db5b409a9ecfd2c71c981c38788d3fcfaf177f447b731"}, + {file = "cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:f677e1268c4e23420c3acade68fac427fffcb8d19d7df95ed7ad17cdef8404f4"}, + {file = "cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f5e7cb1e5e56ca0933b4873c0220a78b773b24d40d186b6738080b73d3d0a756"}, + {file = "cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:8b3e6eae66cf54701ee7d9c83c30ac0a1e3fa17be486033000f2a73a12ab507c"}, + {file = "cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:be4ce505894d15d5c5037167ffb7f0ae90b7be6f2a98f9a5c3442395501c32fa"}, + {file = "cryptography-44.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:62901fb618f74d7d81bf408c8719e9ec14d863086efe4185afd07c352aee1d2c"}, + {file = "cryptography-44.0.0.tar.gz", hash = "sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02"}, ] [package.dependencies] cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} [package.extras] -docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] -docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"] -nox = ["nox"] -pep8test = ["check-sdist", "click", "mypy", "ruff"] -sdist = ["build"] +docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=3.0.0)"] +docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"] +nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2)"] +pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] +sdist = ["build (>=1.0.0)"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi", "cryptography-vectors (==43.0.1)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test = ["certifi (>=2024)", "cryptography-vectors (==44.0.0)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] test-randomorder = ["pytest-randomly"] [[package]] @@ -445,6 +559,37 @@ files = [ {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, ] +[[package]] +name = "deprecated" +version = "1.2.15" +description = "Python @deprecated decorator to deprecate old python classes, functions or methods." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +files = [ + {file = "Deprecated-1.2.15-py2.py3-none-any.whl", hash = "sha256:353bc4a8ac4bfc96800ddab349d89c25dec1079f65fd53acdcc1e0b975b21320"}, + {file = "deprecated-1.2.15.tar.gz", hash = "sha256:683e561a90de76239796e6b6feac66b99030d2dd3fcf61ef996330f14bbb9b0d"}, +] + +[package.dependencies] +wrapt = ">=1.10,<2" + +[package.extras] +dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "jinja2 (>=3.0.3,<3.1.0)", "setuptools", "sphinx (<2)", "tox"] + +[[package]] +name = "deprecation" +version = "2.1.0" +description = "A library to handle automated deprecations" +optional = false +python-versions = "*" +files = [ + {file = "deprecation-2.1.0-py2.py3-none-any.whl", hash = "sha256:a10811591210e1fb0e768a8c25517cabeabcba6f0bf96564f8ff45189f90b14a"}, + {file = "deprecation-2.1.0.tar.gz", hash = "sha256:72b3bde64e5d778694b0cf68178aed03d15e15477116add3fb773e581f9518ff"}, +] + +[package.dependencies] +packaging = "*" + [[package]] name = "docutils" version = "0.21.2" @@ -477,15 +622,19 @@ lua = ["lupa (>=1.14,<2.0)"] [[package]] name = "fastly" -version = "5.2.0" +version = "6.0.0" description = "A Python Fastly API client library" optional = false python-versions = ">=3.6" files = [ - {file = "fastly-5.2.0-py3-none-any.whl", hash = "sha256:cff951f3e0bc875243843ff2460ef0701c3735bcf36f8db8c76ca6f2c2c6f527"}, - {file = "fastly-5.2.0.tar.gz", hash = "sha256:acfce6386291ab0fb02b989a27339e1f035e64dafc66ae889c36bb0eb4533615"}, + {file = "fastly-6.0.0-py3-none-any.whl", hash = "sha256:6aaf15bf35c35c94b32f6a6ff5c6e65afd1d4d5162e08cc69fb3e98abce29598"}, + {file = "fastly-6.0.0.tar.gz", hash = "sha256:d09658b48230f741cad66d50aa8ede835c13442402e1752cb252ea32e8b81dd5"}, ] +[package.dependencies] +python-dateutil = "*" +urllib3 = ">=1.25.3" + [[package]] name = "fire" version = "0.5.0" @@ -538,15 +687,52 @@ Boto3 = ">=1.1.1" Flask = "*" six = "*" +[[package]] +name = "functions-framework" +version = "3.8.2" +description = "An open source FaaS (Function as a service) framework for writing portable Python functions -- brought to you by the Google Cloud Functions team." +optional = false +python-versions = "<4,>=3.5" +files = [ + {file = "functions_framework-3.8.2-py3-none-any.whl", hash = "sha256:ecbe8e4566efca9ed1718f210ac92d47fc47ec3a448d2bca3b4bb5888bceca08"}, + {file = "functions_framework-3.8.2.tar.gz", hash = "sha256:109bcdca01244067052a605536b44d042903b3805d093cd32e343ba5affffc90"}, +] + +[package.dependencies] +click = ">=7.0,<9.0" +cloudevents = ">=1.2.0,<2.0.0" +flask = ">=1.0,<4.0" +gunicorn = {version = ">=22.0.0", markers = "platform_system != \"Windows\""} +watchdog = ">=1.0.0" +Werkzeug = ">=0.14,<4.0.0" + +[[package]] +name = "geoalchemy2" +version = "0.15.2" +description = "Using SQLAlchemy with Spatial Databases" +optional = false +python-versions = ">=3.7" +files = [ + {file = "GeoAlchemy2-0.15.2-py3-none-any.whl", hash = "sha256:546455dc39f5bcdfc5b871e57d3f7546c8a6f798eb364c474200f488ace6fd32"}, + {file = "geoalchemy2-0.15.2.tar.gz", hash = "sha256:3af0272db927373e74ee3b064cdc9464ba08defdb945c51745db1b841482f5dc"}, +] + +[package.dependencies] +packaging = "*" +SQLAlchemy = ">=1.4" + +[package.extras] +shapely = ["Shapely (>=1.7)"] + [[package]] name = "google-api-core" -version = "2.19.0" +version = "2.24.0" description = "Google API client core library" optional = false python-versions = ">=3.7" files = [ - {file = "google-api-core-2.19.0.tar.gz", hash = "sha256:cf1b7c2694047886d2af1128a03ae99e391108a08804f87cfd35970e49c9cd10"}, - {file = "google_api_core-2.19.0-py3-none-any.whl", hash = "sha256:8661eec4078c35428fd3f69a2c7ee29e342896b70f01d1a1cbcb334372dd6251"}, + {file = "google_api_core-2.24.0-py3-none-any.whl", hash = "sha256:10d82ac0fca69c82a25b3efdeefccf6f28e02ebb97925a8cce8edbfe379929d9"}, + {file = "google_api_core-2.24.0.tar.gz", hash = "sha256:e255640547a597a4da010876d333208ddac417d60add22b6851a0c66a831fcaf"}, ] [package.dependencies] @@ -554,24 +740,28 @@ google-auth = ">=2.14.1,<3.0.dev0" googleapis-common-protos = ">=1.56.2,<2.0.dev0" grpcio = {version = ">=1.49.1,<2.0dev", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""} grpcio-status = {version = ">=1.49.1,<2.0.dev0", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""} -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0" +proto-plus = [ + {version = ">=1.25.0,<2.0.0dev", markers = "python_version >= \"3.13\""}, + {version = ">=1.22.3,<2.0.0dev", markers = "python_version < \"3.13\""}, +] +protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" requests = ">=2.18.0,<3.0.0.dev0" [package.extras] +async-rest = ["google-auth[aiohttp] (>=2.35.0,<3.0.dev0)"] grpc = ["grpcio (>=1.33.2,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "grpcio-status (>=1.33.2,<2.0.dev0)", "grpcio-status (>=1.49.1,<2.0.dev0)"] grpcgcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] [[package]] name = "google-auth" -version = "2.29.0" +version = "2.37.0" description = "Google Authentication Library" optional = false python-versions = ">=3.7" files = [ - {file = "google-auth-2.29.0.tar.gz", hash = "sha256:672dff332d073227550ffc7457868ac4218d6c500b155fe6cc17d2b13602c360"}, - {file = "google_auth-2.29.0-py2.py3-none-any.whl", hash = "sha256:d452ad095688cd52bae0ad6fafe027f6a6d6f560e810fec20914e17a09526415"}, + {file = "google_auth-2.37.0-py2.py3-none-any.whl", hash = "sha256:42664f18290a6be591be5329a96fe30184be1a1badb7292a7f686a9659de9ca0"}, + {file = "google_auth-2.37.0.tar.gz", hash = "sha256:0054623abf1f9c83492c63d3f47e77f0a544caa3d40b2d98e099a611c2dd5d00"}, ] [package.dependencies] @@ -581,42 +771,77 @@ rsa = ">=3.1.4,<5" [package.extras] aiohttp = ["aiohttp (>=3.6.2,<4.0.0.dev0)", "requests (>=2.20.0,<3.0.0.dev0)"] -enterprise-cert = ["cryptography (==36.0.2)", "pyopenssl (==22.0.0)"] +enterprise-cert = ["cryptography", "pyopenssl"] +pyjwt = ["cryptography (>=38.0.3)", "pyjwt (>=2.0)"] pyopenssl = ["cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] reauth = ["pyu2f (>=0.1.5)"] requests = ["requests (>=2.20.0,<3.0.0.dev0)"] [[package]] name = "google-cloud-appengine-logging" -version = "1.4.3" +version = "1.5.0" description = "Google Cloud Appengine Logging API client library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-appengine-logging-1.4.3.tar.gz", hash = "sha256:fb504e6199fe8de85baa9d31cecf6776877851fe58867de603317ec7cc739987"}, - {file = "google_cloud_appengine_logging-1.4.3-py2.py3-none-any.whl", hash = "sha256:8e30af51d853f219caf29e8b8b342b9ce8214b29f334dafae38d39aaaff7d372"}, + {file = "google_cloud_appengine_logging-1.5.0-py2.py3-none-any.whl", hash = "sha256:81e36606e13c377c4898c918542888abb7a6896837ac5f559011c7729fc63d8a"}, + {file = "google_cloud_appengine_logging-1.5.0.tar.gz", hash = "sha256:39a2df694d97981ed00ef5df541f7cfcca920a92496707557f2b07bb7ba9d67a"}, ] [package.dependencies] google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" +proto-plus = [ + {version = ">=1.25.0,<2.0.0dev", markers = "python_version >= \"3.13\""}, + {version = ">=1.22.3,<2.0.0dev", markers = "python_version < \"3.13\""}, +] +protobuf = ">=3.20.2,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0dev" [[package]] name = "google-cloud-audit-log" -version = "0.2.5" +version = "0.3.0" description = "Google Cloud Audit Protos" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-audit-log-0.2.5.tar.gz", hash = "sha256:86e2faba3383adc8fd04a5bd7fd4f960b3e4aedaa7ed950f2f891ce16902eb6b"}, - {file = "google_cloud_audit_log-0.2.5-py2.py3-none-any.whl", hash = "sha256:18b94d4579002a450b7902cd2e8b8fdcb1ea2dd4df3b41f8f82be6d9f7fcd746"}, + {file = "google_cloud_audit_log-0.3.0-py2.py3-none-any.whl", hash = "sha256:8340793120a1d5aa143605def8704ecdcead15106f754ef1381ae3bab533722f"}, + {file = "google_cloud_audit_log-0.3.0.tar.gz", hash = "sha256:901428b257020d8c1d1133e0fa004164a555e5a395c7ca3cdbb8486513df3a65"}, ] [package.dependencies] googleapis-common-protos = ">=1.56.2,<2.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" +protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0dev" + +[[package]] +name = "google-cloud-bigquery" +version = "3.27.0" +description = "Google BigQuery API client library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "google_cloud_bigquery-3.27.0-py2.py3-none-any.whl", hash = "sha256:b53b0431e5ba362976a4cd8acce72194b4116cdf8115030c7b339b884603fcc3"}, + {file = "google_cloud_bigquery-3.27.0.tar.gz", hash = "sha256:379c524054d7b090fa56d0c22662cc6e6458a6229b6754c0e7177e3a73421d2c"}, +] + +[package.dependencies] +google-api-core = {version = ">=2.11.1,<3.0.0dev", extras = ["grpc"]} +google-auth = ">=2.14.1,<3.0.0dev" +google-cloud-core = ">=2.4.1,<3.0.0dev" +google-resumable-media = ">=2.0.0,<3.0dev" +packaging = ">=20.0.0" +python-dateutil = ">=2.7.3,<3.0dev" +requests = ">=2.21.0,<3.0.0dev" + +[package.extras] +all = ["Shapely (>=1.8.4,<3.0.0dev)", "bigquery-magics (>=0.1.0)", "db-dtypes (>=0.3.0,<2.0.0dev)", "geopandas (>=0.9.0,<1.0dev)", "google-cloud-bigquery-storage (>=2.6.0,<3.0.0dev)", "grpcio (>=1.47.0,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "importlib-metadata (>=1.0.0)", "ipykernel (>=6.0.0)", "ipywidgets (>=7.7.0)", "opentelemetry-api (>=1.1.0)", "opentelemetry-instrumentation (>=0.20b0)", "opentelemetry-sdk (>=1.1.0)", "pandas (>=1.1.0)", "proto-plus (>=1.22.3,<2.0.0dev)", "protobuf (>=3.20.2,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<6.0.0dev)", "pyarrow (>=3.0.0)", "tqdm (>=4.7.4,<5.0.0dev)"] +bigquery-v2 = ["proto-plus (>=1.22.3,<2.0.0dev)", "protobuf (>=3.20.2,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<6.0.0dev)"] +bqstorage = ["google-cloud-bigquery-storage (>=2.6.0,<3.0.0dev)", "grpcio (>=1.47.0,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "pyarrow (>=3.0.0)"] +geopandas = ["Shapely (>=1.8.4,<3.0.0dev)", "geopandas (>=0.9.0,<1.0dev)"] +ipython = ["bigquery-magics (>=0.1.0)"] +ipywidgets = ["ipykernel (>=6.0.0)", "ipywidgets (>=7.7.0)"] +opentelemetry = ["opentelemetry-api (>=1.1.0)", "opentelemetry-instrumentation (>=0.20b0)", "opentelemetry-sdk (>=1.1.0)"] +pandas = ["db-dtypes (>=0.3.0,<2.0.0dev)", "importlib-metadata (>=1.0.0)", "pandas (>=1.1.0)", "pyarrow (>=3.0.0)"] +tqdm = ["tqdm (>=4.7.4,<5.0.0dev)"] [[package]] name = "google-cloud-core" @@ -638,54 +863,58 @@ grpc = ["grpcio (>=1.38.0,<2.0dev)", "grpcio-status (>=1.38.0,<2.0.dev0)"] [[package]] name = "google-cloud-logging" -version = "3.10.0" +version = "3.11.3" description = "Stackdriver Logging API client library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-logging-3.10.0.tar.gz", hash = "sha256:d93d347351240ddb14cfe201987a2d32cf9d7f478b8b2fabed3015b425b3274f"}, - {file = "google_cloud_logging-3.10.0-py2.py3-none-any.whl", hash = "sha256:132192beb45731130a2ffbcd4b2b5cbd87370e7dcfa7397ae4002154f542bd20"}, + {file = "google_cloud_logging-3.11.3-py2.py3-none-any.whl", hash = "sha256:b8ec23f2998f76a58f8492db26a0f4151dd500425c3f08448586b85972f3c494"}, + {file = "google_cloud_logging-3.11.3.tar.gz", hash = "sha256:0a73cd94118875387d4535371d9e9426861edef8e44fba1261e86782d5b8d54f"}, ] [package.dependencies] google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -google-cloud-appengine-logging = ">=0.1.0,<2.0.0dev" -google-cloud-audit-log = ">=0.1.0,<1.0.0dev" +google-cloud-appengine-logging = ">=0.1.3,<2.0.0dev" +google-cloud-audit-log = ">=0.2.4,<1.0.0dev" google-cloud-core = ">=2.0.0,<3.0.0dev" grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" +opentelemetry-api = ">=1.9.0" proto-plus = {version = ">=1.22.2,<2.0.0dev", markers = "python_version >= \"3.11\""} -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" +protobuf = ">=3.20.2,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0dev" [[package]] name = "google-cloud-monitoring" -version = "2.21.0" +version = "2.23.1" description = "Google Cloud Monitoring API client library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-monitoring-2.21.0.tar.gz", hash = "sha256:e7b1c8758fc3563ffb9a347bc5172e2782f44c121bc80fc15283e289cff675bf"}, - {file = "google_cloud_monitoring-2.21.0-py2.py3-none-any.whl", hash = "sha256:1b174e656a3bfd767c269bf2ba023b40e0a80a85e36ed0b75bb272be65e76904"}, + {file = "google_cloud_monitoring-2.23.1-py2.py3-none-any.whl", hash = "sha256:4ae3fdf1665bccf6b554a35cba541f8d64655b0b41552382e0d72041d129d900"}, + {file = "google_cloud_monitoring-2.23.1.tar.gz", hash = "sha256:239aab05adc82c068a6cc4e548688ad5ef48eead630c9fd1d4afd090e09e26f0"}, ] [package.dependencies] google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" +proto-plus = [ + {version = ">=1.25.0,<2.0.0dev", markers = "python_version >= \"3.13\""}, + {version = ">=1.22.3,<2.0.0dev", markers = "python_version < \"3.13\""}, +] +protobuf = ">=3.20.2,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0dev" [package.extras] pandas = ["pandas (>=0.23.2)"] [[package]] name = "google-cloud-pubsub" -version = "2.21.1" +version = "2.27.1" description = "Google Cloud Pub/Sub API client library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-pubsub-2.21.1.tar.gz", hash = "sha256:31fcf07444b7f813a616c4b650e1fbf1dc998a088fe0059a76164855ac17f05c"}, - {file = "google_cloud_pubsub-2.21.1-py2.py3-none-any.whl", hash = "sha256:55a3602ec45bc09626604d712032288a8ee3566145cb83523cff908938f69a4b"}, + {file = "google_cloud_pubsub-2.27.1-py2.py3-none-any.whl", hash = "sha256:3ca8980c198a847ee464845ab60f05478d4819cf693c9950ee89da96f0b80a41"}, + {file = "google_cloud_pubsub-2.27.1.tar.gz", hash = "sha256:7119dbc5af4b915ecdfa1289919f791a432927eaaa7bbfbeb740e6d7020c181e"}, ] [package.dependencies] @@ -694,21 +923,26 @@ google-auth = ">=2.14.1,<3.0.0dev" grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" grpcio = ">=1.51.3,<2.0dev" grpcio-status = ">=1.33.2" -proto-plus = {version = ">=1.22.2,<2.0.0dev", markers = "python_version >= \"3.11\""} -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" +opentelemetry-api = {version = ">=1.27.0", markers = "python_version >= \"3.8\""} +opentelemetry-sdk = {version = ">=1.27.0", markers = "python_version >= \"3.8\""} +proto-plus = [ + {version = ">=1.25.0,<2.0.0dev", markers = "python_version >= \"3.13\""}, + {version = ">=1.22.2,<2.0.0dev", markers = "python_version >= \"3.11\" and python_version < \"3.13\""}, +] +protobuf = ">=3.20.2,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0dev" [package.extras] libcst = ["libcst (>=0.3.10)"] [[package]] name = "google-cloud-storage" -version = "2.16.0" +version = "2.19.0" description = "Google Cloud Storage API client library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-storage-2.16.0.tar.gz", hash = "sha256:dda485fa503710a828d01246bd16ce9db0823dc51bbca742ce96a6817d58669f"}, - {file = "google_cloud_storage-2.16.0-py2.py3-none-any.whl", hash = "sha256:91a06b96fb79cf9cdfb4e759f178ce11ea885c79938f89590344d079305f5852"}, + {file = "google_cloud_storage-2.19.0-py2.py3-none-any.whl", hash = "sha256:aeb971b5c29cf8ab98445082cbfe7b161a1f48ed275822f59ed3f1524ea54fba"}, + {file = "google_cloud_storage-2.19.0.tar.gz", hash = "sha256:cd05e9e7191ba6cb68934d8eb76054d9be4562aa89dbc4236feee4d7d51342b2"}, ] [package.dependencies] @@ -716,87 +950,47 @@ google-api-core = ">=2.15.0,<3.0.0dev" google-auth = ">=2.26.1,<3.0dev" google-cloud-core = ">=2.3.0,<3.0dev" google-crc32c = ">=1.0,<2.0dev" -google-resumable-media = ">=2.6.0" +google-resumable-media = ">=2.7.2" requests = ">=2.18.0,<3.0.0dev" [package.extras] -protobuf = ["protobuf (<5.0.0dev)"] +protobuf = ["protobuf (<6.0.0dev)"] +tracing = ["opentelemetry-api (>=1.1.0)"] [[package]] name = "google-crc32c" -version = "1.5.0" +version = "1.6.0" description = "A python wrapper of the C library 'Google CRC32C'" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "google-crc32c-1.5.0.tar.gz", hash = "sha256:89284716bc6a5a415d4eaa11b1726d2d60a0cd12aadf5439828353662ede9dd7"}, - {file = "google_crc32c-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:596d1f98fc70232fcb6590c439f43b350cb762fb5d61ce7b0e9db4539654cc13"}, - {file = "google_crc32c-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:be82c3c8cfb15b30f36768797a640e800513793d6ae1724aaaafe5bf86f8f346"}, - {file = "google_crc32c-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:461665ff58895f508e2866824a47bdee72497b091c730071f2b7575d5762ab65"}, - {file = "google_crc32c-1.5.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2096eddb4e7c7bdae4bd69ad364e55e07b8316653234a56552d9c988bd2d61b"}, - {file = "google_crc32c-1.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:116a7c3c616dd14a3de8c64a965828b197e5f2d121fedd2f8c5585c547e87b02"}, - {file = "google_crc32c-1.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5829b792bf5822fd0a6f6eb34c5f81dd074f01d570ed7f36aa101d6fc7a0a6e4"}, - {file = "google_crc32c-1.5.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:64e52e2b3970bd891309c113b54cf0e4384762c934d5ae56e283f9a0afcd953e"}, - {file = "google_crc32c-1.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:02ebb8bf46c13e36998aeaad1de9b48f4caf545e91d14041270d9dca767b780c"}, - {file = "google_crc32c-1.5.0-cp310-cp310-win32.whl", hash = "sha256:2e920d506ec85eb4ba50cd4228c2bec05642894d4c73c59b3a2fe20346bd00ee"}, - {file = "google_crc32c-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:07eb3c611ce363c51a933bf6bd7f8e3878a51d124acfc89452a75120bc436289"}, - {file = "google_crc32c-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cae0274952c079886567f3f4f685bcaf5708f0a23a5f5216fdab71f81a6c0273"}, - {file = "google_crc32c-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1034d91442ead5a95b5aaef90dbfaca8633b0247d1e41621d1e9f9db88c36298"}, - {file = "google_crc32c-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c42c70cd1d362284289c6273adda4c6af8039a8ae12dc451dcd61cdabb8ab57"}, - {file = "google_crc32c-1.5.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8485b340a6a9e76c62a7dce3c98e5f102c9219f4cfbf896a00cf48caf078d438"}, - {file = "google_crc32c-1.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77e2fd3057c9d78e225fa0a2160f96b64a824de17840351b26825b0848022906"}, - {file = "google_crc32c-1.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f583edb943cf2e09c60441b910d6a20b4d9d626c75a36c8fcac01a6c96c01183"}, - {file = "google_crc32c-1.5.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:a1fd716e7a01f8e717490fbe2e431d2905ab8aa598b9b12f8d10abebb36b04dd"}, - {file = "google_crc32c-1.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:72218785ce41b9cfd2fc1d6a017dc1ff7acfc4c17d01053265c41a2c0cc39b8c"}, - {file = "google_crc32c-1.5.0-cp311-cp311-win32.whl", hash = "sha256:66741ef4ee08ea0b2cc3c86916ab66b6aef03768525627fd6a1b34968b4e3709"}, - {file = "google_crc32c-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:ba1eb1843304b1e5537e1fca632fa894d6f6deca8d6389636ee5b4797affb968"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:98cb4d057f285bd80d8778ebc4fde6b4d509ac3f331758fb1528b733215443ae"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd8536e902db7e365f49e7d9029283403974ccf29b13fc7028b97e2295b33556"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19e0a019d2c4dcc5e598cd4a4bc7b008546b0358bd322537c74ad47a5386884f"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02c65b9817512edc6a4ae7c7e987fea799d2e0ee40c53ec573a692bee24de876"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6ac08d24c1f16bd2bf5eca8eaf8304812f44af5cfe5062006ec676e7e1d50afc"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3359fc442a743e870f4588fcf5dcbc1bf929df1fad8fb9905cd94e5edb02e84c"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1e986b206dae4476f41bcec1faa057851f3889503a70e1bdb2378d406223994a"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:de06adc872bcd8c2a4e0dc51250e9e65ef2ca91be023b9d13ebd67c2ba552e1e"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-win32.whl", hash = "sha256:d3515f198eaa2f0ed49f8819d5732d70698c3fa37384146079b3799b97667a94"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:67b741654b851abafb7bc625b6d1cdd520a379074e64b6a128e3b688c3c04740"}, - {file = "google_crc32c-1.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c02ec1c5856179f171e032a31d6f8bf84e5a75c45c33b2e20a3de353b266ebd8"}, - {file = "google_crc32c-1.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:edfedb64740750e1a3b16152620220f51d58ff1b4abceb339ca92e934775c27a"}, - {file = "google_crc32c-1.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84e6e8cd997930fc66d5bb4fde61e2b62ba19d62b7abd7a69920406f9ecca946"}, - {file = "google_crc32c-1.5.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:024894d9d3cfbc5943f8f230e23950cd4906b2fe004c72e29b209420a1e6b05a"}, - {file = "google_crc32c-1.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:998679bf62b7fb599d2878aa3ed06b9ce688b8974893e7223c60db155f26bd8d"}, - {file = "google_crc32c-1.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:83c681c526a3439b5cf94f7420471705bbf96262f49a6fe546a6db5f687a3d4a"}, - {file = "google_crc32c-1.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4c6fdd4fccbec90cc8a01fc00773fcd5fa28db683c116ee3cb35cd5da9ef6c37"}, - {file = "google_crc32c-1.5.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5ae44e10a8e3407dbe138984f21e536583f2bba1be9491239f942c2464ac0894"}, - {file = "google_crc32c-1.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:37933ec6e693e51a5b07505bd05de57eee12f3e8c32b07da7e73669398e6630a"}, - {file = "google_crc32c-1.5.0-cp38-cp38-win32.whl", hash = "sha256:fe70e325aa68fa4b5edf7d1a4b6f691eb04bbccac0ace68e34820d283b5f80d4"}, - {file = "google_crc32c-1.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:74dea7751d98034887dbd821b7aae3e1d36eda111d6ca36c206c44478035709c"}, - {file = "google_crc32c-1.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c6c777a480337ac14f38564ac88ae82d4cd238bf293f0a22295b66eb89ffced7"}, - {file = "google_crc32c-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:759ce4851a4bb15ecabae28f4d2e18983c244eddd767f560165563bf9aefbc8d"}, - {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f13cae8cc389a440def0c8c52057f37359014ccbc9dc1f0827936bcd367c6100"}, - {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e560628513ed34759456a416bf86b54b2476c59144a9138165c9a1575801d0d9"}, - {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1674e4307fa3024fc897ca774e9c7562c957af85df55efe2988ed9056dc4e57"}, - {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:278d2ed7c16cfc075c91378c4f47924c0625f5fc84b2d50d921b18b7975bd210"}, - {file = "google_crc32c-1.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d5280312b9af0976231f9e317c20e4a61cd2f9629b7bfea6a693d1878a264ebd"}, - {file = "google_crc32c-1.5.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8b87e1a59c38f275c0e3676fc2ab6d59eccecfd460be267ac360cc31f7bcde96"}, - {file = "google_crc32c-1.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7c074fece789b5034b9b1404a1f8208fc2d4c6ce9decdd16e8220c5a793e6f61"}, - {file = "google_crc32c-1.5.0-cp39-cp39-win32.whl", hash = "sha256:7f57f14606cd1dd0f0de396e1e53824c371e9544a822648cd76c034d209b559c"}, - {file = "google_crc32c-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:a2355cba1f4ad8b6988a4ca3feed5bff33f6af2d7f134852cf279c2aebfde541"}, - {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f314013e7dcd5cf45ab1945d92e713eec788166262ae8deb2cfacd53def27325"}, - {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b747a674c20a67343cb61d43fdd9207ce5da6a99f629c6e2541aa0e89215bcd"}, - {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8f24ed114432de109aa9fd317278518a5af2d31ac2ea6b952b2f7782b43da091"}, - {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8667b48e7a7ef66afba2c81e1094ef526388d35b873966d8a9a447974ed9178"}, - {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:1c7abdac90433b09bad6c43a43af253e688c9cfc1c86d332aed13f9a7c7f65e2"}, - {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6f998db4e71b645350b9ac28a2167e6632c239963ca9da411523bb439c5c514d"}, - {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c99616c853bb585301df6de07ca2cadad344fd1ada6d62bb30aec05219c45d2"}, - {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ad40e31093a4af319dadf503b2467ccdc8f67c72e4bcba97f8c10cb078207b5"}, - {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd67cf24a553339d5062eff51013780a00d6f97a39ca062781d06b3a73b15462"}, - {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:398af5e3ba9cf768787eef45c803ff9614cc3e22a5b2f7d7ae116df8b11e3314"}, - {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b1f8133c9a275df5613a451e73f36c2aea4fe13c5c8997e22cf355ebd7bd0728"}, - {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ba053c5f50430a3fcfd36f75aff9caeba0440b2d076afdb79a318d6ca245f88"}, - {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:272d3892a1e1a2dbc39cc5cde96834c236d5327e2122d3aaa19f6614531bb6eb"}, - {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:635f5d4dd18758a1fbd1049a8e8d2fee4ffed124462d837d1a02a0e009c3ab31"}, - {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c672d99a345849301784604bfeaeba4db0c7aae50b95be04dd651fd2a7310b93"}, + {file = "google_crc32c-1.6.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:5bcc90b34df28a4b38653c36bb5ada35671ad105c99cfe915fb5bed7ad6924aa"}, + {file = "google_crc32c-1.6.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:d9e9913f7bd69e093b81da4535ce27af842e7bf371cde42d1ae9e9bd382dc0e9"}, + {file = "google_crc32c-1.6.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a184243544811e4a50d345838a883733461e67578959ac59964e43cca2c791e7"}, + {file = "google_crc32c-1.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:236c87a46cdf06384f614e9092b82c05f81bd34b80248021f729396a78e55d7e"}, + {file = "google_crc32c-1.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebab974b1687509e5c973b5c4b8b146683e101e102e17a86bd196ecaa4d099fc"}, + {file = "google_crc32c-1.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:50cf2a96da226dcbff8671233ecf37bf6e95de98b2a2ebadbfdf455e6d05df42"}, + {file = "google_crc32c-1.6.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:f7a1fc29803712f80879b0806cb83ab24ce62fc8daf0569f2204a0cfd7f68ed4"}, + {file = "google_crc32c-1.6.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:40b05ab32a5067525670880eb5d169529089a26fe35dce8891127aeddc1950e8"}, + {file = "google_crc32c-1.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9e4b426c3702f3cd23b933436487eb34e01e00327fac20c9aebb68ccf34117d"}, + {file = "google_crc32c-1.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51c4f54dd8c6dfeb58d1df5e4f7f97df8abf17a36626a217f169893d1d7f3e9f"}, + {file = "google_crc32c-1.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:bb8b3c75bd157010459b15222c3fd30577042a7060e29d42dabce449c087f2b3"}, + {file = "google_crc32c-1.6.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:ed767bf4ba90104c1216b68111613f0d5926fb3780660ea1198fc469af410e9d"}, + {file = "google_crc32c-1.6.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:62f6d4a29fea082ac4a3c9be5e415218255cf11684ac6ef5488eea0c9132689b"}, + {file = "google_crc32c-1.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c87d98c7c4a69066fd31701c4e10d178a648c2cac3452e62c6b24dc51f9fcc00"}, + {file = "google_crc32c-1.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd5e7d2445d1a958c266bfa5d04c39932dc54093fa391736dbfdb0f1929c1fb3"}, + {file = "google_crc32c-1.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:7aec8e88a3583515f9e0957fe4f5f6d8d4997e36d0f61624e70469771584c760"}, + {file = "google_crc32c-1.6.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:e2806553238cd076f0a55bddab37a532b53580e699ed8e5606d0de1f856b5205"}, + {file = "google_crc32c-1.6.0-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:bb0966e1c50d0ef5bc743312cc730b533491d60585a9a08f897274e57c3f70e0"}, + {file = "google_crc32c-1.6.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:386122eeaaa76951a8196310432c5b0ef3b53590ef4c317ec7588ec554fec5d2"}, + {file = "google_crc32c-1.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2952396dc604544ea7476b33fe87faedc24d666fb0c2d5ac971a2b9576ab871"}, + {file = "google_crc32c-1.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35834855408429cecf495cac67ccbab802de269e948e27478b1e47dfb6465e57"}, + {file = "google_crc32c-1.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:d8797406499f28b5ef791f339594b0b5fdedf54e203b5066675c406ba69d705c"}, + {file = "google_crc32c-1.6.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48abd62ca76a2cbe034542ed1b6aee851b6f28aaca4e6551b5599b6f3ef175cc"}, + {file = "google_crc32c-1.6.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18e311c64008f1f1379158158bb3f0c8d72635b9eb4f9545f8cf990c5668e59d"}, + {file = "google_crc32c-1.6.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05e2d8c9a2f853ff116db9706b4a27350587f341eda835f46db3c0a8c8ce2f24"}, + {file = "google_crc32c-1.6.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91ca8145b060679ec9176e6de4f89b07363d6805bd4760631ef254905503598d"}, + {file = "google_crc32c-1.6.0.tar.gz", hash = "sha256:6eceb6ad197656a1ff49ebfbbfa870678c75be4344feb35ac1edf694309413dc"}, ] [package.extras] @@ -804,13 +998,13 @@ testing = ["pytest"] [[package]] name = "google-resumable-media" -version = "2.7.0" +version = "2.7.2" description = "Utilities for Google Media Downloads and Resumable Uploads" optional = false -python-versions = ">= 3.7" +python-versions = ">=3.7" files = [ - {file = "google-resumable-media-2.7.0.tar.gz", hash = "sha256:5f18f5fa9836f4b083162064a1c2c98c17239bfda9ca50ad970ccf905f3e625b"}, - {file = "google_resumable_media-2.7.0-py2.py3-none-any.whl", hash = "sha256:79543cfe433b63fd81c0844b7803aba1bb8950b47bedf7d980c38fa123937e08"}, + {file = "google_resumable_media-2.7.2-py2.py3-none-any.whl", hash = "sha256:3ce7551e9fe6d99e9a126101d2536612bb73486721951e9562fee0f90c6ababa"}, + {file = "google_resumable_media-2.7.2.tar.gz", hash = "sha256:5280aed4629f2b60b847b0d42f9857fd4935c11af266744df33d8074cae92fe0"}, ] [package.dependencies] @@ -822,87 +1016,102 @@ requests = ["requests (>=2.18.0,<3.0.0dev)"] [[package]] name = "googleapis-common-protos" -version = "1.63.0" +version = "1.66.0" description = "Common protobufs used in Google APIs" optional = false python-versions = ">=3.7" files = [ - {file = "googleapis-common-protos-1.63.0.tar.gz", hash = "sha256:17ad01b11d5f1d0171c06d3ba5c04c54474e883b66b949722b4938ee2694ef4e"}, - {file = "googleapis_common_protos-1.63.0-py2.py3-none-any.whl", hash = "sha256:ae45f75702f7c08b541f750854a678bd8f534a1a6bace6afe975f1d0a82d6632"}, + {file = "googleapis_common_protos-1.66.0-py2.py3-none-any.whl", hash = "sha256:d7abcd75fabb2e0ec9f74466401f6c119a0b498e27370e9be4c94cb7e382b8ed"}, + {file = "googleapis_common_protos-1.66.0.tar.gz", hash = "sha256:c3e7b33d15fdca5374cc0a7346dd92ffa847425cc4ea941d970f13680052ec8c"}, ] [package.dependencies] grpcio = {version = ">=1.44.0,<2.0.0.dev0", optional = true, markers = "extra == \"grpc\""} -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0" +protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" [package.extras] grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] [[package]] name = "greenlet" -version = "3.0.3" +version = "3.1.1" description = "Lightweight in-process concurrent programming" optional = false python-versions = ">=3.7" files = [ - {file = "greenlet-3.0.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405"}, - {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f"}, - {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb"}, - {file = "greenlet-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9"}, - {file = "greenlet-3.0.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22"}, - {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3"}, - {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d"}, - {file = "greenlet-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728"}, - {file = "greenlet-3.0.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf"}, - {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305"}, - {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6"}, - {file = "greenlet-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2"}, - {file = "greenlet-3.0.3-cp37-cp37m-macosx_11_0_universal2.whl", hash = "sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41"}, - {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7"}, - {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6"}, - {file = "greenlet-3.0.3-cp37-cp37m-win32.whl", hash = "sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d"}, - {file = "greenlet-3.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67"}, - {file = "greenlet-3.0.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4"}, - {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5"}, - {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da"}, - {file = "greenlet-3.0.3-cp38-cp38-win32.whl", hash = "sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3"}, - {file = "greenlet-3.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf"}, - {file = "greenlet-3.0.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b"}, - {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6"}, - {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113"}, - {file = "greenlet-3.0.3-cp39-cp39-win32.whl", hash = "sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e"}, - {file = "greenlet-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067"}, - {file = "greenlet-3.0.3.tar.gz", hash = "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491"}, + {file = "greenlet-3.1.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:0bbae94a29c9e5c7e4a2b7f0aae5c17e8e90acbfd3bf6270eeba60c39fce3563"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fde093fb93f35ca72a556cf72c92ea3ebfda3d79fc35bb19fbe685853869a83"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:36b89d13c49216cadb828db8dfa6ce86bbbc476a82d3a6c397f0efae0525bdd0"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94b6150a85e1b33b40b1464a3f9988dcc5251d6ed06842abff82e42632fac120"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93147c513fac16385d1036b7e5b102c7fbbdb163d556b791f0f11eada7ba65dc"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da7a9bff22ce038e19bf62c4dd1ec8391062878710ded0a845bcf47cc0200617"}, + {file = "greenlet-3.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b2795058c23988728eec1f36a4e5e4ebad22f8320c85f3587b539b9ac84128d7"}, + {file = "greenlet-3.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ed10eac5830befbdd0c32f83e8aa6288361597550ba669b04c48f0f9a2c843c6"}, + {file = "greenlet-3.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:77c386de38a60d1dfb8e55b8c1101d68c79dfdd25c7095d51fec2dd800892b80"}, + {file = "greenlet-3.1.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e4d333e558953648ca09d64f13e6d8f0523fa705f51cae3f03b5983489958c70"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fc016b73c94e98e29af67ab7b9a879c307c6731a2c9da0db5a7d9b7edd1159"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5e975ca70269d66d17dd995dafc06f1b06e8cb1ec1e9ed54c1d1e4a7c4cf26e"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b2813dc3de8c1ee3f924e4d4227999285fd335d1bcc0d2be6dc3f1f6a318ec1"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e347b3bfcf985a05e8c0b7d462ba6f15b1ee1c909e2dcad795e49e91b152c383"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e8f8c9cb53cdac7ba9793c276acd90168f416b9ce36799b9b885790f8ad6c0a"}, + {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:62ee94988d6b4722ce0028644418d93a52429e977d742ca2ccbe1c4f4a792511"}, + {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1776fd7f989fc6b8d8c8cb8da1f6b82c5814957264d1f6cf818d475ec2bf6395"}, + {file = "greenlet-3.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:48ca08c771c268a768087b408658e216133aecd835c0ded47ce955381105ba39"}, + {file = "greenlet-3.1.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:4afe7ea89de619adc868e087b4d2359282058479d7cfb94970adf4b55284574d"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f406b22b7c9a9b4f8aa9d2ab13d6ae0ac3e85c9a809bd590ad53fed2bf70dc79"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c3a701fe5a9695b238503ce5bbe8218e03c3bcccf7e204e455e7462d770268aa"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2846930c65b47d70b9d178e89c7e1a69c95c1f68ea5aa0a58646b7a96df12441"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99cfaa2110534e2cf3ba31a7abcac9d328d1d9f1b95beede58294a60348fba36"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1443279c19fca463fc33e65ef2a935a5b09bb90f978beab37729e1c3c6c25fe9"}, + {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b7cede291382a78f7bb5f04a529cb18e068dd29e0fb27376074b6d0317bf4dd0"}, + {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:23f20bb60ae298d7d8656c6ec6db134bca379ecefadb0b19ce6f19d1f232a942"}, + {file = "greenlet-3.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:7124e16b4c55d417577c2077be379514321916d5790fa287c9ed6f23bd2ffd01"}, + {file = "greenlet-3.1.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:05175c27cb459dcfc05d026c4232f9de8913ed006d42713cb8a5137bd49375f1"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:935e943ec47c4afab8965954bf49bfa639c05d4ccf9ef6e924188f762145c0ff"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667a9706c970cb552ede35aee17339a18e8f2a87a51fba2ed39ceeeb1004798a"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8a678974d1f3aa55f6cc34dc480169d58f2e6d8958895d68845fa4ab566509e"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efc0f674aa41b92da8c49e0346318c6075d734994c3c4e4430b1c3f853e498e4"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e"}, + {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:275f72decf9932639c1c6dd1013a1bc266438eb32710016a1c742df5da6e60a1"}, + {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c4aab7f6381f38a4b42f269057aee279ab0fc7bf2e929e3d4abfae97b682a12c"}, + {file = "greenlet-3.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:b42703b1cf69f2aa1df7d1030b9d77d3e584a70755674d60e710f0af570f3761"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1695e76146579f8c06c1509c7ce4dfe0706f49c6831a817ac04eebb2fd02011"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7876452af029456b3f3549b696bb36a06db7c90747740c5302f74a9e9fa14b13"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ead44c85f8ab905852d3de8d86f6f8baf77109f9da589cb4fa142bd3b57b475"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8320f64b777d00dd7ccdade271eaf0cad6636343293a25074cc5566160e4de7b"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6510bf84a6b643dabba74d3049ead221257603a253d0a9873f55f6a59a65f822"}, + {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:04b013dc07c96f83134b1e99888e7a79979f1a247e2a9f59697fa14b5862ed01"}, + {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47da355d8687fd65240c364c90a31569a133b7b60de111c255ef5b606f2ae291"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:98884ecf2ffb7d7fe6bd517e8eb99d31ff7855a840fa6d0d63cd07c037f6a981"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1d4aeb8891338e60d1ab6127af1fe45def5259def8094b9c7e34690c8858803"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db32b5348615a04b82240cc67983cb315309e88d444a288934ee6ceaebcad6cc"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dcc62f31eae24de7f8dce72134c8651c58000d3b1868e01392baea7c32c247de"}, + {file = "greenlet-3.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1d3755bcb2e02de341c55b4fca7a745a24a9e7212ac953f6b3a48d117d7257aa"}, + {file = "greenlet-3.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b8da394b34370874b4572676f36acabac172602abf054cbc4ac910219f3340af"}, + {file = "greenlet-3.1.1-cp37-cp37m-win32.whl", hash = "sha256:a0dfc6c143b519113354e780a50381508139b07d2177cb6ad6a08278ec655798"}, + {file = "greenlet-3.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:54558ea205654b50c438029505def3834e80f0869a70fb15b871c29b4575ddef"}, + {file = "greenlet-3.1.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:346bed03fe47414091be4ad44786d1bd8bef0c3fcad6ed3dee074a032ab408a9"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfc59d69fc48664bc693842bd57acfdd490acafda1ab52c7836e3fc75c90a111"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21e10da6ec19b457b82636209cbe2331ff4306b54d06fa04b7c138ba18c8a81"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:37b9de5a96111fc15418819ab4c4432e4f3c2ede61e660b1e33971eba26ef9ba"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef9ea3f137e5711f0dbe5f9263e8c009b7069d8a1acea822bd5e9dae0ae49c8"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85f3ff71e2e60bd4b4932a043fbbe0f499e263c628390b285cb599154a3b03b1"}, + {file = "greenlet-3.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:95ffcf719966dd7c453f908e208e14cde192e09fde6c7186c8f1896ef778d8cd"}, + {file = "greenlet-3.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:03a088b9de532cbfe2ba2034b2b85e82df37874681e8c470d6fb2f8c04d7e4b7"}, + {file = "greenlet-3.1.1-cp38-cp38-win32.whl", hash = "sha256:8b8b36671f10ba80e159378df9c4f15c14098c4fd73a36b9ad715f057272fbef"}, + {file = "greenlet-3.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:7017b2be767b9d43cc31416aba48aab0d2309ee31b4dbf10a1d38fb7972bdf9d"}, + {file = "greenlet-3.1.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:396979749bd95f018296af156201d6211240e7a23090f50a8d5d18c370084dc3"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca9d0ff5ad43e785350894d97e13633a66e2b50000e8a183a50a88d834752d42"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f6ff3b14f2df4c41660a7dec01045a045653998784bf8cfcb5a525bdffffbc8f"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94ebba31df2aa506d7b14866fed00ac141a867e63143fe5bca82a8e503b36437"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73aaad12ac0ff500f62cebed98d8789198ea0e6f233421059fa68a5aa7220145"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63e4844797b975b9af3a3fb8f7866ff08775f5426925e1e0bbcfe7932059a12c"}, + {file = "greenlet-3.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7939aa3ca7d2a1593596e7ac6d59391ff30281ef280d8632fa03d81f7c5f955e"}, + {file = "greenlet-3.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d0028e725ee18175c6e422797c407874da24381ce0690d6b9396c204c7f7276e"}, + {file = "greenlet-3.1.1-cp39-cp39-win32.whl", hash = "sha256:5e06afd14cbaf9e00899fae69b24a32f2196c19de08fcb9f4779dd4f004e5e7c"}, + {file = "greenlet-3.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:3319aa75e0e0639bc15ff54ca327e8dc7a6fe404003496e3c6925cd3142e0e22"}, + {file = "greenlet-3.1.1.tar.gz", hash = "sha256:4ce3ac6cdb6adf7946475d7ef31777c26d94bccc377e070a7986bd2d5c515467"}, ] [package.extras] @@ -911,93 +1120,123 @@ test = ["objgraph", "psutil"] [[package]] name = "grpc-google-iam-v1" -version = "0.13.0" +version = "0.13.1" description = "IAM API client library" optional = false python-versions = ">=3.7" files = [ - {file = "grpc-google-iam-v1-0.13.0.tar.gz", hash = "sha256:fad318608b9e093258fbf12529180f400d1c44453698a33509cc6ecf005b294e"}, - {file = "grpc_google_iam_v1-0.13.0-py2.py3-none-any.whl", hash = "sha256:53902e2af7de8df8c1bd91373d9be55b0743ec267a7428ea638db3775becae89"}, + {file = "grpc-google-iam-v1-0.13.1.tar.gz", hash = "sha256:3ff4b2fd9d990965e410965253c0da6f66205d5a8291c4c31c6ebecca18a9001"}, + {file = "grpc_google_iam_v1-0.13.1-py2.py3-none-any.whl", hash = "sha256:c3e86151a981811f30d5e7330f271cee53e73bb87755e88cc3b6f0c7b5fe374e"}, ] [package.dependencies] googleapis-common-protos = {version = ">=1.56.0,<2.0.0dev", extras = ["grpc"]} grpcio = ">=1.44.0,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" +protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0dev" [[package]] name = "grpcio" -version = "1.63.0" +version = "1.68.1" description = "HTTP/2-based RPC framework" optional = false python-versions = ">=3.8" files = [ - {file = "grpcio-1.63.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:2e93aca840c29d4ab5db93f94ed0a0ca899e241f2e8aec6334ab3575dc46125c"}, - {file = "grpcio-1.63.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:91b73d3f1340fefa1e1716c8c1ec9930c676d6b10a3513ab6c26004cb02d8b3f"}, - {file = "grpcio-1.63.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:b3afbd9d6827fa6f475a4f91db55e441113f6d3eb9b7ebb8fb806e5bb6d6bd0d"}, - {file = "grpcio-1.63.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8f3f6883ce54a7a5f47db43289a0a4c776487912de1a0e2cc83fdaec9685cc9f"}, - {file = "grpcio-1.63.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf8dae9cc0412cb86c8de5a8f3be395c5119a370f3ce2e69c8b7d46bb9872c8d"}, - {file = "grpcio-1.63.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:08e1559fd3b3b4468486b26b0af64a3904a8dbc78d8d936af9c1cf9636eb3e8b"}, - {file = "grpcio-1.63.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5c039ef01516039fa39da8a8a43a95b64e288f79f42a17e6c2904a02a319b357"}, - {file = "grpcio-1.63.0-cp310-cp310-win32.whl", hash = "sha256:ad2ac8903b2eae071055a927ef74121ed52d69468e91d9bcbd028bd0e554be6d"}, - {file = "grpcio-1.63.0-cp310-cp310-win_amd64.whl", hash = "sha256:b2e44f59316716532a993ca2966636df6fbe7be4ab6f099de6815570ebe4383a"}, - {file = "grpcio-1.63.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:f28f8b2db7b86c77916829d64ab21ff49a9d8289ea1564a2b2a3a8ed9ffcccd3"}, - {file = "grpcio-1.63.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:65bf975639a1f93bee63ca60d2e4951f1b543f498d581869922910a476ead2f5"}, - {file = "grpcio-1.63.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:b5194775fec7dc3dbd6a935102bb156cd2c35efe1685b0a46c67b927c74f0cfb"}, - {file = "grpcio-1.63.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4cbb2100ee46d024c45920d16e888ee5d3cf47c66e316210bc236d5bebc42b3"}, - {file = "grpcio-1.63.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ff737cf29b5b801619f10e59b581869e32f400159e8b12d7a97e7e3bdeee6a2"}, - {file = "grpcio-1.63.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cd1e68776262dd44dedd7381b1a0ad09d9930ffb405f737d64f505eb7f77d6c7"}, - {file = "grpcio-1.63.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:93f45f27f516548e23e4ec3fbab21b060416007dbe768a111fc4611464cc773f"}, - {file = "grpcio-1.63.0-cp311-cp311-win32.whl", hash = "sha256:878b1d88d0137df60e6b09b74cdb73db123f9579232c8456f53e9abc4f62eb3c"}, - {file = "grpcio-1.63.0-cp311-cp311-win_amd64.whl", hash = "sha256:756fed02dacd24e8f488f295a913f250b56b98fb793f41d5b2de6c44fb762434"}, - {file = "grpcio-1.63.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:93a46794cc96c3a674cdfb59ef9ce84d46185fe9421baf2268ccb556f8f81f57"}, - {file = "grpcio-1.63.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a7b19dfc74d0be7032ca1eda0ed545e582ee46cd65c162f9e9fc6b26ef827dc6"}, - {file = "grpcio-1.63.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:8064d986d3a64ba21e498b9a376cbc5d6ab2e8ab0e288d39f266f0fca169b90d"}, - {file = "grpcio-1.63.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:219bb1848cd2c90348c79ed0a6b0ea51866bc7e72fa6e205e459fedab5770172"}, - {file = "grpcio-1.63.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2d60cd1d58817bc5985fae6168d8b5655c4981d448d0f5b6194bbcc038090d2"}, - {file = "grpcio-1.63.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:9e350cb096e5c67832e9b6e018cf8a0d2a53b2a958f6251615173165269a91b0"}, - {file = "grpcio-1.63.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:56cdf96ff82e3cc90dbe8bac260352993f23e8e256e063c327b6cf9c88daf7a9"}, - {file = "grpcio-1.63.0-cp312-cp312-win32.whl", hash = "sha256:3a6d1f9ea965e750db7b4ee6f9fdef5fdf135abe8a249e75d84b0a3e0c668a1b"}, - {file = "grpcio-1.63.0-cp312-cp312-win_amd64.whl", hash = "sha256:d2497769895bb03efe3187fb1888fc20e98a5f18b3d14b606167dacda5789434"}, - {file = "grpcio-1.63.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:fdf348ae69c6ff484402cfdb14e18c1b0054ac2420079d575c53a60b9b2853ae"}, - {file = "grpcio-1.63.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a3abfe0b0f6798dedd2e9e92e881d9acd0fdb62ae27dcbbfa7654a57e24060c0"}, - {file = "grpcio-1.63.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:6ef0ad92873672a2a3767cb827b64741c363ebaa27e7f21659e4e31f4d750280"}, - {file = "grpcio-1.63.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b416252ac5588d9dfb8a30a191451adbf534e9ce5f56bb02cd193f12d8845b7f"}, - {file = "grpcio-1.63.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3b77eaefc74d7eb861d3ffbdf91b50a1bb1639514ebe764c47773b833fa2d91"}, - {file = "grpcio-1.63.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b005292369d9c1f80bf70c1db1c17c6c342da7576f1c689e8eee4fb0c256af85"}, - {file = "grpcio-1.63.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cdcda1156dcc41e042d1e899ba1f5c2e9f3cd7625b3d6ebfa619806a4c1aadda"}, - {file = "grpcio-1.63.0-cp38-cp38-win32.whl", hash = "sha256:01799e8649f9e94ba7db1aeb3452188048b0019dc37696b0f5ce212c87c560c3"}, - {file = "grpcio-1.63.0-cp38-cp38-win_amd64.whl", hash = "sha256:6a1a3642d76f887aa4009d92f71eb37809abceb3b7b5a1eec9c554a246f20e3a"}, - {file = "grpcio-1.63.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:75f701ff645858a2b16bc8c9fc68af215a8bb2d5a9b647448129de6e85d52bce"}, - {file = "grpcio-1.63.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cacdef0348a08e475a721967f48206a2254a1b26ee7637638d9e081761a5ba86"}, - {file = "grpcio-1.63.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:0697563d1d84d6985e40ec5ec596ff41b52abb3fd91ec240e8cb44a63b895094"}, - {file = "grpcio-1.63.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6426e1fb92d006e47476d42b8f240c1d916a6d4423c5258ccc5b105e43438f61"}, - {file = "grpcio-1.63.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e48cee31bc5f5a31fb2f3b573764bd563aaa5472342860edcc7039525b53e46a"}, - {file = "grpcio-1.63.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:50344663068041b34a992c19c600236e7abb42d6ec32567916b87b4c8b8833b3"}, - {file = "grpcio-1.63.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:259e11932230d70ef24a21b9fb5bb947eb4703f57865a404054400ee92f42f5d"}, - {file = "grpcio-1.63.0-cp39-cp39-win32.whl", hash = "sha256:a44624aad77bf8ca198c55af811fd28f2b3eaf0a50ec5b57b06c034416ef2d0a"}, - {file = "grpcio-1.63.0-cp39-cp39-win_amd64.whl", hash = "sha256:166e5c460e5d7d4656ff9e63b13e1f6029b122104c1633d5f37eaea348d7356d"}, - {file = "grpcio-1.63.0.tar.gz", hash = "sha256:f3023e14805c61bc439fb40ca545ac3d5740ce66120a678a3c6c2c55b70343d1"}, -] - -[package.extras] -protobuf = ["grpcio-tools (>=1.63.0)"] + {file = "grpcio-1.68.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:d35740e3f45f60f3c37b1e6f2f4702c23867b9ce21c6410254c9c682237da68d"}, + {file = "grpcio-1.68.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:d99abcd61760ebb34bdff37e5a3ba333c5cc09feda8c1ad42547bea0416ada78"}, + {file = "grpcio-1.68.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:f8261fa2a5f679abeb2a0a93ad056d765cdca1c47745eda3f2d87f874ff4b8c9"}, + {file = "grpcio-1.68.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0feb02205a27caca128627bd1df4ee7212db051019a9afa76f4bb6a1a80ca95e"}, + {file = "grpcio-1.68.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:919d7f18f63bcad3a0f81146188e90274fde800a94e35d42ffe9eadf6a9a6330"}, + {file = "grpcio-1.68.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:963cc8d7d79b12c56008aabd8b457f400952dbea8997dd185f155e2f228db079"}, + {file = "grpcio-1.68.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ccf2ebd2de2d6661e2520dae293298a3803a98ebfc099275f113ce1f6c2a80f1"}, + {file = "grpcio-1.68.1-cp310-cp310-win32.whl", hash = "sha256:2cc1fd04af8399971bcd4f43bd98c22d01029ea2e56e69c34daf2bf8470e47f5"}, + {file = "grpcio-1.68.1-cp310-cp310-win_amd64.whl", hash = "sha256:ee2e743e51cb964b4975de572aa8fb95b633f496f9fcb5e257893df3be854746"}, + {file = "grpcio-1.68.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:55857c71641064f01ff0541a1776bfe04a59db5558e82897d35a7793e525774c"}, + {file = "grpcio-1.68.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4b177f5547f1b995826ef529d2eef89cca2f830dd8b2c99ffd5fde4da734ba73"}, + {file = "grpcio-1.68.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:3522c77d7e6606d6665ec8d50e867f13f946a4e00c7df46768f1c85089eae515"}, + {file = "grpcio-1.68.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9d1fae6bbf0816415b81db1e82fb3bf56f7857273c84dcbe68cbe046e58e1ccd"}, + {file = "grpcio-1.68.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:298ee7f80e26f9483f0b6f94cc0a046caf54400a11b644713bb5b3d8eb387600"}, + {file = "grpcio-1.68.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cbb5780e2e740b6b4f2d208e90453591036ff80c02cc605fea1af8e6fc6b1bbe"}, + {file = "grpcio-1.68.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ddda1aa22495d8acd9dfbafff2866438d12faec4d024ebc2e656784d96328ad0"}, + {file = "grpcio-1.68.1-cp311-cp311-win32.whl", hash = "sha256:b33bd114fa5a83f03ec6b7b262ef9f5cac549d4126f1dc702078767b10c46ed9"}, + {file = "grpcio-1.68.1-cp311-cp311-win_amd64.whl", hash = "sha256:7f20ebec257af55694d8f993e162ddf0d36bd82d4e57f74b31c67b3c6d63d8b2"}, + {file = "grpcio-1.68.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:8829924fffb25386995a31998ccbbeaa7367223e647e0122043dfc485a87c666"}, + {file = "grpcio-1.68.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:3aed6544e4d523cd6b3119b0916cef3d15ef2da51e088211e4d1eb91a6c7f4f1"}, + {file = "grpcio-1.68.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:4efac5481c696d5cb124ff1c119a78bddbfdd13fc499e3bc0ca81e95fc573684"}, + {file = "grpcio-1.68.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ab2d912ca39c51f46baf2a0d92aa265aa96b2443266fc50d234fa88bf877d8e"}, + {file = "grpcio-1.68.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95c87ce2a97434dffe7327a4071839ab8e8bffd0054cc74cbe971fba98aedd60"}, + {file = "grpcio-1.68.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e4842e4872ae4ae0f5497bf60a0498fa778c192cc7a9e87877abd2814aca9475"}, + {file = "grpcio-1.68.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:255b1635b0ed81e9f91da4fcc8d43b7ea5520090b9a9ad9340d147066d1d3613"}, + {file = "grpcio-1.68.1-cp312-cp312-win32.whl", hash = "sha256:7dfc914cc31c906297b30463dde0b9be48e36939575eaf2a0a22a8096e69afe5"}, + {file = "grpcio-1.68.1-cp312-cp312-win_amd64.whl", hash = "sha256:a0c8ddabef9c8f41617f213e527254c41e8b96ea9d387c632af878d05db9229c"}, + {file = "grpcio-1.68.1-cp313-cp313-linux_armv7l.whl", hash = "sha256:a47faedc9ea2e7a3b6569795c040aae5895a19dde0c728a48d3c5d7995fda385"}, + {file = "grpcio-1.68.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:390eee4225a661c5cd133c09f5da1ee3c84498dc265fd292a6912b65c421c78c"}, + {file = "grpcio-1.68.1-cp313-cp313-manylinux_2_17_aarch64.whl", hash = "sha256:66a24f3d45c33550703f0abb8b656515b0ab777970fa275693a2f6dc8e35f1c1"}, + {file = "grpcio-1.68.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c08079b4934b0bf0a8847f42c197b1d12cba6495a3d43febd7e99ecd1cdc8d54"}, + {file = "grpcio-1.68.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8720c25cd9ac25dd04ee02b69256d0ce35bf8a0f29e20577427355272230965a"}, + {file = "grpcio-1.68.1-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:04cfd68bf4f38f5bb959ee2361a7546916bd9a50f78617a346b3aeb2b42e2161"}, + {file = "grpcio-1.68.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c28848761a6520c5c6071d2904a18d339a796ebe6b800adc8b3f474c5ce3c3ad"}, + {file = "grpcio-1.68.1-cp313-cp313-win32.whl", hash = "sha256:77d65165fc35cff6e954e7fd4229e05ec76102d4406d4576528d3a3635fc6172"}, + {file = "grpcio-1.68.1-cp313-cp313-win_amd64.whl", hash = "sha256:a8040f85dcb9830d8bbb033ae66d272614cec6faceee88d37a88a9bd1a7a704e"}, + {file = "grpcio-1.68.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:eeb38ff04ab6e5756a2aef6ad8d94e89bb4a51ef96e20f45c44ba190fa0bcaad"}, + {file = "grpcio-1.68.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8a3869a6661ec8f81d93f4597da50336718bde9eb13267a699ac7e0a1d6d0bea"}, + {file = "grpcio-1.68.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:2c4cec6177bf325eb6faa6bd834d2ff6aa8bb3b29012cceb4937b86f8b74323c"}, + {file = "grpcio-1.68.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12941d533f3cd45d46f202e3667be8ebf6bcb3573629c7ec12c3e211d99cfccf"}, + {file = "grpcio-1.68.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80af6f1e69c5e68a2be529990684abdd31ed6622e988bf18850075c81bb1ad6e"}, + {file = "grpcio-1.68.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e8dbe3e00771bfe3d04feed8210fc6617006d06d9a2679b74605b9fed3e8362c"}, + {file = "grpcio-1.68.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:83bbf5807dc3ee94ce1de2dfe8a356e1d74101e4b9d7aa8c720cc4818a34aded"}, + {file = "grpcio-1.68.1-cp38-cp38-win32.whl", hash = "sha256:8cb620037a2fd9eeee97b4531880e439ebfcd6d7d78f2e7dcc3726428ab5ef63"}, + {file = "grpcio-1.68.1-cp38-cp38-win_amd64.whl", hash = "sha256:52fbf85aa71263380d330f4fce9f013c0798242e31ede05fcee7fbe40ccfc20d"}, + {file = "grpcio-1.68.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:cb400138e73969eb5e0535d1d06cae6a6f7a15f2cc74add320e2130b8179211a"}, + {file = "grpcio-1.68.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a1b988b40f2fd9de5c820f3a701a43339d8dcf2cb2f1ca137e2c02671cc83ac1"}, + {file = "grpcio-1.68.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:96f473cdacfdd506008a5d7579c9f6a7ff245a9ade92c3c0265eb76cc591914f"}, + {file = "grpcio-1.68.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:37ea3be171f3cf3e7b7e412a98b77685eba9d4fd67421f4a34686a63a65d99f9"}, + {file = "grpcio-1.68.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ceb56c4285754e33bb3c2fa777d055e96e6932351a3082ce3559be47f8024f0"}, + {file = "grpcio-1.68.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:dffd29a2961f3263a16d73945b57cd44a8fd0b235740cb14056f0612329b345e"}, + {file = "grpcio-1.68.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:025f790c056815b3bf53da850dd70ebb849fd755a4b1ac822cb65cd631e37d43"}, + {file = "grpcio-1.68.1-cp39-cp39-win32.whl", hash = "sha256:1098f03dedc3b9810810568060dea4ac0822b4062f537b0f53aa015269be0a76"}, + {file = "grpcio-1.68.1-cp39-cp39-win_amd64.whl", hash = "sha256:334ab917792904245a028f10e803fcd5b6f36a7b2173a820c0b5b076555825e1"}, + {file = "grpcio-1.68.1.tar.gz", hash = "sha256:44a8502dd5de653ae6a73e2de50a401d84184f0331d0ac3daeb044e66d5c5054"}, +] + +[package.extras] +protobuf = ["grpcio-tools (>=1.68.1)"] [[package]] name = "grpcio-status" -version = "1.62.2" +version = "1.68.1" description = "Status proto mapping for gRPC" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "grpcio-status-1.62.2.tar.gz", hash = "sha256:62e1bfcb02025a1cd73732a2d33672d3e9d0df4d21c12c51e0bbcaf09bab742a"}, - {file = "grpcio_status-1.62.2-py3-none-any.whl", hash = "sha256:206ddf0eb36bc99b033f03b2c8e95d319f0044defae9b41ae21408e7e0cda48f"}, + {file = "grpcio_status-1.68.1-py3-none-any.whl", hash = "sha256:66f3d8847f665acfd56221333d66f7ad8927903d87242a482996bdb45e8d28fd"}, + {file = "grpcio_status-1.68.1.tar.gz", hash = "sha256:e1378d036c81a1610d7b4c7a146cd663dd13fcc915cf4d7d053929dba5bbb6e1"}, ] [package.dependencies] googleapis-common-protos = ">=1.5.5" -grpcio = ">=1.62.2" -protobuf = ">=4.21.6" +grpcio = ">=1.68.1" +protobuf = ">=5.26.1,<6.0dev" + +[[package]] +name = "gunicorn" +version = "23.0.0" +description = "WSGI HTTP Server for UNIX" +optional = false +python-versions = ">=3.7" +files = [ + {file = "gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d"}, + {file = "gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec"}, +] + +[package.dependencies] +packaging = "*" + +[package.extras] +eventlet = ["eventlet (>=0.24.1,!=0.36.0)"] +gevent = ["gevent (>=1.4.0)"] +setproctitle = ["setproctitle"] +testing = ["coverage", "eventlet", "gevent", "pytest", "pytest-cov"] +tornado = ["tornado (>=0.2)"] [[package]] name = "h11" @@ -1012,13 +1251,13 @@ files = [ [[package]] name = "hypothesis" -version = "6.102.4" +version = "6.122.3" description = "A library for property-based testing" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "hypothesis-6.102.4-py3-none-any.whl", hash = "sha256:013df31b04a4daede13756f497e60e451963d86f426395a79f99c5d692919bbd"}, - {file = "hypothesis-6.102.4.tar.gz", hash = "sha256:59b4d144346d5cffb482cc1bafbd21b13ff31608e8c4b3e4630339aee3e87763"}, + {file = "hypothesis-6.122.3-py3-none-any.whl", hash = "sha256:f0f57036d3b95b979491602b32c95b6725c3af678cccb6165d8de330857f3c83"}, + {file = "hypothesis-6.122.3.tar.gz", hash = "sha256:f4c927ce0ec739fa6266e4572949d0b54e24a14601a2bc5fec8f78e16af57918"}, ] [package.dependencies] @@ -1026,33 +1265,36 @@ attrs = ">=22.2.0" sortedcontainers = ">=2.1.0,<3.0.0" [package.extras] -all = ["backports.zoneinfo (>=0.2.1)", "black (>=19.10b0)", "click (>=7.0)", "crosshair-tool (>=0.0.54)", "django (>=3.2)", "dpcontracts (>=0.4)", "hypothesis-crosshair (>=0.0.2)", "lark (>=0.10.1)", "libcst (>=0.3.16)", "numpy (>=1.17.3)", "pandas (>=1.1)", "pytest (>=4.6)", "python-dateutil (>=1.4)", "pytz (>=2014.1)", "redis (>=3.0.0)", "rich (>=9.0.0)", "tzdata (>=2024.1)"] +all = ["black (>=19.10b0)", "click (>=7.0)", "crosshair-tool (>=0.0.78)", "django (>=4.2)", "dpcontracts (>=0.4)", "hypothesis-crosshair (>=0.0.18)", "lark (>=0.10.1)", "libcst (>=0.3.16)", "numpy (>=1.19.3)", "pandas (>=1.1)", "pytest (>=4.6)", "python-dateutil (>=1.4)", "pytz (>=2014.1)", "redis (>=3.0.0)", "rich (>=9.0.0)", "tzdata (>=2024.2)"] cli = ["black (>=19.10b0)", "click (>=7.0)", "rich (>=9.0.0)"] codemods = ["libcst (>=0.3.16)"] -crosshair = ["crosshair-tool (>=0.0.54)", "hypothesis-crosshair (>=0.0.2)"] +crosshair = ["crosshair-tool (>=0.0.78)", "hypothesis-crosshair (>=0.0.18)"] dateutil = ["python-dateutil (>=1.4)"] -django = ["django (>=3.2)"] +django = ["django (>=4.2)"] dpcontracts = ["dpcontracts (>=0.4)"] ghostwriter = ["black (>=19.10b0)"] lark = ["lark (>=0.10.1)"] -numpy = ["numpy (>=1.17.3)"] +numpy = ["numpy (>=1.19.3)"] pandas = ["pandas (>=1.1)"] pytest = ["pytest (>=4.6)"] pytz = ["pytz (>=2014.1)"] redis = ["redis (>=3.0.0)"] -zoneinfo = ["backports.zoneinfo (>=0.2.1)", "tzdata (>=2024.1)"] +zoneinfo = ["tzdata (>=2024.2)"] [[package]] name = "idna" -version = "3.7" +version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" files = [ - {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, - {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + [[package]] name = "imagesize" version = "1.4.1" @@ -1064,6 +1306,52 @@ files = [ {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, ] +[[package]] +name = "importlib-metadata" +version = "8.5.0" +description = "Read metadata from Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"}, + {file = "importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"}, +] + +[package.dependencies] +zipp = ">=3.20" + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +perf = ["ipython"] +test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +type = ["pytest-mypy"] + +[[package]] +name = "inflect" +version = "7.4.0" +description = "Correctly generate plurals, singular nouns, ordinals, indefinite articles" +optional = false +python-versions = ">=3.8" +files = [ + {file = "inflect-7.4.0-py3-none-any.whl", hash = "sha256:85af0997ee2bda942b1c1eed8c8a827abda91aa3e22d1efaa0eea817f9350ce7"}, + {file = "inflect-7.4.0.tar.gz", hash = "sha256:904baa17cc2cb74827a6c27b95692e95670dadc72b208b3e8c1c05aeed47026b"}, +] + +[package.dependencies] +more-itertools = ">=8.5.0" +typeguard = ">=4.0.1" + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["pygments", "pytest (>=6,!=8.1.*)"] +type = ["pytest-mypy"] + [[package]] name = "iniconfig" version = "2.0.0" @@ -1129,132 +1417,206 @@ files = [ cryptography = ">=3.4" typing-extensions = ">=4.5.0" +[[package]] +name = "libcst" +version = "1.5.1" +description = "A concrete syntax tree with AST-like properties for Python 3.0 through 3.13 programs." +optional = false +python-versions = ">=3.9" +files = [ + {file = "libcst-1.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ab83633e61ee91df575a3838b1e73c371f19d4916bf1816554933235553d41ea"}, + {file = "libcst-1.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b58a49895d95ec1fd34fad041a142d98edf9b51fcaf632337c13befeb4d51c7c"}, + {file = "libcst-1.5.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d9ec764aa781ef35ab96b693569ac3dced16df9feb40ee6c274d13e86a1472e"}, + {file = "libcst-1.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99bbffd8596d192bc0e844a4cf3c4fc696979d4e20ab1c0774a01768a59b47ed"}, + {file = "libcst-1.5.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ec6ee607cfe4cc4cc93e56e0188fdb9e50399d61a1262d58229752946f288f5e"}, + {file = "libcst-1.5.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:72132756f985a19ef64d702a821099d4afc3544974662772b44cbc55b7279727"}, + {file = "libcst-1.5.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:40b75bf2d70fc0bc26b1fa73e61bdc46fef59f5c71aedf16128e7c33db8d5e40"}, + {file = "libcst-1.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:56c944acaa781b8e586df3019374f5cf117054d7fc98f85be1ba84fe810005dc"}, + {file = "libcst-1.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:db7711a762b0327b581be5a963908fecd74412bdda34db34553faa521563c22d"}, + {file = "libcst-1.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aa524bd012aaae1f485fd44490ef5abf708b14d2addc0f06b28de3e4585c4b9e"}, + {file = "libcst-1.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3ffb8135c09e41e8cf710b152c33e9b7f1d0d0b9f242bae0c502eb082fdb1fb"}, + {file = "libcst-1.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76a8ac7a84f9b6f678a668bff85b360e0a93fa8d7f25a74a206a28110734bb2a"}, + {file = "libcst-1.5.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89c808bdb5fa9ca02df41dd234cbb0e9de0d2e0c029c7063d5435a9f6781cc10"}, + {file = "libcst-1.5.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40fbbaa8b839bfbfa5b300623ca2b6b0768b58bbc31b341afbc99110c9bee232"}, + {file = "libcst-1.5.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c7021e3904d8d088c369afc3fe17c279883e583415ef07edacadba76cfbecd27"}, + {file = "libcst-1.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:f053a5deb6a214972dbe9fa26ecd8255edb903de084a3d7715bf9e9da8821c50"}, + {file = "libcst-1.5.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:666813950b8637af0c0e96b1ca46f5d5f183d2fe50bbac2186f5b283a99f3529"}, + {file = "libcst-1.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b7b58b36022ae77a5a00002854043ae95c03e92f6062ad08473eff326f32efa0"}, + {file = "libcst-1.5.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eeb13d7c598fe9a798a1d22eae56ab3d3d599b38b83436039bd6ae229fc854d7"}, + {file = "libcst-1.5.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5987daff8389b0df60b5c20499ff4fb73fc03cb3ae1f6a746eefd204ed08df85"}, + {file = "libcst-1.5.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00f3d2f32ee081bad3394546b0b9ac5e31686d3b5cfe4892d716d2ba65f9ec08"}, + {file = "libcst-1.5.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1ff21005c33b634957a98db438e882522febf1cacc62fa716f29e163a3f5871a"}, + {file = "libcst-1.5.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:15697ea9f1edbb9a263364d966c72abda07195d1c1a6838eb79af057f1040770"}, + {file = "libcst-1.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:cedd4c8336e01c51913113fbf5566b8f61a86d90f3d5cc5b1cb5049575622c5f"}, + {file = "libcst-1.5.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:06a9b4c9b76da4a7399e6f1f3a325196fb5febd3ea59fac1f68e2116f3517cd8"}, + {file = "libcst-1.5.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:940ec4c8db4c2d620a7268d6c83e64ff646e4afd74ae5183d0f0ef3b80e05be0"}, + {file = "libcst-1.5.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fbccb016b1ac6d892344300dcccc8a16887b71bb7f875ba56c0ed6c1a7ade8be"}, + {file = "libcst-1.5.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c615af2117320e9a218083c83ec61227d3547e38a0de80329376971765f27a9e"}, + {file = "libcst-1.5.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02b38fa4d9f13e79fe69e9b5407b9e173557bcfb5960f7866cf4145af9c7ae09"}, + {file = "libcst-1.5.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3334afe9e7270e175de01198f816b0dc78dda94d9d72152b61851c323e4e741e"}, + {file = "libcst-1.5.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:26c804fa8091747128579013df0b5f8e6b0c7904d9c4ee83841f136f53e18684"}, + {file = "libcst-1.5.1-cp313-cp313-win_amd64.whl", hash = "sha256:b5a0d3c632aa2b21c5fa145e4e8dbf86f45c9b37a64c0b7221a5a45caf58915a"}, + {file = "libcst-1.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1cc7393aaac733e963f0ee00466d059db74a38e15fc7e6a46dddd128c5be8d08"}, + {file = "libcst-1.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bbaf5755be50fa9b35a3d553d1e62293fbb2ee5ce2c16c7e7ffeb2746af1ab88"}, + {file = "libcst-1.5.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e397f5b6c0fc271acea44579f154b0f3ab36011050f6db75ab00cef47441946"}, + {file = "libcst-1.5.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1947790a4fd7d96bcc200a6ecaa528045fcb26a34a24030d5859c7983662289e"}, + {file = "libcst-1.5.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:697eabe9f5ffc40f76d6d02e693274e0a382826d0cf8183bd44e7407dfb0ab90"}, + {file = "libcst-1.5.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dc06b7c60d086ef1832aebfd31b64c3c8a645adf0c5638d6243e5838f6a9356e"}, + {file = "libcst-1.5.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:19e39cfef4316599ca20d1c821490aeb783b52e8a8543a824972a525322a85d0"}, + {file = "libcst-1.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:01e01c04f0641188160d3b99c6526436e93a3fbf9783dba970f9885a77ec9b38"}, + {file = "libcst-1.5.1.tar.gz", hash = "sha256:71cb294db84df9e410208009c732628e920111683c2f2b2e0c5b71b98464f365"}, +] + +[package.dependencies] +pyyaml = ">=5.2" + +[package.extras] +dev = ["Sphinx (>=5.1.1)", "black (==24.8.0)", "build (>=0.10.0)", "coverage[toml] (>=4.5.4)", "fixit (==2.1.0)", "flake8 (==7.1.1)", "hypothesis (>=4.36.0)", "hypothesmith (>=0.0.4)", "jinja2 (==3.1.4)", "jupyter (>=1.0.0)", "maturin (>=1.7.0,<1.8)", "nbsphinx (>=0.4.2)", "prompt-toolkit (>=2.0.9)", "pyre-check (==0.9.18)", "setuptools-rust (>=1.5.2)", "setuptools-scm (>=6.0.1)", "slotscheck (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "ufmt (==2.7.3)", "usort (==1.0.8.post1)"] + [[package]] name = "markupsafe" -version = "2.1.5" +version = "3.0.2" description = "Safely add untrusted strings to HTML/XML markup." optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, - {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, + {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, ] [[package]] name = "mimesis" -version = "17.0.0" +version = "18.0.0" description = "Mimesis: Fake Data Generator." optional = false python-versions = "<4.0,>=3.10" files = [ - {file = "mimesis-17.0.0-py3-none-any.whl", hash = "sha256:a088a14075c6d0356fea15e7687afb8f900a412daa80f2f3fe20f1771532402f"}, - {file = "mimesis-17.0.0.tar.gz", hash = "sha256:57fd7c2762c668054f2ebb85f71d484fa2fd55647d2a02bac4f2e97b81f22d8d"}, + {file = "mimesis-18.0.0-py3-none-any.whl", hash = "sha256:a51854a5ce63ebf2bd6a98e8841412e04cede38593be7e16d1d712848e6273df"}, + {file = "mimesis-18.0.0.tar.gz", hash = "sha256:7d7c76ecd680ae48afe8dc4413ef1ef1ee7ef20e16f9f9cb42892add642fc1b2"}, ] [package.extras] factory = ["factory-boy (>=3.3.0,<4.0.0)"] pytest = ["pytest (>=7.2,<8.0)"] +[[package]] +name = "more-itertools" +version = "10.5.0" +description = "More routines for operating on iterables, beyond itertools" +optional = false +python-versions = ">=3.8" +files = [ + {file = "more-itertools-10.5.0.tar.gz", hash = "sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6"}, + {file = "more_itertools-10.5.0-py3-none-any.whl", hash = "sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef"}, +] + [[package]] name = "mypy" -version = "1.10.0" +version = "1.13.0" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:da1cbf08fb3b851ab3b9523a884c232774008267b1f83371ace57f412fe308c2"}, - {file = "mypy-1.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:12b6bfc1b1a66095ab413160a6e520e1dc076a28f3e22f7fb25ba3b000b4ef99"}, - {file = "mypy-1.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e36fb078cce9904c7989b9693e41cb9711e0600139ce3970c6ef814b6ebc2b2"}, - {file = "mypy-1.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2b0695d605ddcd3eb2f736cd8b4e388288c21e7de85001e9f85df9187f2b50f9"}, - {file = "mypy-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:cd777b780312ddb135bceb9bc8722a73ec95e042f911cc279e2ec3c667076051"}, - {file = "mypy-1.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3be66771aa5c97602f382230165b856c231d1277c511c9a8dd058be4784472e1"}, - {file = "mypy-1.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8b2cbaca148d0754a54d44121b5825ae71868c7592a53b7292eeb0f3fdae95ee"}, - {file = "mypy-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ec404a7cbe9fc0e92cb0e67f55ce0c025014e26d33e54d9e506a0f2d07fe5de"}, - {file = "mypy-1.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e22e1527dc3d4aa94311d246b59e47f6455b8729f4968765ac1eacf9a4760bc7"}, - {file = "mypy-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:a87dbfa85971e8d59c9cc1fcf534efe664d8949e4c0b6b44e8ca548e746a8d53"}, - {file = "mypy-1.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a781f6ad4bab20eef8b65174a57e5203f4be627b46291f4589879bf4e257b97b"}, - {file = "mypy-1.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b808e12113505b97d9023b0b5e0c0705a90571c6feefc6f215c1df9381256e30"}, - {file = "mypy-1.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f55583b12156c399dce2df7d16f8a5095291354f1e839c252ec6c0611e86e2e"}, - {file = "mypy-1.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4cf18f9d0efa1b16478c4c129eabec36148032575391095f73cae2e722fcf9d5"}, - {file = "mypy-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:bc6ac273b23c6b82da3bb25f4136c4fd42665f17f2cd850771cb600bdd2ebeda"}, - {file = "mypy-1.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9fd50226364cd2737351c79807775136b0abe084433b55b2e29181a4c3c878c0"}, - {file = "mypy-1.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f90cff89eea89273727d8783fef5d4a934be2fdca11b47def50cf5d311aff727"}, - {file = "mypy-1.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fcfc70599efde5c67862a07a1aaf50e55bce629ace26bb19dc17cece5dd31ca4"}, - {file = "mypy-1.10.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:075cbf81f3e134eadaf247de187bd604748171d6b79736fa9b6c9685b4083061"}, - {file = "mypy-1.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:3f298531bca95ff615b6e9f2fc0333aae27fa48052903a0ac90215021cdcfa4f"}, - {file = "mypy-1.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fa7ef5244615a2523b56c034becde4e9e3f9b034854c93639adb667ec9ec2976"}, - {file = "mypy-1.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3236a4c8f535a0631f85f5fcdffba71c7feeef76a6002fcba7c1a8e57c8be1ec"}, - {file = "mypy-1.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a2b5cdbb5dd35aa08ea9114436e0d79aceb2f38e32c21684dcf8e24e1e92821"}, - {file = "mypy-1.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92f93b21c0fe73dc00abf91022234c79d793318b8a96faac147cd579c1671746"}, - {file = "mypy-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:28d0e038361b45f099cc086d9dd99c15ff14d0188f44ac883010e172ce86c38a"}, - {file = "mypy-1.10.0-py3-none-any.whl", hash = "sha256:f8c083976eb530019175aabadb60921e73b4f45736760826aa1689dda8208aee"}, - {file = "mypy-1.10.0.tar.gz", hash = "sha256:3d087fcbec056c4ee34974da493a826ce316947485cef3901f511848e687c131"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80"}, + {file = "mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7"}, + {file = "mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f"}, + {file = "mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d"}, + {file = "mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b"}, + {file = "mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73"}, + {file = "mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e"}, + {file = "mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2"}, + {file = "mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0"}, + {file = "mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62"}, + {file = "mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8"}, + {file = "mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7"}, + {file = "mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:100fac22ce82925f676a734af0db922ecfea991e1d7ec0ceb1e115ebe501301a"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bcb0bb7f42a978bb323a7c88f1081d1b5dee77ca86f4100735a6f541299d8fb"}, + {file = "mypy-1.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bde31fc887c213e223bbfc34328070996061b0833b0a4cfec53745ed61f3519b"}, + {file = "mypy-1.13.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07de989f89786f62b937851295ed62e51774722e5444a27cecca993fc3f9cd74"}, + {file = "mypy-1.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:4bde84334fbe19bad704b3f5b78c4abd35ff1026f8ba72b29de70dda0916beb6"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732"}, + {file = "mypy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc"}, + {file = "mypy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d"}, + {file = "mypy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24"}, + {file = "mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a"}, + {file = "mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e"}, ] [package.dependencies] mypy-extensions = ">=1.0.0" -typing-extensions = ">=4.1.0" +typing-extensions = ">=4.6.0" [package.extras] dmypy = ["psutil (>=4.0)"] +faster-cache = ["orjson"] install-types = ["pip"] mypyc = ["setuptools (>=50)"] reports = ["lxml"] @@ -1272,22 +1634,131 @@ files = [ [[package]] name = "mysqlclient" -version = "2.2.4" +version = "2.2.6" description = "Python interface to MySQL" optional = false python-versions = ">=3.8" files = [ - {file = "mysqlclient-2.2.4-cp310-cp310-win_amd64.whl", hash = "sha256:ac44777eab0a66c14cb0d38965572f762e193ec2e5c0723bcd11319cc5b693c5"}, - {file = "mysqlclient-2.2.4-cp311-cp311-win_amd64.whl", hash = "sha256:329e4eec086a2336fe3541f1ce095d87a6f169d1cc8ba7b04ac68bcb234c9711"}, - {file = "mysqlclient-2.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:e1ebe3f41d152d7cb7c265349fdb7f1eca86ccb0ca24a90036cde48e00ceb2ab"}, - {file = "mysqlclient-2.2.4-cp38-cp38-win_amd64.whl", hash = "sha256:3c318755e06df599338dad7625f884b8a71fcf322a9939ef78c9b3db93e1de7a"}, - {file = "mysqlclient-2.2.4-cp39-cp39-win_amd64.whl", hash = "sha256:9d4c015480c4a6b2b1602eccd9846103fc70606244788d04aa14b31c4bd1f0e2"}, - {file = "mysqlclient-2.2.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d43987bb9626096a302ca6ddcdd81feaeca65ced1d5fe892a6a66b808326aa54"}, - {file = "mysqlclient-2.2.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4e80dcad884dd6e14949ac6daf769123223a52a6805345608bf49cdaf7bc8b3a"}, - {file = "mysqlclient-2.2.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:9d3310295cb682232cadc28abd172f406c718b9ada41d2371259098ae37779d3"}, - {file = "mysqlclient-2.2.4.tar.gz", hash = "sha256:33bc9fb3464e7d7c10b1eaf7336c5ff8f2a3d3b88bab432116ad2490beb3bf41"}, + {file = "mysqlclient-2.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:e94a92858203d97fd584bdb6d7ee8c56f2590db8d77fd44215c0dcf5e739bc37"}, + {file = "mysqlclient-2.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:43c5b30be0675080b9c815f457d73397f0442173e7be83d089b126835e2617ae"}, + {file = "mysqlclient-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:e940b41d85dfd7b190fa47d52f525f878cfa203d4653bf6a35b271b3c3be125b"}, + {file = "mysqlclient-2.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:794857bce4f9a1903a99786dd29ad7887f45a870b3d11585b8c51c4a753c4174"}, + {file = "mysqlclient-2.2.6-cp39-cp39-win_amd64.whl", hash = "sha256:b0a5cddf1d3488b254605041070086cac743401d876a659a72d706a0d89c8ebb"}, + {file = "mysqlclient-2.2.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f3efb849d6f7ef4b9788a0eda2e896b975e0ebf1d6bf3dcabea63fd698e5b0b5"}, + {file = "mysqlclient-2.2.6-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3da70a07753ba6be881f7d75e795e254f6a0c12795778034acc69769b0649d37"}, + {file = "mysqlclient-2.2.6.tar.gz", hash = "sha256:c0b46d9b78b461dbb62482089ca8040fa916595b1b30f831ebbd1b0a82b43d53"}, ] +[[package]] +name = "numpy" +version = "2.2.0" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.10" +files = [ + {file = "numpy-2.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1e25507d85da11ff5066269d0bd25d06e0a0f2e908415534f3e603d2a78e4ffa"}, + {file = "numpy-2.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a62eb442011776e4036af5c8b1a00b706c5bc02dc15eb5344b0c750428c94219"}, + {file = "numpy-2.2.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:b606b1aaf802e6468c2608c65ff7ece53eae1a6874b3765f69b8ceb20c5fa78e"}, + {file = "numpy-2.2.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:36b2b43146f646642b425dd2027730f99bac962618ec2052932157e213a040e9"}, + {file = "numpy-2.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7fe8f3583e0607ad4e43a954e35c1748b553bfe9fdac8635c02058023277d1b3"}, + {file = "numpy-2.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:122fd2fcfafdefc889c64ad99c228d5a1f9692c3a83f56c292618a59aa60ae83"}, + {file = "numpy-2.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3f2f5cddeaa4424a0a118924b988746db6ffa8565e5829b1841a8a3bd73eb59a"}, + {file = "numpy-2.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7fe4bb0695fe986a9e4deec3b6857003b4cfe5c5e4aac0b95f6a658c14635e31"}, + {file = "numpy-2.2.0-cp310-cp310-win32.whl", hash = "sha256:b30042fe92dbd79f1ba7f6898fada10bdaad1847c44f2dff9a16147e00a93661"}, + {file = "numpy-2.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:54dc1d6d66f8d37843ed281773c7174f03bf7ad826523f73435deb88ba60d2d4"}, + {file = "numpy-2.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9874bc2ff574c40ab7a5cbb7464bf9b045d617e36754a7bc93f933d52bd9ffc6"}, + {file = "numpy-2.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0da8495970f6b101ddd0c38ace92edea30e7e12b9a926b57f5fabb1ecc25bb90"}, + {file = "numpy-2.2.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:0557eebc699c1c34cccdd8c3778c9294e8196df27d713706895edc6f57d29608"}, + {file = "numpy-2.2.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:3579eaeb5e07f3ded59298ce22b65f877a86ba8e9fe701f5576c99bb17c283da"}, + {file = "numpy-2.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40deb10198bbaa531509aad0cd2f9fadb26c8b94070831e2208e7df543562b74"}, + {file = "numpy-2.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2aed8fcf8abc3020d6a9ccb31dbc9e7d7819c56a348cc88fd44be269b37427e"}, + {file = "numpy-2.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a222d764352c773aa5ebde02dd84dba3279c81c6db2e482d62a3fa54e5ece69b"}, + {file = "numpy-2.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4e58666988605e251d42c2818c7d3d8991555381be26399303053b58a5bbf30d"}, + {file = "numpy-2.2.0-cp311-cp311-win32.whl", hash = "sha256:4723a50e1523e1de4fccd1b9a6dcea750c2102461e9a02b2ac55ffeae09a4410"}, + {file = "numpy-2.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:16757cf28621e43e252c560d25b15f18a2f11da94fea344bf26c599b9cf54b73"}, + {file = "numpy-2.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cff210198bb4cae3f3c100444c5eaa573a823f05c253e7188e1362a5555235b3"}, + {file = "numpy-2.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:58b92a5828bd4d9aa0952492b7de803135038de47343b2aa3cc23f3b71a3dc4e"}, + {file = "numpy-2.2.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:ebe5e59545401fbb1b24da76f006ab19734ae71e703cdb4a8b347e84a0cece67"}, + {file = "numpy-2.2.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:e2b8cd48a9942ed3f85b95ca4105c45758438c7ed28fff1e4ce3e57c3b589d8e"}, + {file = "numpy-2.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57fcc997ffc0bef234b8875a54d4058afa92b0b0c4223fc1f62f24b3b5e86038"}, + {file = "numpy-2.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85ad7d11b309bd132d74397fcf2920933c9d1dc865487128f5c03d580f2c3d03"}, + {file = "numpy-2.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cb24cca1968b21355cc6f3da1a20cd1cebd8a023e3c5b09b432444617949085a"}, + {file = "numpy-2.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0798b138c291d792f8ea40fe3768610f3c7dd2574389e37c3f26573757c8f7ef"}, + {file = "numpy-2.2.0-cp312-cp312-win32.whl", hash = "sha256:afe8fb968743d40435c3827632fd36c5fbde633b0423da7692e426529b1759b1"}, + {file = "numpy-2.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:3a4199f519e57d517ebd48cb76b36c82da0360781c6a0353e64c0cac30ecaad3"}, + {file = "numpy-2.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f8c8b141ef9699ae777c6278b52c706b653bf15d135d302754f6b2e90eb30367"}, + {file = "numpy-2.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0f0986e917aca18f7a567b812ef7ca9391288e2acb7a4308aa9d265bd724bdae"}, + {file = "numpy-2.2.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:1c92113619f7b272838b8d6702a7f8ebe5edea0df48166c47929611d0b4dea69"}, + {file = "numpy-2.2.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:5a145e956b374e72ad1dff82779177d4a3c62bc8248f41b80cb5122e68f22d13"}, + {file = "numpy-2.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18142b497d70a34b01642b9feabb70156311b326fdddd875a9981f34a369b671"}, + {file = "numpy-2.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7d41d1612c1a82b64697e894b75db6758d4f21c3ec069d841e60ebe54b5b571"}, + {file = "numpy-2.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a98f6f20465e7618c83252c02041517bd2f7ea29be5378f09667a8f654a5918d"}, + {file = "numpy-2.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e09d40edfdb4e260cb1567d8ae770ccf3b8b7e9f0d9b5c2a9992696b30ce2742"}, + {file = "numpy-2.2.0-cp313-cp313-win32.whl", hash = "sha256:3905a5fffcc23e597ee4d9fb3fcd209bd658c352657548db7316e810ca80458e"}, + {file = "numpy-2.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:a184288538e6ad699cbe6b24859206e38ce5fba28f3bcfa51c90d0502c1582b2"}, + {file = "numpy-2.2.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:7832f9e8eb00be32f15fdfb9a981d6955ea9adc8574c521d48710171b6c55e95"}, + {file = "numpy-2.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f0dd071b95bbca244f4cb7f70b77d2ff3aaaba7fa16dc41f58d14854a6204e6c"}, + {file = "numpy-2.2.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:b0b227dcff8cdc3efbce66d4e50891f04d0a387cce282fe1e66199146a6a8fca"}, + {file = "numpy-2.2.0-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:6ab153263a7c5ccaf6dfe7e53447b74f77789f28ecb278c3b5d49db7ece10d6d"}, + {file = "numpy-2.2.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e500aba968a48e9019e42c0c199b7ec0696a97fa69037bea163b55398e390529"}, + {file = "numpy-2.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:440cfb3db4c5029775803794f8638fbdbf71ec702caf32735f53b008e1eaece3"}, + {file = "numpy-2.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a55dc7a7f0b6198b07ec0cd445fbb98b05234e8b00c5ac4874a63372ba98d4ab"}, + {file = "numpy-2.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4bddbaa30d78c86329b26bd6aaaea06b1e47444da99eddac7bf1e2fab717bd72"}, + {file = "numpy-2.2.0-cp313-cp313t-win32.whl", hash = "sha256:30bf971c12e4365153afb31fc73f441d4da157153f3400b82db32d04de1e4066"}, + {file = "numpy-2.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:d35717333b39d1b6bb8433fa758a55f1081543de527171543a2b710551d40881"}, + {file = "numpy-2.2.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e12c6c1ce84628c52d6367863773f7c8c8241be554e8b79686e91a43f1733773"}, + {file = "numpy-2.2.0-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:b6207dc8fb3c8cb5668e885cef9ec7f70189bec4e276f0ff70d5aa078d32c88e"}, + {file = "numpy-2.2.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a50aeff71d0f97b6450d33940c7181b08be1441c6c193e678211bff11aa725e7"}, + {file = "numpy-2.2.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:df12a1f99b99f569a7c2ae59aa2d31724e8d835fc7f33e14f4792e3071d11221"}, + {file = "numpy-2.2.0.tar.gz", hash = "sha256:140dd80ff8981a583a60980be1a655068f8adebf7a45a06a6858c873fcdcd4a0"}, +] + +[[package]] +name = "opentelemetry-api" +version = "1.29.0" +description = "OpenTelemetry Python API" +optional = false +python-versions = ">=3.8" +files = [ + {file = "opentelemetry_api-1.29.0-py3-none-any.whl", hash = "sha256:5fcd94c4141cc49c736271f3e1efb777bebe9cc535759c54c936cca4f1b312b8"}, + {file = "opentelemetry_api-1.29.0.tar.gz", hash = "sha256:d04a6cf78aad09614f52964ecb38021e248f5714dc32c2e0d8fd99517b4d69cf"}, +] + +[package.dependencies] +deprecated = ">=1.2.6" +importlib-metadata = ">=6.0,<=8.5.0" + +[[package]] +name = "opentelemetry-sdk" +version = "1.29.0" +description = "OpenTelemetry Python SDK" +optional = false +python-versions = ">=3.8" +files = [ + {file = "opentelemetry_sdk-1.29.0-py3-none-any.whl", hash = "sha256:173be3b5d3f8f7d671f20ea37056710217959e774e2749d984355d1f9391a30a"}, + {file = "opentelemetry_sdk-1.29.0.tar.gz", hash = "sha256:b0787ce6aade6ab84315302e72bd7a7f2f014b0fb1b7c3295b88afe014ed0643"}, +] + +[package.dependencies] +opentelemetry-api = "1.29.0" +opentelemetry-semantic-conventions = "0.50b0" +typing-extensions = ">=3.7.4" + +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.50b0" +description = "OpenTelemetry Semantic Conventions" +optional = false +python-versions = ">=3.8" +files = [ + {file = "opentelemetry_semantic_conventions-0.50b0-py3-none-any.whl", hash = "sha256:e87efba8fdb67fb38113efea6a349531e75ed7ffc01562f65b802fcecb5e115e"}, + {file = "opentelemetry_semantic_conventions-0.50b0.tar.gz", hash = "sha256:02dc6dbcb62f082de9b877ff19a3f1ffaa3c306300fa53bfac761c4567c83d38"}, +] + +[package.dependencies] +deprecated = ">=1.2.6" +opentelemetry-api = "1.29.0" + [[package]] name = "outcome" version = "1.3.0.post0" @@ -1304,15 +1775,56 @@ attrs = ">=19.2.0" [[package]] name = "packaging" -version = "24.0" +version = "24.2" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, - {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "pgvector" +version = "0.3.6" +description = "pgvector support for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pgvector-0.3.6-py3-none-any.whl", hash = "sha256:f6c269b3c110ccb7496bac87202148ed18f34b390a0189c783e351062400a75a"}, + {file = "pgvector-0.3.6.tar.gz", hash = "sha256:31d01690e6ea26cea8a633cde5f0f55f5b246d9c8292d68efdef8c22ec994ade"}, +] + +[package.dependencies] +numpy = "*" + +[[package]] +name = "platformdirs" +version = "4.3.6" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, +] + +[package.extras] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.11.2)"] + [[package]] name = "pluggy" version = "1.5.0" @@ -1330,39 +1842,39 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "proto-plus" -version = "1.23.0" +version = "1.25.0" description = "Beautiful, Pythonic protocol buffers." optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "proto-plus-1.23.0.tar.gz", hash = "sha256:89075171ef11988b3fa157f5dbd8b9cf09d65fffee97e29ce403cd8defba19d2"}, - {file = "proto_plus-1.23.0-py3-none-any.whl", hash = "sha256:a829c79e619e1cf632de091013a4173deed13a55f326ef84f05af6f50ff4c82c"}, + {file = "proto_plus-1.25.0-py3-none-any.whl", hash = "sha256:c91fc4a65074ade8e458e95ef8bac34d4008daa7cce4a12d6707066fca648961"}, + {file = "proto_plus-1.25.0.tar.gz", hash = "sha256:fbb17f57f7bd05a68b7707e745e26528b0b3c34e378db91eef93912c54982d91"}, ] [package.dependencies] -protobuf = ">=3.19.0,<5.0.0dev" +protobuf = ">=3.19.0,<6.0.0dev" [package.extras] -testing = ["google-api-core[grpc] (>=1.31.5)"] +testing = ["google-api-core (>=1.31.5)"] [[package]] name = "protobuf" -version = "4.25.3" +version = "5.29.1" description = "" optional = false python-versions = ">=3.8" files = [ - {file = "protobuf-4.25.3-cp310-abi3-win32.whl", hash = "sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa"}, - {file = "protobuf-4.25.3-cp310-abi3-win_amd64.whl", hash = "sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8"}, - {file = "protobuf-4.25.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c"}, - {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:e7cb0ae90dd83727f0c0718634ed56837bfeeee29a5f82a7514c03ee1364c019"}, - {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:7c8daa26095f82482307bc717364e7c13f4f1c99659be82890dcfc215194554d"}, - {file = "protobuf-4.25.3-cp38-cp38-win32.whl", hash = "sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2"}, - {file = "protobuf-4.25.3-cp38-cp38-win_amd64.whl", hash = "sha256:c053062984e61144385022e53678fbded7aea14ebb3e0305ae3592fb219ccfa4"}, - {file = "protobuf-4.25.3-cp39-cp39-win32.whl", hash = "sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4"}, - {file = "protobuf-4.25.3-cp39-cp39-win_amd64.whl", hash = "sha256:e3c97a1555fd6388f857770ff8b9703083de6bf1f9274a002a332d65fbb56c8c"}, - {file = "protobuf-4.25.3-py3-none-any.whl", hash = "sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9"}, - {file = "protobuf-4.25.3.tar.gz", hash = "sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c"}, + {file = "protobuf-5.29.1-cp310-abi3-win32.whl", hash = "sha256:22c1f539024241ee545cbcb00ee160ad1877975690b16656ff87dde107b5f110"}, + {file = "protobuf-5.29.1-cp310-abi3-win_amd64.whl", hash = "sha256:1fc55267f086dd4050d18ef839d7bd69300d0d08c2a53ca7df3920cc271a3c34"}, + {file = "protobuf-5.29.1-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:d473655e29c0c4bbf8b69e9a8fb54645bc289dead6d753b952e7aa660254ae18"}, + {file = "protobuf-5.29.1-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:b5ba1d0e4c8a40ae0496d0e2ecfdbb82e1776928a205106d14ad6985a09ec155"}, + {file = "protobuf-5.29.1-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:8ee1461b3af56145aca2800e6a3e2f928108c749ba8feccc6f5dd0062c410c0d"}, + {file = "protobuf-5.29.1-cp38-cp38-win32.whl", hash = "sha256:50879eb0eb1246e3a5eabbbe566b44b10348939b7cc1b267567e8c3d07213853"}, + {file = "protobuf-5.29.1-cp38-cp38-win_amd64.whl", hash = "sha256:027fbcc48cea65a6b17028510fdd054147057fa78f4772eb547b9274e5219331"}, + {file = "protobuf-5.29.1-cp39-cp39-win32.whl", hash = "sha256:5a41deccfa5e745cef5c65a560c76ec0ed8e70908a67cc8f4da5fce588b50d57"}, + {file = "protobuf-5.29.1-cp39-cp39-win_amd64.whl", hash = "sha256:012ce28d862ff417fd629285aca5d9772807f15ceb1a0dbd15b88f58c776c98c"}, + {file = "protobuf-5.29.1-py3-none-any.whl", hash = "sha256:32600ddb9c2a53dedc25b8581ea0f1fd8ea04956373c0c07577ce58d312522e0"}, + {file = "protobuf-5.29.1.tar.gz", hash = "sha256:683be02ca21a6ffe80db6dd02c0b5b2892322c59ca57fd6c872d652cb80549cb"}, ] [[package]] @@ -1454,29 +1966,40 @@ files = [ [[package]] name = "pyasn1" -version = "0.6.0" +version = "0.6.1" description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" optional = false python-versions = ">=3.8" files = [ - {file = "pyasn1-0.6.0-py2.py3-none-any.whl", hash = "sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473"}, - {file = "pyasn1-0.6.0.tar.gz", hash = "sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c"}, + {file = "pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629"}, + {file = "pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034"}, ] [[package]] name = "pyasn1-modules" -version = "0.4.0" +version = "0.4.1" description = "A collection of ASN.1-based protocols modules" optional = false python-versions = ">=3.8" files = [ - {file = "pyasn1_modules-0.4.0-py3-none-any.whl", hash = "sha256:be04f15b66c206eed667e0bb5ab27e2b1855ea54a842e5037738099e8ca4ae0b"}, - {file = "pyasn1_modules-0.4.0.tar.gz", hash = "sha256:831dbcea1b177b28c9baddf4c6d1013c24c3accd14a1873fffaa6a2e905f17b6"}, + {file = "pyasn1_modules-0.4.1-py3-none-any.whl", hash = "sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd"}, + {file = "pyasn1_modules-0.4.1.tar.gz", hash = "sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c"}, ] [package.dependencies] pyasn1 = ">=0.4.6,<0.7.0" +[[package]] +name = "pycodestyle" +version = "2.12.1" +description = "Python style guide checker" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pycodestyle-2.12.1-py2.py3-none-any.whl", hash = "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3"}, + {file = "pycodestyle-2.12.1.tar.gz", hash = "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521"}, +] + [[package]] name = "pycparser" version = "2.22" @@ -1490,47 +2013,54 @@ files = [ [[package]] name = "pydantic" -version = "1.10.15" +version = "1.10.19" description = "Data validation and settings management using python type hints" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic-1.10.15-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:22ed12ee588b1df028a2aa5d66f07bf8f8b4c8579c2e96d5a9c1f96b77f3bb55"}, - {file = "pydantic-1.10.15-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:75279d3cac98186b6ebc2597b06bcbc7244744f6b0b44a23e4ef01e5683cc0d2"}, - {file = "pydantic-1.10.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50f1666a9940d3d68683c9d96e39640f709d7a72ff8702987dab1761036206bb"}, - {file = "pydantic-1.10.15-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82790d4753ee5d00739d6cb5cf56bceb186d9d6ce134aca3ba7befb1eedbc2c8"}, - {file = "pydantic-1.10.15-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:d207d5b87f6cbefbdb1198154292faee8017d7495a54ae58db06762004500d00"}, - {file = "pydantic-1.10.15-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e49db944fad339b2ccb80128ffd3f8af076f9f287197a480bf1e4ca053a866f0"}, - {file = "pydantic-1.10.15-cp310-cp310-win_amd64.whl", hash = "sha256:d3b5c4cbd0c9cb61bbbb19ce335e1f8ab87a811f6d589ed52b0254cf585d709c"}, - {file = "pydantic-1.10.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c3d5731a120752248844676bf92f25a12f6e45425e63ce22e0849297a093b5b0"}, - {file = "pydantic-1.10.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c365ad9c394f9eeffcb30a82f4246c0006417f03a7c0f8315d6211f25f7cb654"}, - {file = "pydantic-1.10.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3287e1614393119c67bd4404f46e33ae3be3ed4cd10360b48d0a4459f420c6a3"}, - {file = "pydantic-1.10.15-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be51dd2c8596b25fe43c0a4a59c2bee4f18d88efb8031188f9e7ddc6b469cf44"}, - {file = "pydantic-1.10.15-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6a51a1dd4aa7b3f1317f65493a182d3cff708385327c1c82c81e4a9d6d65b2e4"}, - {file = "pydantic-1.10.15-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4e316e54b5775d1eb59187f9290aeb38acf620e10f7fd2f776d97bb788199e53"}, - {file = "pydantic-1.10.15-cp311-cp311-win_amd64.whl", hash = "sha256:0d142fa1b8f2f0ae11ddd5e3e317dcac060b951d605fda26ca9b234b92214986"}, - {file = "pydantic-1.10.15-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7ea210336b891f5ea334f8fc9f8f862b87acd5d4a0cbc9e3e208e7aa1775dabf"}, - {file = "pydantic-1.10.15-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3453685ccd7140715e05f2193d64030101eaad26076fad4e246c1cc97e1bb30d"}, - {file = "pydantic-1.10.15-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bea1f03b8d4e8e86702c918ccfd5d947ac268f0f0cc6ed71782e4b09353b26f"}, - {file = "pydantic-1.10.15-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:005655cabc29081de8243126e036f2065bd7ea5b9dff95fde6d2c642d39755de"}, - {file = "pydantic-1.10.15-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:af9850d98fc21e5bc24ea9e35dd80a29faf6462c608728a110c0a30b595e58b7"}, - {file = "pydantic-1.10.15-cp37-cp37m-win_amd64.whl", hash = "sha256:d31ee5b14a82c9afe2bd26aaa405293d4237d0591527d9129ce36e58f19f95c1"}, - {file = "pydantic-1.10.15-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5e09c19df304b8123938dc3c53d3d3be6ec74b9d7d0d80f4f4b5432ae16c2022"}, - {file = "pydantic-1.10.15-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7ac9237cd62947db00a0d16acf2f3e00d1ae9d3bd602b9c415f93e7a9fc10528"}, - {file = "pydantic-1.10.15-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:584f2d4c98ffec420e02305cf675857bae03c9d617fcfdc34946b1160213a948"}, - {file = "pydantic-1.10.15-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bbc6989fad0c030bd70a0b6f626f98a862224bc2b1e36bfc531ea2facc0a340c"}, - {file = "pydantic-1.10.15-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d573082c6ef99336f2cb5b667b781d2f776d4af311574fb53d908517ba523c22"}, - {file = "pydantic-1.10.15-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6bd7030c9abc80134087d8b6e7aa957e43d35714daa116aced57269a445b8f7b"}, - {file = "pydantic-1.10.15-cp38-cp38-win_amd64.whl", hash = "sha256:3350f527bb04138f8aff932dc828f154847fbdc7a1a44c240fbfff1b57f49a12"}, - {file = "pydantic-1.10.15-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:51d405b42f1b86703555797270e4970a9f9bd7953f3990142e69d1037f9d9e51"}, - {file = "pydantic-1.10.15-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a980a77c52723b0dc56640ced396b73a024d4b74f02bcb2d21dbbac1debbe9d0"}, - {file = "pydantic-1.10.15-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67f1a1fb467d3f49e1708a3f632b11c69fccb4e748a325d5a491ddc7b5d22383"}, - {file = "pydantic-1.10.15-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:676ed48f2c5bbad835f1a8ed8a6d44c1cd5a21121116d2ac40bd1cd3619746ed"}, - {file = "pydantic-1.10.15-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:92229f73400b80c13afcd050687f4d7e88de9234d74b27e6728aa689abcf58cc"}, - {file = "pydantic-1.10.15-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2746189100c646682eff0bce95efa7d2e203420d8e1c613dc0c6b4c1d9c1fde4"}, - {file = "pydantic-1.10.15-cp39-cp39-win_amd64.whl", hash = "sha256:394f08750bd8eaad714718812e7fab615f873b3cdd0b9d84e76e51ef3b50b6b7"}, - {file = "pydantic-1.10.15-py3-none-any.whl", hash = "sha256:28e552a060ba2740d0d2aabe35162652c1459a0b9069fe0db7f4ee0e18e74d58"}, - {file = "pydantic-1.10.15.tar.gz", hash = "sha256:ca832e124eda231a60a041da4f013e3ff24949d94a01154b137fc2f2a43c3ffb"}, + {file = "pydantic-1.10.19-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a415b9e95fa602b10808113967f72b2da8722061265d6af69268c111c254832d"}, + {file = "pydantic-1.10.19-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:11965f421f7eb026439d4eb7464e9182fe6d69c3d4d416e464a4485d1ba61ab6"}, + {file = "pydantic-1.10.19-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5bb81fcfc6d5bff62cd786cbd87480a11d23f16d5376ad2e057c02b3b44df96"}, + {file = "pydantic-1.10.19-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83ee8c9916689f8e6e7d90161e6663ac876be2efd32f61fdcfa3a15e87d4e413"}, + {file = "pydantic-1.10.19-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0399094464ae7f28482de22383e667625e38e1516d6b213176df1acdd0c477ea"}, + {file = "pydantic-1.10.19-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8b2cf5e26da84f2d2dee3f60a3f1782adedcee785567a19b68d0af7e1534bd1f"}, + {file = "pydantic-1.10.19-cp310-cp310-win_amd64.whl", hash = "sha256:1fc8cc264afaf47ae6a9bcbd36c018d0c6b89293835d7fb0e5e1a95898062d59"}, + {file = "pydantic-1.10.19-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d7a8a1dd68bac29f08f0a3147de1885f4dccec35d4ea926e6e637fac03cdb4b3"}, + {file = "pydantic-1.10.19-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:07d00ca5ef0de65dd274005433ce2bb623730271d495a7d190a91c19c5679d34"}, + {file = "pydantic-1.10.19-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad57004e5d73aee36f1e25e4e73a4bc853b473a1c30f652dc8d86b0a987ffce3"}, + {file = "pydantic-1.10.19-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dce355fe7ae53e3090f7f5fa242423c3a7b53260747aa398b4b3aaf8b25f41c3"}, + {file = "pydantic-1.10.19-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:0d32227ea9a3bf537a2273fd2fdb6d64ab4d9b83acd9e4e09310a777baaabb98"}, + {file = "pydantic-1.10.19-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e351df83d1c9cffa53d4e779009a093be70f1d5c6bb7068584086f6a19042526"}, + {file = "pydantic-1.10.19-cp311-cp311-win_amd64.whl", hash = "sha256:d8d72553d2f3f57ce547de4fa7dc8e3859927784ab2c88343f1fc1360ff17a08"}, + {file = "pydantic-1.10.19-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d5b5b7c6bafaef90cbb7dafcb225b763edd71d9e22489647ee7df49d6d341890"}, + {file = "pydantic-1.10.19-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:570ad0aeaf98b5e33ff41af75aba2ef6604ee25ce0431ecd734a28e74a208555"}, + {file = "pydantic-1.10.19-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0890fbd7fec9e151c7512941243d830b2d6076d5df159a2030952d480ab80a4e"}, + {file = "pydantic-1.10.19-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ec5c44e6e9eac5128a9bfd21610df3b8c6b17343285cc185105686888dc81206"}, + {file = "pydantic-1.10.19-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6eb56074b11a696e0b66c7181da682e88c00e5cebe6570af8013fcae5e63e186"}, + {file = "pydantic-1.10.19-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9d7d48fbc5289efd23982a0d68e973a1f37d49064ccd36d86de4543aff21e086"}, + {file = "pydantic-1.10.19-cp312-cp312-win_amd64.whl", hash = "sha256:fd34012691fbd4e67bdf4accb1f0682342101015b78327eaae3543583fcd451e"}, + {file = "pydantic-1.10.19-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4a5d5b877c7d3d9e17399571a8ab042081d22fe6904416a8b20f8af5909e6c8f"}, + {file = "pydantic-1.10.19-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c46f58ef2df958ed2ea7437a8be0897d5efe9ee480818405338c7da88186fb3"}, + {file = "pydantic-1.10.19-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6d8a38a44bb6a15810084316ed69c854a7c06e0c99c5429f1d664ad52cec353c"}, + {file = "pydantic-1.10.19-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a82746c6d6e91ca17e75f7f333ed41d70fce93af520a8437821dec3ee52dfb10"}, + {file = "pydantic-1.10.19-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:566bebdbe6bc0ac593fa0f67d62febbad9f8be5433f686dc56401ba4aab034e3"}, + {file = "pydantic-1.10.19-cp37-cp37m-win_amd64.whl", hash = "sha256:22a1794e01591884741be56c6fba157c4e99dcc9244beb5a87bd4aa54b84ea8b"}, + {file = "pydantic-1.10.19-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:076c49e24b73d346c45f9282d00dbfc16eef7ae27c970583d499f11110d9e5b0"}, + {file = "pydantic-1.10.19-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5d4320510682d5a6c88766b2a286d03b87bd3562bf8d78c73d63bab04b21e7b4"}, + {file = "pydantic-1.10.19-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e66aa0fa7f8aa9d0a620361834f6eb60d01d3e9cea23ca1a92cda99e6f61dac"}, + {file = "pydantic-1.10.19-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d216f8d0484d88ab72ab45d699ac669fe031275e3fa6553e3804e69485449fa0"}, + {file = "pydantic-1.10.19-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9f28a81978e936136c44e6a70c65bde7548d87f3807260f73aeffbf76fb94c2f"}, + {file = "pydantic-1.10.19-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d3449633c207ec3d2d672eedb3edbe753e29bd4e22d2e42a37a2c1406564c20f"}, + {file = "pydantic-1.10.19-cp38-cp38-win_amd64.whl", hash = "sha256:7ea24e8614f541d69ea72759ff635df0e612b7dc9d264d43f51364df310081a3"}, + {file = "pydantic-1.10.19-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:573254d844f3e64093f72fcd922561d9c5696821ff0900a0db989d8c06ab0c25"}, + {file = "pydantic-1.10.19-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ff09600cebe957ecbb4a27496fe34c1d449e7957ed20a202d5029a71a8af2e35"}, + {file = "pydantic-1.10.19-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4739c206bfb6bb2bdc78dcd40bfcebb2361add4ceac6d170e741bb914e9eff0f"}, + {file = "pydantic-1.10.19-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0bfb5b378b78229119d66ced6adac2e933c67a0aa1d0a7adffbe432f3ec14ce4"}, + {file = "pydantic-1.10.19-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7f31742c95e3f9443b8c6fa07c119623e61d76603be9c0d390bcf7e888acabcb"}, + {file = "pydantic-1.10.19-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c6444368b651a14c2ce2fb22145e1496f7ab23cbdb978590d47c8d34a7bc0289"}, + {file = "pydantic-1.10.19-cp39-cp39-win_amd64.whl", hash = "sha256:945407f4d08cd12485757a281fca0e5b41408606228612f421aa4ea1b63a095d"}, + {file = "pydantic-1.10.19-py3-none-any.whl", hash = "sha256:2206a1752d9fac011e95ca83926a269fb0ef5536f7e053966d058316e24d929f"}, + {file = "pydantic-1.10.19.tar.gz", hash = "sha256:fea36c2065b7a1d28c6819cc2e93387b43dd5d3cf5a1e82d8132ee23f36d1f10"}, ] [package.dependencies] @@ -1573,13 +2103,13 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyjwt" -version = "2.9.0" +version = "2.10.1" description = "JSON Web Token implementation in Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "PyJWT-2.9.0-py3-none-any.whl", hash = "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850"}, - {file = "pyjwt-2.9.0.tar.gz", hash = "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c"}, + {file = "PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb"}, + {file = "pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953"}, ] [package.extras] @@ -1602,37 +2132,37 @@ files = [ [[package]] name = "pytest" -version = "8.2.1" +version = "8.3.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.2.1-py3-none-any.whl", hash = "sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1"}, - {file = "pytest-8.2.1.tar.gz", hash = "sha256:5046e5b46d8e4cac199c373041f26be56fdb81eb4e67dc11d4e10811fc3408fd"}, + {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, + {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, ] [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} iniconfig = "*" packaging = "*" -pluggy = ">=1.5,<2.0" +pluggy = ">=1.5,<2" [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-cov" -version = "5.0.0" +version = "6.0.0" description = "Pytest plugin for measuring coverage." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, - {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, + {file = "pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0"}, + {file = "pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35"}, ] [package.dependencies] -coverage = {version = ">=5.2.1", extras = ["toml"]} +coverage = {version = ">=7.5", extras = ["toml"]} pytest = ">=4.6" [package.extras] @@ -1671,13 +2201,75 @@ six = ">=1.5" [[package]] name = "pytz" -version = "2024.1" +version = "2024.2" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" files = [ - {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, - {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, + {file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"}, + {file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] [[package]] @@ -1706,13 +2298,13 @@ redis = "2.10.6" [[package]] name = "requests" -version = "2.32.0" +version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" files = [ - {file = "requests-2.32.0-py3-none-any.whl", hash = "sha256:f2c3881dddb70d056c5bd7600a4fae312b2a300e39be6a118d30b90bd27262b5"}, - {file = "requests-2.32.0.tar.gz", hash = "sha256:fa5490319474c82ef1d2c9bc459d3652e3ae4ef4c4ebdd18a21145a47ca4b6b8"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] @@ -1756,13 +2348,13 @@ pyasn1 = ">=0.1.3" [[package]] name = "s3transfer" -version = "0.10.1" +version = "0.10.4" description = "An Amazon S3 Transfer Manager" optional = false -python-versions = ">= 3.8" +python-versions = ">=3.8" files = [ - {file = "s3transfer-0.10.1-py3-none-any.whl", hash = "sha256:ceb252b11bcf87080fb7850a224fb6e05c8a776bab8f2b64b7f25b969464839d"}, - {file = "s3transfer-0.10.1.tar.gz", hash = "sha256:5683916b4c724f799e600f41dd9e10a9ff19871bf87623cc8f491cb4f5fa0a19"}, + {file = "s3transfer-0.10.4-py3-none-any.whl", hash = "sha256:244a76a24355363a68164241438de1b72f8781664920260c48465896b712a41e"}, + {file = "s3transfer-0.10.4.tar.gz", hash = "sha256:29edc09801743c21eb5ecbc617a152df41d3c287f67b615f73e5f750583666a7"}, ] [package.dependencies] @@ -1773,47 +2365,47 @@ crt = ["botocore[crt] (>=1.33.2,<2.0a.0)"] [[package]] name = "selenium" -version = "4.23.0" +version = "4.27.1" description = "Official Python bindings for Selenium WebDriver" optional = false python-versions = ">=3.8" files = [ - {file = "selenium-4.23.0-py3-none-any.whl", hash = "sha256:3fa5124c8ba071a2d22f7512a80e7799f5a5492d5e20ada1909fe66a476b2a44"}, - {file = "selenium-4.23.0.tar.gz", hash = "sha256:88f36e3fe6d1d3a9e0626f527f4bd00f0300d43e93f51f59771a911078d4f472"}, + {file = "selenium-4.27.1-py3-none-any.whl", hash = "sha256:b89b1f62b5cfe8025868556fe82360d6b649d464f75d2655cb966c8f8447ea18"}, + {file = "selenium-4.27.1.tar.gz", hash = "sha256:5296c425a75ff1b44d0d5199042b36a6d1ef76c04fb775b97b40be739a9caae2"}, ] [package.dependencies] certifi = ">=2021.10.8" trio = ">=0.17,<1.0" trio-websocket = ">=0.9,<1.0" -typing_extensions = ">=4.9.0,<4.10.0" +typing_extensions = ">=4.9,<5.0" urllib3 = {version = ">=1.26,<3", extras = ["socks"]} -websocket-client = "1.8.0" +websocket-client = ">=1.8,<2.0" [[package]] name = "setuptools" -version = "70.1.0" +version = "70.3.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-70.1.0-py3-none-any.whl", hash = "sha256:d9b8b771455a97c8a9f3ab3448ebe0b29b5e105f1228bba41028be116985a267"}, - {file = "setuptools-70.1.0.tar.gz", hash = "sha256:01a1e793faa5bd89abc851fa15d0a0db26f160890c7102cd8dce643e886b47f5"}, + {file = "setuptools-70.3.0-py3-none-any.whl", hash = "sha256:fe384da74336c398e0d956d1cae0669bc02eed936cdb1d49b57de1990dc11ffc"}, + {file = "setuptools-70.3.0.tar.gz", hash = "sha256:f171bab1dfbc86b132997f26a119f6056a57950d058587841a0082e8830f9dc5"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" -version = "1.16.0" +version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] [[package]] @@ -1851,102 +2443,102 @@ files = [ [[package]] name = "sphinx" -version = "7.3.7" +version = "8.1.3" description = "Python documentation generator" optional = true -python-versions = ">=3.9" +python-versions = ">=3.10" files = [ - {file = "sphinx-7.3.7-py3-none-any.whl", hash = "sha256:413f75440be4cacf328f580b4274ada4565fb2187d696a84970c23f77b64d8c3"}, - {file = "sphinx-7.3.7.tar.gz", hash = "sha256:a4a7db75ed37531c05002d56ed6948d4c42f473a36f46e1382b0bd76ca9627bc"}, + {file = "sphinx-8.1.3-py3-none-any.whl", hash = "sha256:09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2"}, + {file = "sphinx-8.1.3.tar.gz", hash = "sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927"}, ] [package.dependencies] -alabaster = ">=0.7.14,<0.8.0" -babel = ">=2.9" -colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} -docutils = ">=0.18.1,<0.22" +alabaster = ">=0.7.14" +babel = ">=2.13" +colorama = {version = ">=0.4.6", markers = "sys_platform == \"win32\""} +docutils = ">=0.20,<0.22" imagesize = ">=1.3" -Jinja2 = ">=3.0" -packaging = ">=21.0" -Pygments = ">=2.14" -requests = ">=2.25.0" -snowballstemmer = ">=2.0" -sphinxcontrib-applehelp = "*" -sphinxcontrib-devhelp = "*" -sphinxcontrib-htmlhelp = ">=2.0.0" -sphinxcontrib-jsmath = "*" -sphinxcontrib-qthelp = "*" +Jinja2 = ">=3.1" +packaging = ">=23.0" +Pygments = ">=2.17" +requests = ">=2.30.0" +snowballstemmer = ">=2.2" +sphinxcontrib-applehelp = ">=1.0.7" +sphinxcontrib-devhelp = ">=1.0.6" +sphinxcontrib-htmlhelp = ">=2.0.6" +sphinxcontrib-jsmath = ">=1.0.1" +sphinxcontrib-qthelp = ">=1.0.6" sphinxcontrib-serializinghtml = ">=1.1.9" [package.extras] docs = ["sphinxcontrib-websupport"] -lint = ["flake8 (>=3.5.0)", "importlib_metadata", "mypy (==1.9.0)", "pytest (>=6.0)", "ruff (==0.3.7)", "sphinx-lint", "tomli", "types-docutils", "types-requests"] -test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=6.0)", "setuptools (>=67.0)"] +lint = ["flake8 (>=6.0)", "mypy (==1.11.1)", "pyright (==1.1.384)", "pytest (>=6.0)", "ruff (==0.6.9)", "sphinx-lint (>=0.9)", "tomli (>=2)", "types-Pillow (==10.2.0.20240822)", "types-Pygments (==2.18.0.20240506)", "types-colorama (==0.4.15.20240311)", "types-defusedxml (==0.7.0.20240218)", "types-docutils (==0.21.0.20241005)", "types-requests (==2.32.0.20240914)", "types-urllib3 (==1.26.25.14)"] +test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=8.0)", "setuptools (>=70.0)", "typing_extensions (>=4.9)"] [[package]] name = "sphinx-autodoc-typehints" -version = "2.1.0" +version = "2.5.0" description = "Type hints (PEP 484) support for the Sphinx autodoc extension" optional = true -python-versions = ">=3.9" +python-versions = ">=3.10" files = [ - {file = "sphinx_autodoc_typehints-2.1.0-py3-none-any.whl", hash = "sha256:46f1a710b3ed35904f63a77c5e68334c5ee1c2e22828b75fdcd147f1c52c199b"}, - {file = "sphinx_autodoc_typehints-2.1.0.tar.gz", hash = "sha256:51bf8dc77c4fba747e32f0735002a91500747d0553cae616863848e8f5e49fe8"}, + {file = "sphinx_autodoc_typehints-2.5.0-py3-none-any.whl", hash = "sha256:53def4753239683835b19bfa8b68c021388bd48a096efcb02cdab508ece27363"}, + {file = "sphinx_autodoc_typehints-2.5.0.tar.gz", hash = "sha256:259e1026b218d563d72743f417fcc25906a9614897fe37f91bd8d7d58f748c3b"}, ] [package.dependencies] -sphinx = ">=7.3.5" +sphinx = ">=8.0.2" [package.extras] -docs = ["furo (>=2024.1.29)"] +docs = ["furo (>=2024.8.6)"] numpy = ["nptyping (>=2.5)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.4.4)", "defusedxml (>=0.7.1)", "diff-cover (>=9)", "pytest (>=8.1.1)", "pytest-cov (>=5)", "sphobjinv (>=2.3.1)", "typing-extensions (>=4.11)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "defusedxml (>=0.7.1)", "diff-cover (>=9.1.1)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "sphobjinv (>=2.3.1.1)", "typing-extensions (>=4.12.2)"] [[package]] name = "sphinxcontrib-applehelp" -version = "1.0.8" +version = "2.0.0" description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" optional = true python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_applehelp-1.0.8-py3-none-any.whl", hash = "sha256:cb61eb0ec1b61f349e5cc36b2028e9e7ca765be05e49641c97241274753067b4"}, - {file = "sphinxcontrib_applehelp-1.0.8.tar.gz", hash = "sha256:c40a4f96f3776c4393d933412053962fac2b84f4c99a7982ba42e09576a70619"}, + {file = "sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5"}, + {file = "sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1"}, ] [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-devhelp" -version = "1.0.6" +version = "2.0.0" description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" optional = true python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_devhelp-1.0.6-py3-none-any.whl", hash = "sha256:6485d09629944511c893fa11355bda18b742b83a2b181f9a009f7e500595c90f"}, - {file = "sphinxcontrib_devhelp-1.0.6.tar.gz", hash = "sha256:9893fd3f90506bc4b97bdb977ceb8fbd823989f4316b28c3841ec128544372d3"}, + {file = "sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2"}, + {file = "sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad"}, ] [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-htmlhelp" -version = "2.0.5" +version = "2.1.0" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" optional = true python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_htmlhelp-2.0.5-py3-none-any.whl", hash = "sha256:393f04f112b4d2f53d93448d4bce35842f62b307ccdc549ec1585e950bc35e04"}, - {file = "sphinxcontrib_htmlhelp-2.0.5.tar.gz", hash = "sha256:0dc87637d5de53dd5eec3a6a01753b1ccf99494bd756aafecd74b4fa9e729015"}, + {file = "sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8"}, + {file = "sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9"}, ] [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] standalone = ["Sphinx (>=5)"] test = ["html5lib", "pytest"] @@ -1966,45 +2558,45 @@ test = ["flake8", "mypy", "pytest"] [[package]] name = "sphinxcontrib-qthelp" -version = "1.0.7" +version = "2.0.0" description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" optional = true python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_qthelp-1.0.7-py3-none-any.whl", hash = "sha256:e2ae3b5c492d58fcbd73281fbd27e34b8393ec34a073c792642cd8e529288182"}, - {file = "sphinxcontrib_qthelp-1.0.7.tar.gz", hash = "sha256:053dedc38823a80a7209a80860b16b722e9e0209e32fea98c90e4e6624588ed6"}, + {file = "sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb"}, + {file = "sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab"}, ] [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] standalone = ["Sphinx (>=5)"] -test = ["pytest"] +test = ["defusedxml (>=0.7.1)", "pytest"] [[package]] name = "sphinxcontrib-serializinghtml" -version = "1.1.10" +version = "2.0.0" description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" optional = true python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_serializinghtml-1.1.10-py3-none-any.whl", hash = "sha256:326369b8df80a7d2d8d7f99aa5ac577f51ea51556ed974e7716cfd4fca3f6cb7"}, - {file = "sphinxcontrib_serializinghtml-1.1.10.tar.gz", hash = "sha256:93f3f5dc458b91b192fe10c397e324f262cf163d79f3282c158e8436a2c4511f"}, + {file = "sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331"}, + {file = "sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d"}, ] [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-websupport" -version = "1.2.7" +version = "2.0.0" description = "sphinxcontrib-websupport provides a Python API to easily integrate Sphinx documentation into your Web application" optional = true python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_websupport-1.2.7-py3-none-any.whl", hash = "sha256:2dc179d7f821ebd54f31f93c894ca52435ebc5364e4e4dfb0da834ac119d51fd"}, - {file = "sphinxcontrib_websupport-1.2.7.tar.gz", hash = "sha256:e322802ebfd5fe79368efd864aeb87b063566ae61911dccb2714e28a45ed7561"}, + {file = "sphinxcontrib_websupport-2.0.0-py3-none-any.whl", hash = "sha256:365b4da67e03cc163dc4752ed44b3c4bc334172c8198102135a7eb7945111229"}, + {file = "sphinxcontrib_websupport-2.0.0.tar.gz", hash = "sha256:0b7367d3bac6454b1f97e42aa8c4d4d4a1b756d525fc726ebbe5571e033e79cd"}, ] [package.dependencies] @@ -2013,70 +2605,78 @@ Sphinx = ">=5" sphinxcontrib-serializinghtml = "*" [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] test = ["pytest"] whoosh = ["sqlalchemy", "whoosh"] [[package]] name = "sqlalchemy" -version = "2.0.30" +version = "2.0.36" description = "Database Abstraction Library" optional = false python-versions = ">=3.7" files = [ - {file = "SQLAlchemy-2.0.30-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3b48154678e76445c7ded1896715ce05319f74b1e73cf82d4f8b59b46e9c0ddc"}, - {file = "SQLAlchemy-2.0.30-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2753743c2afd061bb95a61a51bbb6a1a11ac1c44292fad898f10c9839a7f75b2"}, - {file = "SQLAlchemy-2.0.30-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7bfc726d167f425d4c16269a9a10fe8630ff6d14b683d588044dcef2d0f6be7"}, - {file = "SQLAlchemy-2.0.30-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4f61ada6979223013d9ab83a3ed003ded6959eae37d0d685db2c147e9143797"}, - {file = "SQLAlchemy-2.0.30-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a365eda439b7a00732638f11072907c1bc8e351c7665e7e5da91b169af794af"}, - {file = "SQLAlchemy-2.0.30-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bba002a9447b291548e8d66fd8c96a6a7ed4f2def0bb155f4f0a1309fd2735d5"}, - {file = "SQLAlchemy-2.0.30-cp310-cp310-win32.whl", hash = "sha256:0138c5c16be3600923fa2169532205d18891b28afa817cb49b50e08f62198bb8"}, - {file = "SQLAlchemy-2.0.30-cp310-cp310-win_amd64.whl", hash = "sha256:99650e9f4cf3ad0d409fed3eec4f071fadd032e9a5edc7270cd646a26446feeb"}, - {file = "SQLAlchemy-2.0.30-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:955991a09f0992c68a499791a753523f50f71a6885531568404fa0f231832aa0"}, - {file = "SQLAlchemy-2.0.30-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f69e4c756ee2686767eb80f94c0125c8b0a0b87ede03eacc5c8ae3b54b99dc46"}, - {file = "SQLAlchemy-2.0.30-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69c9db1ce00e59e8dd09d7bae852a9add716efdc070a3e2068377e6ff0d6fdaa"}, - {file = "SQLAlchemy-2.0.30-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1429a4b0f709f19ff3b0cf13675b2b9bfa8a7e79990003207a011c0db880a13"}, - {file = "SQLAlchemy-2.0.30-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:efedba7e13aa9a6c8407c48facfdfa108a5a4128e35f4c68f20c3407e4376aa9"}, - {file = "SQLAlchemy-2.0.30-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:16863e2b132b761891d6c49f0a0f70030e0bcac4fd208117f6b7e053e68668d0"}, - {file = "SQLAlchemy-2.0.30-cp311-cp311-win32.whl", hash = "sha256:2ecabd9ccaa6e914e3dbb2aa46b76dede7eadc8cbf1b8083c94d936bcd5ffb49"}, - {file = "SQLAlchemy-2.0.30-cp311-cp311-win_amd64.whl", hash = "sha256:0b3f4c438e37d22b83e640f825ef0f37b95db9aa2d68203f2c9549375d0b2260"}, - {file = "SQLAlchemy-2.0.30-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5a79d65395ac5e6b0c2890935bad892eabb911c4aa8e8015067ddb37eea3d56c"}, - {file = "SQLAlchemy-2.0.30-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9a5baf9267b752390252889f0c802ea13b52dfee5e369527da229189b8bd592e"}, - {file = "SQLAlchemy-2.0.30-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cb5a646930c5123f8461f6468901573f334c2c63c795b9af350063a736d0134"}, - {file = "SQLAlchemy-2.0.30-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:296230899df0b77dec4eb799bcea6fbe39a43707ce7bb166519c97b583cfcab3"}, - {file = "SQLAlchemy-2.0.30-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c62d401223f468eb4da32627bffc0c78ed516b03bb8a34a58be54d618b74d472"}, - {file = "SQLAlchemy-2.0.30-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3b69e934f0f2b677ec111b4d83f92dc1a3210a779f69bf905273192cf4ed433e"}, - {file = "SQLAlchemy-2.0.30-cp312-cp312-win32.whl", hash = "sha256:77d2edb1f54aff37e3318f611637171e8ec71472f1fdc7348b41dcb226f93d90"}, - {file = "SQLAlchemy-2.0.30-cp312-cp312-win_amd64.whl", hash = "sha256:b6c7ec2b1f4969fc19b65b7059ed00497e25f54069407a8701091beb69e591a5"}, - {file = "SQLAlchemy-2.0.30-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5a8e3b0a7e09e94be7510d1661339d6b52daf202ed2f5b1f9f48ea34ee6f2d57"}, - {file = "SQLAlchemy-2.0.30-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b60203c63e8f984df92035610c5fb76d941254cf5d19751faab7d33b21e5ddc0"}, - {file = "SQLAlchemy-2.0.30-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1dc3eabd8c0232ee8387fbe03e0a62220a6f089e278b1f0aaf5e2d6210741ad"}, - {file = "SQLAlchemy-2.0.30-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:40ad017c672c00b9b663fcfcd5f0864a0a97828e2ee7ab0c140dc84058d194cf"}, - {file = "SQLAlchemy-2.0.30-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e42203d8d20dc704604862977b1470a122e4892791fe3ed165f041e4bf447a1b"}, - {file = "SQLAlchemy-2.0.30-cp37-cp37m-win32.whl", hash = "sha256:2a4f4da89c74435f2bc61878cd08f3646b699e7d2eba97144030d1be44e27584"}, - {file = "SQLAlchemy-2.0.30-cp37-cp37m-win_amd64.whl", hash = "sha256:b6bf767d14b77f6a18b6982cbbf29d71bede087edae495d11ab358280f304d8e"}, - {file = "SQLAlchemy-2.0.30-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bc0c53579650a891f9b83fa3cecd4e00218e071d0ba00c4890f5be0c34887ed3"}, - {file = "SQLAlchemy-2.0.30-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:311710f9a2ee235f1403537b10c7687214bb1f2b9ebb52702c5aa4a77f0b3af7"}, - {file = "SQLAlchemy-2.0.30-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:408f8b0e2c04677e9c93f40eef3ab22f550fecb3011b187f66a096395ff3d9fd"}, - {file = "SQLAlchemy-2.0.30-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37a4b4fb0dd4d2669070fb05b8b8824afd0af57587393015baee1cf9890242d9"}, - {file = "SQLAlchemy-2.0.30-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a943d297126c9230719c27fcbbeab57ecd5d15b0bd6bfd26e91bfcfe64220621"}, - {file = "SQLAlchemy-2.0.30-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0a089e218654e740a41388893e090d2e2c22c29028c9d1353feb38638820bbeb"}, - {file = "SQLAlchemy-2.0.30-cp38-cp38-win32.whl", hash = "sha256:fa561138a64f949f3e889eb9ab8c58e1504ab351d6cf55259dc4c248eaa19da6"}, - {file = "SQLAlchemy-2.0.30-cp38-cp38-win_amd64.whl", hash = "sha256:7d74336c65705b986d12a7e337ba27ab2b9d819993851b140efdf029248e818e"}, - {file = "SQLAlchemy-2.0.30-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ae8c62fe2480dd61c532ccafdbce9b29dacc126fe8be0d9a927ca3e699b9491a"}, - {file = "SQLAlchemy-2.0.30-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2383146973a15435e4717f94c7509982770e3e54974c71f76500a0136f22810b"}, - {file = "SQLAlchemy-2.0.30-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8409de825f2c3b62ab15788635ccaec0c881c3f12a8af2b12ae4910a0a9aeef6"}, - {file = "SQLAlchemy-2.0.30-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0094c5dc698a5f78d3d1539853e8ecec02516b62b8223c970c86d44e7a80f6c7"}, - {file = "SQLAlchemy-2.0.30-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:edc16a50f5e1b7a06a2dcc1f2205b0b961074c123ed17ebda726f376a5ab0953"}, - {file = "SQLAlchemy-2.0.30-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f7703c2010355dd28f53deb644a05fc30f796bd8598b43f0ba678878780b6e4c"}, - {file = "SQLAlchemy-2.0.30-cp39-cp39-win32.whl", hash = "sha256:1f9a727312ff6ad5248a4367358e2cf7e625e98b1028b1d7ab7b806b7d757513"}, - {file = "SQLAlchemy-2.0.30-cp39-cp39-win_amd64.whl", hash = "sha256:a0ef36b28534f2a5771191be6edb44cc2673c7b2edf6deac6562400288664221"}, - {file = "SQLAlchemy-2.0.30-py3-none-any.whl", hash = "sha256:7108d569d3990c71e26a42f60474b4c02c8586c4681af5fd67e51a044fdea86a"}, - {file = "SQLAlchemy-2.0.30.tar.gz", hash = "sha256:2b1708916730f4830bc69d6f49d37f7698b5bd7530aca7f04f785f8849e95255"}, -] - -[package.dependencies] -greenlet = {version = "!=0.4.17", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""} + {file = "SQLAlchemy-2.0.36-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:59b8f3adb3971929a3e660337f5dacc5942c2cdb760afcabb2614ffbda9f9f72"}, + {file = "SQLAlchemy-2.0.36-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37350015056a553e442ff672c2d20e6f4b6d0b2495691fa239d8aa18bb3bc908"}, + {file = "SQLAlchemy-2.0.36-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8318f4776c85abc3f40ab185e388bee7a6ea99e7fa3a30686580b209eaa35c08"}, + {file = "SQLAlchemy-2.0.36-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c245b1fbade9c35e5bd3b64270ab49ce990369018289ecfde3f9c318411aaa07"}, + {file = "SQLAlchemy-2.0.36-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:69f93723edbca7342624d09f6704e7126b152eaed3cdbb634cb657a54332a3c5"}, + {file = "SQLAlchemy-2.0.36-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f9511d8dd4a6e9271d07d150fb2f81874a3c8c95e11ff9af3a2dfc35fe42ee44"}, + {file = "SQLAlchemy-2.0.36-cp310-cp310-win32.whl", hash = "sha256:c3f3631693003d8e585d4200730616b78fafd5a01ef8b698f6967da5c605b3fa"}, + {file = "SQLAlchemy-2.0.36-cp310-cp310-win_amd64.whl", hash = "sha256:a86bfab2ef46d63300c0f06936bd6e6c0105faa11d509083ba8f2f9d237fb5b5"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fd3a55deef00f689ce931d4d1b23fa9f04c880a48ee97af488fd215cf24e2a6c"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4f5e9cd989b45b73bd359f693b935364f7e1f79486e29015813c338450aa5a71"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0ddd9db6e59c44875211bc4c7953a9f6638b937b0a88ae6d09eb46cced54eff"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2519f3a5d0517fc159afab1015e54bb81b4406c278749779be57a569d8d1bb0d"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59b1ee96617135f6e1d6f275bbe988f419c5178016f3d41d3c0abb0c819f75bb"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:39769a115f730d683b0eb7b694db9789267bcd027326cccc3125e862eb03bfd8"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-win32.whl", hash = "sha256:66bffbad8d6271bb1cc2f9a4ea4f86f80fe5e2e3e501a5ae2a3dc6a76e604e6f"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-win_amd64.whl", hash = "sha256:23623166bfefe1487d81b698c423f8678e80df8b54614c2bf4b4cfcd7c711959"}, + {file = "SQLAlchemy-2.0.36-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7b64e6ec3f02c35647be6b4851008b26cff592a95ecb13b6788a54ef80bbdd4"}, + {file = "SQLAlchemy-2.0.36-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:46331b00096a6db1fdc052d55b101dbbfc99155a548e20a0e4a8e5e4d1362855"}, + {file = "SQLAlchemy-2.0.36-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdf3386a801ea5aba17c6410dd1dc8d39cf454ca2565541b5ac42a84e1e28f53"}, + {file = "SQLAlchemy-2.0.36-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac9dfa18ff2a67b09b372d5db8743c27966abf0e5344c555d86cc7199f7ad83a"}, + {file = "SQLAlchemy-2.0.36-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:90812a8933df713fdf748b355527e3af257a11e415b613dd794512461eb8a686"}, + {file = "SQLAlchemy-2.0.36-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1bc330d9d29c7f06f003ab10e1eaced295e87940405afe1b110f2eb93a233588"}, + {file = "SQLAlchemy-2.0.36-cp312-cp312-win32.whl", hash = "sha256:79d2e78abc26d871875b419e1fd3c0bca31a1cb0043277d0d850014599626c2e"}, + {file = "SQLAlchemy-2.0.36-cp312-cp312-win_amd64.whl", hash = "sha256:b544ad1935a8541d177cb402948b94e871067656b3a0b9e91dbec136b06a2ff5"}, + {file = "SQLAlchemy-2.0.36-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b5cc79df7f4bc3d11e4b542596c03826063092611e481fcf1c9dfee3c94355ef"}, + {file = "SQLAlchemy-2.0.36-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3c01117dd36800f2ecaa238c65365b7b16497adc1522bf84906e5710ee9ba0e8"}, + {file = "SQLAlchemy-2.0.36-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bc633f4ee4b4c46e7adcb3a9b5ec083bf1d9a97c1d3854b92749d935de40b9b"}, + {file = "SQLAlchemy-2.0.36-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e46ed38affdfc95d2c958de328d037d87801cfcbea6d421000859e9789e61c2"}, + {file = "SQLAlchemy-2.0.36-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b2985c0b06e989c043f1dc09d4fe89e1616aadd35392aea2844f0458a989eacf"}, + {file = "SQLAlchemy-2.0.36-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a121d62ebe7d26fec9155f83f8be5189ef1405f5973ea4874a26fab9f1e262c"}, + {file = "SQLAlchemy-2.0.36-cp313-cp313-win32.whl", hash = "sha256:0572f4bd6f94752167adfd7c1bed84f4b240ee6203a95e05d1e208d488d0d436"}, + {file = "SQLAlchemy-2.0.36-cp313-cp313-win_amd64.whl", hash = "sha256:8c78ac40bde930c60e0f78b3cd184c580f89456dd87fc08f9e3ee3ce8765ce88"}, + {file = "SQLAlchemy-2.0.36-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:be9812b766cad94a25bc63bec11f88c4ad3629a0cec1cd5d4ba48dc23860486b"}, + {file = "SQLAlchemy-2.0.36-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50aae840ebbd6cdd41af1c14590e5741665e5272d2fee999306673a1bb1fdb4d"}, + {file = "SQLAlchemy-2.0.36-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4557e1f11c5f653ebfdd924f3f9d5ebfc718283b0b9beebaa5dd6b77ec290971"}, + {file = "SQLAlchemy-2.0.36-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:07b441f7d03b9a66299ce7ccf3ef2900abc81c0db434f42a5694a37bd73870f2"}, + {file = "SQLAlchemy-2.0.36-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:28120ef39c92c2dd60f2721af9328479516844c6b550b077ca450c7d7dc68575"}, + {file = "SQLAlchemy-2.0.36-cp37-cp37m-win32.whl", hash = "sha256:b81ee3d84803fd42d0b154cb6892ae57ea6b7c55d8359a02379965706c7efe6c"}, + {file = "SQLAlchemy-2.0.36-cp37-cp37m-win_amd64.whl", hash = "sha256:f942a799516184c855e1a32fbc7b29d7e571b52612647866d4ec1c3242578fcb"}, + {file = "SQLAlchemy-2.0.36-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3d6718667da04294d7df1670d70eeddd414f313738d20a6f1d1f379e3139a545"}, + {file = "SQLAlchemy-2.0.36-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:72c28b84b174ce8af8504ca28ae9347d317f9dba3999e5981a3cd441f3712e24"}, + {file = "SQLAlchemy-2.0.36-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b11d0cfdd2b095e7b0686cf5fabeb9c67fae5b06d265d8180715b8cfa86522e3"}, + {file = "SQLAlchemy-2.0.36-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e32092c47011d113dc01ab3e1d3ce9f006a47223b18422c5c0d150af13a00687"}, + {file = "SQLAlchemy-2.0.36-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6a440293d802d3011028e14e4226da1434b373cbaf4a4bbb63f845761a708346"}, + {file = "SQLAlchemy-2.0.36-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c54a1e53a0c308a8e8a7dffb59097bff7facda27c70c286f005327f21b2bd6b1"}, + {file = "SQLAlchemy-2.0.36-cp38-cp38-win32.whl", hash = "sha256:1e0d612a17581b6616ff03c8e3d5eff7452f34655c901f75d62bd86449d9750e"}, + {file = "SQLAlchemy-2.0.36-cp38-cp38-win_amd64.whl", hash = "sha256:8958b10490125124463095bbdadda5aa22ec799f91958e410438ad6c97a7b793"}, + {file = "SQLAlchemy-2.0.36-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dc022184d3e5cacc9579e41805a681187650e170eb2fd70e28b86192a479dcaa"}, + {file = "SQLAlchemy-2.0.36-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b817d41d692bf286abc181f8af476c4fbef3fd05e798777492618378448ee689"}, + {file = "SQLAlchemy-2.0.36-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4e46a888b54be23d03a89be510f24a7652fe6ff660787b96cd0e57a4ebcb46d"}, + {file = "SQLAlchemy-2.0.36-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4ae3005ed83f5967f961fd091f2f8c5329161f69ce8480aa8168b2d7fe37f06"}, + {file = "SQLAlchemy-2.0.36-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:03e08af7a5f9386a43919eda9de33ffda16b44eb11f3b313e6822243770e9763"}, + {file = "SQLAlchemy-2.0.36-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3dbb986bad3ed5ceaf090200eba750b5245150bd97d3e67343a3cfed06feecf7"}, + {file = "SQLAlchemy-2.0.36-cp39-cp39-win32.whl", hash = "sha256:9fe53b404f24789b5ea9003fc25b9a3988feddebd7e7b369c8fac27ad6f52f28"}, + {file = "SQLAlchemy-2.0.36-cp39-cp39-win_amd64.whl", hash = "sha256:af148a33ff0349f53512a049c6406923e4e02bf2f26c5fb285f143faf4f0e46a"}, + {file = "SQLAlchemy-2.0.36-py3-none-any.whl", hash = "sha256:fddbe92b4760c6f5d48162aef14824add991aeda8ddadb3c31d56eb15ca69f8e"}, + {file = "sqlalchemy-2.0.36.tar.gz", hash = "sha256:7f2767680b6d2398aea7082e45a774b2b0767b5c8d8ffb9c8b683088ea9b29c5"}, +] + +[package.dependencies] +greenlet = {version = "!=0.4.17", markers = "python_version < \"3.13\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} typing-extensions = ">=4.6.0" [package.extras] @@ -2085,7 +2685,7 @@ aioodbc = ["aioodbc", "greenlet (!=0.4.17)"] aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] asyncio = ["greenlet (!=0.4.17)"] asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (!=0.4.17)"] -mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5)"] +mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5,!=1.1.10)"] mssql = ["pyodbc"] mssql-pymssql = ["pymssql"] mssql-pyodbc = ["pyodbc"] @@ -2104,15 +2704,43 @@ postgresql-psycopgbinary = ["psycopg[binary] (>=3.0.7)"] pymysql = ["pymysql"] sqlcipher = ["sqlcipher3_binary"] +[[package]] +name = "sqlalchemy-citext" +version = "1.8.0" +description = "A sqlalchemy plugin that allows postgres use of CITEXT." +optional = false +python-versions = "*" +files = [ + {file = "sqlalchemy-citext-1.8.0.tar.gz", hash = "sha256:a1740e693a9a334e7c8f60ae731083fe75ce6c1605bb9ca6644a6f1f63b15b77"}, +] + +[package.dependencies] +SQLAlchemy = ">=0.6" + +[[package]] +name = "sqlmodel" +version = "0.0.22" +description = "SQLModel, SQL databases in Python, designed for simplicity, compatibility, and robustness." +optional = false +python-versions = ">=3.7" +files = [ + {file = "sqlmodel-0.0.22-py3-none-any.whl", hash = "sha256:a1ed13e28a1f4057cbf4ff6cdb4fc09e85702621d3259ba17b3c230bfb2f941b"}, + {file = "sqlmodel-0.0.22.tar.gz", hash = "sha256:7d37c882a30c43464d143e35e9ecaf945d88035e20117bf5ec2834a23cbe505e"}, +] + +[package.dependencies] +pydantic = ">=1.10.13,<3.0.0" +SQLAlchemy = ">=2.0.14,<2.1.0" + [[package]] name = "termcolor" -version = "2.4.0" +version = "2.5.0" description = "ANSI color formatting for output in terminal" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "termcolor-2.4.0-py3-none-any.whl", hash = "sha256:9297c0df9c99445c2412e832e882a7884038a25617c60cea2ad69488d4040d63"}, - {file = "termcolor-2.4.0.tar.gz", hash = "sha256:aab9e56047c8ac41ed798fa36d892a37aca6b3e9159f3e0c24bc64a9b3ac7b7a"}, + {file = "termcolor-2.5.0-py3-none-any.whl", hash = "sha256:37b17b5fc1e604945c2642c872a3764b5d547a48009871aea3edd3afa180afb8"}, + {file = "termcolor-2.5.0.tar.gz", hash = "sha256:998d8d27da6d48442e8e1f016119076b690d962507531df4890fcd2db2ef8a6f"}, ] [package.extras] @@ -2120,13 +2748,13 @@ tests = ["pytest", "pytest-cov"] [[package]] name = "trio" -version = "0.26.0" +version = "0.27.0" description = "A friendly Python library for async concurrency and I/O" optional = false python-versions = ">=3.8" files = [ - {file = "trio-0.26.0-py3-none-any.whl", hash = "sha256:bb9c1b259591af941fccfbabbdc65bc7ed764bd2db76428454c894cd5e3d2032"}, - {file = "trio-0.26.0.tar.gz", hash = "sha256:67c5ec3265dd4abc7b1d1ab9ca4fe4c25b896f9c93dac73713778adab487f9c4"}, + {file = "trio-0.27.0-py3-none-any.whl", hash = "sha256:68eabbcf8f457d925df62da780eff15ff5dc68fd6b367e2dde59f7aaf2a0b884"}, + {file = "trio-0.27.0.tar.gz", hash = "sha256:1dcc95ab1726b2da054afea8fd761af74bad79bd52381b84eae408e983c76831"}, ] [package.dependencies] @@ -2152,15 +2780,33 @@ files = [ trio = ">=0.11" wsproto = ">=0.14" +[[package]] +name = "typeguard" +version = "4.4.1" +description = "Run-time type checker for Python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "typeguard-4.4.1-py3-none-any.whl", hash = "sha256:9324ec07a27ec67fc54a9c063020ca4c0ae6abad5e9f0f9804ca59aee68c6e21"}, + {file = "typeguard-4.4.1.tar.gz", hash = "sha256:0d22a89d00b453b47c49875f42b6601b961757541a2e1e0ef517b6e24213c21b"}, +] + +[package.dependencies] +typing-extensions = ">=4.10.0" + +[package.extras] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme (>=1.3.0)"] +test = ["coverage[toml] (>=7)", "mypy (>=1.2.0)", "pytest (>=7)"] + [[package]] name = "types-requests" -version = "2.32.0.20240712" +version = "2.32.0.20241016" description = "Typing stubs for requests" optional = false python-versions = ">=3.8" files = [ - {file = "types-requests-2.32.0.20240712.tar.gz", hash = "sha256:90c079ff05e549f6bf50e02e910210b98b8ff1ebdd18e19c873cd237737c1358"}, - {file = "types_requests-2.32.0.20240712-py3-none-any.whl", hash = "sha256:f754283e152c752e46e70942fa2a146b5bc70393522257bb85bd1ef7e019dcc3"}, + {file = "types-requests-2.32.0.20241016.tar.gz", hash = "sha256:0d9cad2f27515d0e3e3da7134a1b6f28fb97129d86b867f24d9c726452634d95"}, + {file = "types_requests-2.32.0.20241016-py3-none-any.whl", hash = "sha256:4195d62d6d3e043a4eaaf08ff8a62184584d2e8684e9d2aa178c7915a7da3747"}, ] [package.dependencies] @@ -2168,24 +2814,24 @@ urllib3 = ">=2" [[package]] name = "typing-extensions" -version = "4.9.0" +version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, - {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] name = "urllib3" -version = "2.2.2" +version = "2.2.3" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, - {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, + {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, + {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, ] [package.dependencies] @@ -2199,15 +2845,60 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "validators" -version = "0.28.1" +version = "0.34.0" description = "Python Data Validation for Humans™" optional = false python-versions = ">=3.8" files = [ - {file = "validators-0.28.1-py3-none-any.whl", hash = "sha256:890c98789ad884037f059af6ea915ec2d667129d509180c2c590b8009a4c4219"}, - {file = "validators-0.28.1.tar.gz", hash = "sha256:5ac88e7916c3405f0ce38ac2ac82a477fcf4d90dbbeddd04c8193171fc17f7dc"}, + {file = "validators-0.34.0-py3-none-any.whl", hash = "sha256:c804b476e3e6d3786fa07a30073a4ef694e617805eb1946ceee3fe5a9b8b1321"}, + {file = "validators-0.34.0.tar.gz", hash = "sha256:647fe407b45af9a74d245b943b18e6a816acf4926974278f6dd617778e1e781f"}, ] +[package.extras] +crypto-eth-addresses = ["eth-hash[pycryptodome] (>=0.7.0)"] + +[[package]] +name = "watchdog" +version = "6.0.0" +description = "Filesystem events monitoring" +optional = false +python-versions = ">=3.9" +files = [ + {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26"}, + {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112"}, + {file = "watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3"}, + {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c"}, + {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2"}, + {file = "watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c"}, + {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948"}, + {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860"}, + {file = "watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0"}, + {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c"}, + {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134"}, + {file = "watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b"}, + {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8"}, + {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a"}, + {file = "watchdog-6.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c"}, + {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881"}, + {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11"}, + {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa"}, + {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2"}, + {file = "watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a"}, + {file = "watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680"}, + {file = "watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f"}, + {file = "watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282"}, +] + +[package.extras] +watchmedo = ["PyYAML (>=3.10)"] + [[package]] name = "webencodings" version = "0.5.1" @@ -2237,13 +2928,13 @@ test = ["websockets"] [[package]] name = "werkzeug" -version = "3.0.6" +version = "3.1.3" description = "The comprehensive WSGI web application library." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "werkzeug-3.0.6-py3-none-any.whl", hash = "sha256:1bc0c2310d2fbb07b1dd1105eba2f7af72f322e1e455f2f93c993bee8c8a5f17"}, - {file = "werkzeug-3.0.6.tar.gz", hash = "sha256:a8dd59d4de28ca70471a34cba79bed5f7ef2e036a76b3ab0835474246eb41f8d"}, + {file = "werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e"}, + {file = "werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746"}, ] [package.dependencies] @@ -2252,6 +2943,80 @@ MarkupSafe = ">=2.1.1" [package.extras] watchdog = ["watchdog (>=2.3)"] +[[package]] +name = "wrapt" +version = "1.17.0" +description = "Module for decorators, wrappers and monkey patching." +optional = false +python-versions = ">=3.8" +files = [ + {file = "wrapt-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a0c23b8319848426f305f9cb0c98a6e32ee68a36264f45948ccf8e7d2b941f8"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1ca5f060e205f72bec57faae5bd817a1560fcfc4af03f414b08fa29106b7e2d"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e185ec6060e301a7e5f8461c86fb3640a7beb1a0f0208ffde7a65ec4074931df"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb90765dd91aed05b53cd7a87bd7f5c188fcd95960914bae0d32c5e7f899719d"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:879591c2b5ab0a7184258274c42a126b74a2c3d5a329df16d69f9cee07bba6ea"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fce6fee67c318fdfb7f285c29a82d84782ae2579c0e1b385b7f36c6e8074fffb"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0698d3a86f68abc894d537887b9bbf84d29bcfbc759e23f4644be27acf6da301"}, + {file = "wrapt-1.17.0-cp310-cp310-win32.whl", hash = "sha256:69d093792dc34a9c4c8a70e4973a3361c7a7578e9cd86961b2bbf38ca71e4e22"}, + {file = "wrapt-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:f28b29dc158ca5d6ac396c8e0a2ef45c4e97bb7e65522bfc04c989e6fe814575"}, + {file = "wrapt-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:74bf625b1b4caaa7bad51d9003f8b07a468a704e0644a700e936c357c17dd45a"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f2a28eb35cf99d5f5bd12f5dd44a0f41d206db226535b37b0c60e9da162c3ed"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:81b1289e99cf4bad07c23393ab447e5e96db0ab50974a280f7954b071d41b489"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f2939cd4a2a52ca32bc0b359015718472d7f6de870760342e7ba295be9ebaf9"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a9653131bda68a1f029c52157fd81e11f07d485df55410401f745007bd6d339"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4e4b4385363de9052dac1a67bfb535c376f3d19c238b5f36bddc95efae15e12d"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bdf62d25234290db1837875d4dceb2151e4ea7f9fff2ed41c0fde23ed542eb5b"}, + {file = "wrapt-1.17.0-cp311-cp311-win32.whl", hash = "sha256:5d8fd17635b262448ab8f99230fe4dac991af1dabdbb92f7a70a6afac8a7e346"}, + {file = "wrapt-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:92a3d214d5e53cb1db8b015f30d544bc9d3f7179a05feb8f16df713cecc2620a"}, + {file = "wrapt-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:89fc28495896097622c3fc238915c79365dd0ede02f9a82ce436b13bd0ab7569"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:875d240fdbdbe9e11f9831901fb8719da0bd4e6131f83aa9f69b96d18fae7504"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5ed16d95fd142e9c72b6c10b06514ad30e846a0d0917ab406186541fe68b451"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18b956061b8db634120b58f668592a772e87e2e78bc1f6a906cfcaa0cc7991c1"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:daba396199399ccabafbfc509037ac635a6bc18510ad1add8fd16d4739cdd106"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4d63f4d446e10ad19ed01188d6c1e1bb134cde8c18b0aa2acfd973d41fcc5ada"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8a5e7cc39a45fc430af1aefc4d77ee6bad72c5bcdb1322cfde852c15192b8bd4"}, + {file = "wrapt-1.17.0-cp312-cp312-win32.whl", hash = "sha256:0a0a1a1ec28b641f2a3a2c35cbe86c00051c04fffcfcc577ffcdd707df3f8635"}, + {file = "wrapt-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:3c34f6896a01b84bab196f7119770fd8466c8ae3dfa73c59c0bb281e7b588ce7"}, + {file = "wrapt-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:714c12485aa52efbc0fc0ade1e9ab3a70343db82627f90f2ecbc898fdf0bb181"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da427d311782324a376cacb47c1a4adc43f99fd9d996ffc1b3e8529c4074d393"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba1739fb38441a27a676f4de4123d3e858e494fac05868b7a281c0a383c098f4"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e711fc1acc7468463bc084d1b68561e40d1eaa135d8c509a65dd534403d83d7b"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:140ea00c87fafc42739bd74a94a5a9003f8e72c27c47cd4f61d8e05e6dec8721"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:73a96fd11d2b2e77d623a7f26e004cc31f131a365add1ce1ce9a19e55a1eef90"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0b48554952f0f387984da81ccfa73b62e52817a4386d070c75e4db7d43a28c4a"}, + {file = "wrapt-1.17.0-cp313-cp313-win32.whl", hash = "sha256:498fec8da10e3e62edd1e7368f4b24aa362ac0ad931e678332d1b209aec93045"}, + {file = "wrapt-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:fd136bb85f4568fffca995bd3c8d52080b1e5b225dbf1c2b17b66b4c5fa02838"}, + {file = "wrapt-1.17.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:17fcf043d0b4724858f25b8826c36e08f9fb2e475410bece0ec44a22d533da9b"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4a557d97f12813dc5e18dad9fa765ae44ddd56a672bb5de4825527c847d6379"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0229b247b0fc7dee0d36176cbb79dbaf2a9eb7ecc50ec3121f40ef443155fb1d"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8425cfce27b8b20c9b89d77fb50e368d8306a90bf2b6eef2cdf5cd5083adf83f"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9c900108df470060174108012de06d45f514aa4ec21a191e7ab42988ff42a86c"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4e547b447073fc0dbfcbff15154c1be8823d10dab4ad401bdb1575e3fdedff1b"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:914f66f3b6fc7b915d46c1cc424bc2441841083de01b90f9e81109c9759e43ab"}, + {file = "wrapt-1.17.0-cp313-cp313t-win32.whl", hash = "sha256:a4192b45dff127c7d69b3bdfb4d3e47b64179a0b9900b6351859f3001397dabf"}, + {file = "wrapt-1.17.0-cp313-cp313t-win_amd64.whl", hash = "sha256:4f643df3d4419ea3f856c5c3f40fec1d65ea2e89ec812c83f7767c8730f9827a"}, + {file = "wrapt-1.17.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:69c40d4655e078ede067a7095544bcec5a963566e17503e75a3a3e0fe2803b13"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f495b6754358979379f84534f8dd7a43ff8cff2558dcdea4a148a6e713a758f"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:baa7ef4e0886a6f482e00d1d5bcd37c201b383f1d314643dfb0367169f94f04c"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8fc931382e56627ec4acb01e09ce66e5c03c384ca52606111cee50d931a342d"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8f8909cdb9f1b237786c09a810e24ee5e15ef17019f7cecb207ce205b9b5fcce"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ad47b095f0bdc5585bced35bd088cbfe4177236c7df9984b3cc46b391cc60627"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:948a9bd0fb2c5120457b07e59c8d7210cbc8703243225dbd78f4dfc13c8d2d1f"}, + {file = "wrapt-1.17.0-cp38-cp38-win32.whl", hash = "sha256:5ae271862b2142f4bc687bdbfcc942e2473a89999a54231aa1c2c676e28f29ea"}, + {file = "wrapt-1.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:f335579a1b485c834849e9075191c9898e0731af45705c2ebf70e0cd5d58beed"}, + {file = "wrapt-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d751300b94e35b6016d4b1e7d0e7bbc3b5e1751e2405ef908316c2a9024008a1"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7264cbb4a18dc4acfd73b63e4bcfec9c9802614572025bdd44d0721983fc1d9c"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33539c6f5b96cf0b1105a0ff4cf5db9332e773bb521cc804a90e58dc49b10578"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c30970bdee1cad6a8da2044febd824ef6dc4cc0b19e39af3085c763fdec7de33"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:bc7f729a72b16ee21795a943f85c6244971724819819a41ddbaeb691b2dd85ad"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6ff02a91c4fc9b6a94e1c9c20f62ea06a7e375f42fe57587f004d1078ac86ca9"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2dfb7cff84e72e7bf975b06b4989477873dcf160b2fd89959c629535df53d4e0"}, + {file = "wrapt-1.17.0-cp39-cp39-win32.whl", hash = "sha256:2399408ac33ffd5b200480ee858baa58d77dd30e0dd0cab6a8a9547135f30a88"}, + {file = "wrapt-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:4f763a29ee6a20c529496a20a7bcb16a73de27f5da6a843249c7047daf135977"}, + {file = "wrapt-1.17.0-py3-none-any.whl", hash = "sha256:d2c63b93548eda58abf5188e505ffed0229bf675f7c3090f8e36ad55b8cbc371"}, + {file = "wrapt-1.17.0.tar.gz", hash = "sha256:16187aa2317c731170a88ef35e8937ae0f533c402872c1ee5e6d079fcf320801"}, +] + [[package]] name = "wsproto" version = "1.2.0" @@ -2268,13 +3033,13 @@ h11 = ">=0.9.0,<1" [[package]] name = "wtforms" -version = "3.1.2" +version = "3.2.1" description = "Form validation and rendering for Python web development." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "wtforms-3.1.2-py3-none-any.whl", hash = "sha256:bf831c042829c8cdbad74c27575098d541d039b1faa74c771545ecac916f2c07"}, - {file = "wtforms-3.1.2.tar.gz", hash = "sha256:f8d76180d7239c94c6322f7990ae1216dae3659b7aa1cee94b6318bdffb474b9"}, + {file = "wtforms-3.2.1-py3-none-any.whl", hash = "sha256:583bad77ba1dd7286463f21e11aa3043ca4869d03575921d1a1698d0715e0fd4"}, + {file = "wtforms-3.2.1.tar.gz", hash = "sha256:df3e6b70f3192e92623128123ec8dca3067df9cfadd43d59681e210cfb8d4682"}, ] [package.dependencies] @@ -2283,6 +3048,25 @@ markupsafe = "*" [package.extras] email = ["email-validator"] +[[package]] +name = "zipp" +version = "3.21.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.9" +files = [ + {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, + {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, +] + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +type = ["pytest-mypy"] + [extras] postgres = ["psycopg2-binary"] sphinx = ["sphinx", "sphinx-autodoc-typehints", "sphinxcontrib-websupport"] @@ -2290,4 +3074,4 @@ sphinx = ["sphinx", "sphinx-autodoc-typehints", "sphinxcontrib-websupport"] [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "aab728b7c4056cc5d6f2d96dd91d1ee5383a5932ec5cf9079d5986c8ae3376e1" +content-hash = "86ebaf2a3a2806cdf873221f2e2c5ebe204cc75aadfca6e06b2c3f81c45931b4" diff --git a/pyproject.toml b/pyproject.toml index 18e44efac..f4e3edb5a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,8 +54,11 @@ pytest-mock = "^3.8.2" pytest-cov = "*" hypothesis = "*" fakeredis = "*" - click = "*" +sqlmodel = "*" +sqlalchemy-citext = "*" +geoalchemy2 = "*" +pgvector = "*" [tool.poetry.extras] sphinx = [ "sphinx", "sphinxcontrib-websupport", "sphinx-autodoc-typehints" ] @@ -64,6 +67,15 @@ postgres = ["psycopg2-binary"] [tool.poetry.group.dev.dependencies] selenium = "^4.23.0" types-requests = "^2.32.0.20240712" +autopep8 = "^2.3.1" +inflect = "^7.4.0" +sqlmodel = "^0.0.22" +geoalchemy2 = "^0.15.2" +pgvector = "^0.3.5" +black = "^24.10.0" +libcst = "^1.5.0" +functions-framework = "^3.8.1" +google-cloud-bigquery = "^3.26.0" [build-system] requires = ["poetry-core>=1.0.0"] diff --git a/pytest.ini b/pytest.ini index 5c872f0ba..13481194a 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,4 +1,4 @@ [pytest] markers = with_op: marks tests to run with 1password CLI -addopts = -m "not with_op" +addopts = -m "not with_op" --ignore=development/sqlacodegen/tests --ignore=gcp/cloud_functions/aggregate_hourly_downloads/tests