From 2e6f3540c1cd19ffb4b7452de9b891f62546b198 Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Fri, 18 Oct 2024 13:48:13 -0400 Subject: [PATCH 01/32] (1) db.models - When a column type is Python "str" or String type without max length, default to 255. Otherwise, DB other than sqlite3 cannot have VARCHAR without size. (2) Add the schema deployment to MySQL in github action tests so we'd catch the db.model change that doesn't work. --- .github/workflows/pullreqeust_tests.yaml | 27 ++++++++++++++++++++++-- arxiv/db/models.py | 24 +++++++++++++++++++-- arxiv/db/tests/__init__.py | 0 arxiv/db/tests/test_db_schema.py | 23 ++++++++++++++++++++ 4 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 arxiv/db/tests/__init__.py create mode 100644 arxiv/db/tests/test_db_schema.py diff --git a/.github/workflows/pullreqeust_tests.yaml b/.github/workflows/pullreqeust_tests.yaml index 02941053a..ee708332d 100644 --- a/.github/workflows/pullreqeust_tests.yaml +++ b/.github/workflows/pullreqeust_tests.yaml @@ -5,6 +5,21 @@ on: jobs: build: runs-on: ubuntu-latest + services: + mysql: + image: mysql:8.0 + ports: + - 3306:3306 + options: > + --health-cmd="mysqladmin ping --silent" + --health-interval=10s + --health-timeout=5s + --health-retries=3 + env: + MYSQL_ROOT_PASSWORD: password + MYSQL_DATABASE: testdb + MYSQL_USER: testuser + MYSQL_PASSWORD: testpassword steps: - uses: actions/checkout@v2 - name: Install Python 3 @@ -26,18 +41,26 @@ jobs: # TODO The types are in bad shape and need to be fixed # run: poetry run mypy --exclude "test*" -p arxiv - - name: Install Firefox ESR and test driver + - name: Install Firefox ESR, test driver, mysqladmin run: | sudo add-apt-repository -y ppa:mozillateam/ppa sudo apt update - sudo apt install -y firefox-esr + sudo apt install -y firefox-esr mysql-client-core-8.0 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: Wait for MySQL to be ready + run: | + until mysqladmin ping --host=127.0.0.1 --user=testuser --password=testpassword --silent; do + echo "Waiting for MySQL to be ready..." + sleep 2 + done - name: Run other tests # These tests are split out because their coverage is low + env: + TEST_ARXIV_DB_URI: mysql://testuser:testpassword@127.0.0.1/testdb run: poetry run pytest --cov=arxiv --cov-fail-under=25 arxiv #- name: Check Doc Style # run: poetry run pydocstyle --convention=numpy --add-ignore=D401 arxiv diff --git a/arxiv/db/models.py b/arxiv/db/models.py index dec6fe37f..a1af26986 100644 --- a/arxiv/db/models.py +++ b/arxiv/db/models.py @@ -30,7 +30,8 @@ Table, Enum, text, - Engine + Engine, + event as sqlalchemy_event, ) from sqlalchemy.schema import FetchedValue from sqlalchemy.orm import ( @@ -49,6 +50,23 @@ tz = gettz(settings.ARXIV_BUSINESS_TZ) +@sqlalchemy_event.listens_for(Table, "before_create") +def before_create_replace_string_columns(target, connection, **kw): + """ + Make the default string type as VARCHAR(255) for mysql. + + column type Mapped[Optional[str]] works for sqlite3 but not for MySQL or PostgreSQL. + """ + if connection.engine.dialect.name != "sqlite3": + for column in target.columns: + if isinstance(column.type, String) and column.type.length is None: + column.type = String(255) + if isinstance(column.type, str): + column.type = String(255) + else: + pass + + class MemberInstitution(Base): __tablename__ = 'Subscription_UniversalInstitution' @@ -1812,7 +1830,9 @@ class TapirUser(Base): __tablename__ = 'tapir_users' __table_args__ = ( ForeignKeyConstraint(['policy_class'], ['tapir_policy_classes.class_id'], name='0_510'), - Index('email', 'email', unique=True), + # 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'), 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..8104fb61b --- /dev/null +++ b/arxiv/db/tests/test_db_schema.py @@ -0,0 +1,23 @@ +import os +from sqlalchemy import create_engine, text +from sqlalchemy.orm import sessionmaker + +# 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 test_db_schema(): + db_engine = create_engine(os.environ['TEST_ARXIV_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() From ab5d9c646e7605bef5a167d739a28bf8d2fe112d Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Fri, 18 Oct 2024 16:12:01 -0400 Subject: [PATCH 02/32] "It works on my machine" - take 2. --- .github/workflows/pullreqeust_tests.yaml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/pullreqeust_tests.yaml b/.github/workflows/pullreqeust_tests.yaml index ee708332d..b445722a5 100644 --- a/.github/workflows/pullreqeust_tests.yaml +++ b/.github/workflows/pullreqeust_tests.yaml @@ -10,11 +10,6 @@ jobs: image: mysql:8.0 ports: - 3306:3306 - options: > - --health-cmd="mysqladmin ping --silent" - --health-interval=10s - --health-timeout=5s - --health-retries=3 env: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: testdb From 3fd6e0100d43029421dbc85b531cd3aa2eeeb11c Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Sat, 19 Oct 2024 10:43:55 -0400 Subject: [PATCH 03/32] Fix up the models --- arxiv/db/models.py | 131 +++++++++++++++++++-------------------------- 1 file changed, 55 insertions(+), 76 deletions(-) diff --git a/arxiv/db/models.py b/arxiv/db/models.py index a1af26986..beffeb239 100644 --- a/arxiv/db/models.py +++ b/arxiv/db/models.py @@ -9,6 +9,7 @@ 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 ( @@ -31,7 +32,6 @@ Enum, text, Engine, - event as sqlalchemy_event, ) from sqlalchemy.schema import FetchedValue from sqlalchemy.orm import ( @@ -50,45 +50,28 @@ tz = gettz(settings.ARXIV_BUSINESS_TZ) -@sqlalchemy_event.listens_for(Table, "before_create") -def before_create_replace_string_columns(target, connection, **kw): - """ - Make the default string type as VARCHAR(255) for mysql. - - column type Mapped[Optional[str]] works for sqlite3 but not for MySQL or PostgreSQL. - """ - if connection.engine.dialect.name != "sqlite3": - for column in target.columns: - if isinstance(column.type, String) and column.type.length is None: - column.type = String(255) - if isinstance(column.type, str): - column.type = String(255) - else: - pass - - class MemberInstitution(Base): __tablename__ = 'Subscription_UniversalInstitution' - resolver_URL: Mapped[Optional[str]] + resolver_URL: Mapped[Optional[str]] = mapped_column(String(255)) 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' - email: Mapped[Optional[str]] + 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') @@ -147,16 +130,16 @@ 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()) @@ -176,8 +159,6 @@ class AdminMetadata(Base): Column('comment', String(255)) ) - - class ArchiveCategory(Base): __tablename__ = 'arXiv_archive_category' @@ -190,7 +171,7 @@ class ArchiveDef(Base): __tablename__ = 'arXiv_archive_def' 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)) @@ -254,13 +235,13 @@ class BibFeed(Base): 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()) @@ -285,15 +266,13 @@ class BibUpdate(Base): ) - t_arXiv_block_email = Table( 'arXiv_block_email', metadata, Column('pattern', String(64)) ) - -class BogusCountry(Base): +class BogusCountries(Base): __tablename__ = 'arXiv_bogus_countries' user_id: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) @@ -315,7 +294,7 @@ class Category(Base): 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]] + 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'")) @@ -341,7 +320,7 @@ class CategoryDef(Base): __tablename__ = 'arXiv_category_def' 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()) @@ -523,8 +502,8 @@ class EndorsementRequestsAudit(EndorsementRequest): 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)) @@ -578,7 +557,7 @@ 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]] + name: Mapped[Optional[str]] = mapped_column(String(255)) @@ -629,7 +608,7 @@ class License(Base): __tablename__ = 'arXiv_licenses' 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) @@ -664,14 +643,14 @@ class Metadata(Base): 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) version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) @@ -771,7 +750,7 @@ 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()) @@ -1127,12 +1106,12 @@ 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(VARCHAR(255, charset="latin1")) 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) version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) @@ -1201,8 +1180,8 @@ class SubmitterFlag(Base): __tablename__ = 'arXiv_submitter_flags' 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)) @@ -1455,7 +1434,7 @@ class TapirAdminAudit(Base): 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), nullable=False, index=True) comment: Mapped[str] = mapped_column(Text, nullable=False) entry_id: Mapped[intpk] @@ -1477,8 +1456,8 @@ 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]] - new_email: Mapped[Optional[str]] + 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()) @@ -1522,7 +1501,7 @@ class TapirEmailLog(Base): 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()) @@ -1539,7 +1518,7 @@ class TapirEmailMailing(Base): 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') @@ -1779,7 +1758,7 @@ class TapirRecoveryTokensUsed(Base): '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('value', Text, nullable=False), Column('seq', Integer, nullable=False, server_default=FetchedValue()) ) @@ -2054,7 +2033,7 @@ 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)) @@ -2069,7 +2048,7 @@ class DBLaTeXMLSubmissions (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]] conversion_end_time: Mapped[Optional[int]] @@ -2077,15 +2056,15 @@ 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)) def configure_db_engine(classic_engine: Engine, latexml_engine: Optional[Engine]) -> Tuple[Engine, Optional[Engine]]: From 720136a5fe88311667376399ec5a03c7157bdd59 Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Tue, 29 Oct 2024 13:11:47 -0400 Subject: [PATCH 04/32] progress made. save the codegen before reform --- .gitignore | 2 + Makefile | 32 + arxiv/db/arxiv-db-metadata.yaml | 401 ++++ arxiv/db/orig_models.py | 2102 +++++++++++++++++ arxiv/db/tests/testdb.sh | 5 + development/db_codegen.py | 284 +++ development/extract_class_n_table.py | 33 + development/patch_db_models.py | 0 development/sqlacodegen/.gitignore | 15 + development/sqlacodegen/CHANGES.rst | 189 ++ development/sqlacodegen/CONTRIBUTING.rst | 47 + development/sqlacodegen/LICENSE | 19 + development/sqlacodegen/README.rst | 203 ++ development/sqlacodegen/poetry.lock | 879 +++++++ development/sqlacodegen/pyproject.toml | 100 + .../sqlacodegen/src/sqlacodegen/__init__.py | 0 .../sqlacodegen/src/sqlacodegen/__main__.py | 3 + .../sqlacodegen/src/sqlacodegen/cli.py | 120 + .../sqlacodegen/src/sqlacodegen/generators.py | 1542 ++++++++++++ .../sqlacodegen/src/sqlacodegen/models.py | 79 + .../sqlacodegen/src/sqlacodegen/py.typed | 0 .../sqlacodegen/src/sqlacodegen/utils.py | 204 ++ development/sqlacodegen/tests/__init__.py | 0 development/sqlacodegen/tests/conftest.py | 33 + development/sqlacodegen/tests/test_cli.py | 160 ++ .../tests/test_generator_dataclass.py | 270 +++ .../tests/test_generator_declarative.py | 1511 ++++++++++++ .../tests/test_generator_sqlmodel.py | 188 ++ .../tests/test_generator_tables.py | 979 ++++++++ poetry.lock | 80 +- pyproject.toml | 1 + 31 files changed, 9480 insertions(+), 1 deletion(-) create mode 100644 Makefile create mode 100644 arxiv/db/arxiv-db-metadata.yaml create mode 100644 arxiv/db/orig_models.py create mode 100755 arxiv/db/tests/testdb.sh create mode 100644 development/db_codegen.py create mode 100644 development/extract_class_n_table.py create mode 100644 development/patch_db_models.py create mode 100644 development/sqlacodegen/.gitignore create mode 100644 development/sqlacodegen/CHANGES.rst create mode 100644 development/sqlacodegen/CONTRIBUTING.rst create mode 100644 development/sqlacodegen/LICENSE create mode 100644 development/sqlacodegen/README.rst create mode 100644 development/sqlacodegen/poetry.lock create mode 100644 development/sqlacodegen/pyproject.toml create mode 100644 development/sqlacodegen/src/sqlacodegen/__init__.py create mode 100644 development/sqlacodegen/src/sqlacodegen/__main__.py create mode 100644 development/sqlacodegen/src/sqlacodegen/cli.py create mode 100644 development/sqlacodegen/src/sqlacodegen/generators.py create mode 100644 development/sqlacodegen/src/sqlacodegen/models.py create mode 100644 development/sqlacodegen/src/sqlacodegen/py.typed create mode 100644 development/sqlacodegen/src/sqlacodegen/utils.py create mode 100644 development/sqlacodegen/tests/__init__.py create mode 100644 development/sqlacodegen/tests/conftest.py create mode 100644 development/sqlacodegen/tests/test_cli.py create mode 100644 development/sqlacodegen/tests/test_generator_dataclass.py create mode 100644 development/sqlacodegen/tests/test_generator_declarative.py create mode 100644 development/sqlacodegen/tests/test_generator_sqlmodel.py create mode 100644 development/sqlacodegen/tests/test_generator_tables.py diff --git a/.gitignore b/.gitignore index 73366578e..1e5fcb9c1 100644 --- a/.gitignore +++ b/.gitignore @@ -131,3 +131,5 @@ fastly_hourly_stats.ini foo.json test.db-journal + +arxiv/db/.autogen_models.py diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..cbb07721d --- /dev/null +++ b/Makefile @@ -0,0 +1,32 @@ + +.PHONY: db-models + +default: venv/bin/poetry + +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 + +~/.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='*')))" > $@ + +db-models: arxiv/db/autogen_models.py + +arxiv/db/autogen_models.py: arxiv/db/autogen_models_patch.diff ~/.arxiv/arxiv-db-prod-readonly + @PROD_ARXIV_DB_URI=`cat ~/.arxiv/arxiv-db-prod-readonly`; . venv/bin/activate && \ + poetry run sqlacodegen "$$PROD_ARXIV_DB_URI" --outfile arxiv/db/autogen_models.py && \ + poetry run python3 development/patch_db_models.py arxiv/db/autogen_models.py arxiv/db/arxiv_db_metadata.json + patch arxiv/db/autogen_models.py arxiv/db/autogen_models_patch.diff + +arxiv/db/autogen_models_patch.diff: + @PROD_ARXIV_DB_URI=`cat ~/.arxiv/arxiv-db-prod-readonly`; . venv/bin/activate && \ + poetry run sqlacodegen "$$PROD_ARXIV_DB_URI" --outfile arxiv/db/.autogen_models.py + diff -c arxiv/db/.autogen_models.py arxiv/db/autogen_models.py > arxiv/db/autogen_models_patch.diff diff --git a/arxiv/db/arxiv-db-metadata.yaml b/arxiv/db/arxiv-db-metadata.yaml new file mode 100644 index 000000000..ab120f076 --- /dev/null +++ b/arxiv/db/arxiv-db-metadata.yaml @@ -0,0 +1,401 @@ +Subscription_UniversalInstitution: + class_name: MemberInstitution +Subscription_UniversalInstitutionContact: + class_name: MemberInstitutionContact +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 +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 +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'),", ""] + - replace: ["Index('user_id', 'user_id')", ""] + - replace: ["Index('ix_arXiv_cross_control_freeze_date', 'freeze_date'),", "" ] + columns: + freeze_date: "mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue())" +arXiv_datacite_dois: + class_name: DataciteDois + table_args: + - replace: ["Index('metadata_id', 'metadata_id')", ""] + +arXiv_dblp_authors: + class_name: DBLPAuthor + table_args: + - replace: ["Index('author_id', 'author_id'),", ""] + - replace: ["Index('document_id', 'document_id')", ""] +arXiv_dblp_document_authors: + class_name: DBLPDocumentAuthor + table_args: + - replace: ["Index('author_id', 'author_id'),", ""] + - replace: ["Index('document_id', 'document_id')", ""] +arXiv_document_category: + class_name: DocumentCategory + table_args: + - replace: ["Index('category', 'category'),", ""] + - replace: ["Index('document_id', 'document_id')", ""] +arXiv_documents: + class_name: Document +arXiv_dblp: + class_name: DBLP +arXiv_paper_pw: + class_name: PaperPw +arXiv_endorsement_domains: + class_name: EndorsementDomain +arXiv_endorsement_requests: + class_name: EndorsementRequest + table_args: + # Index('archive', 'archive', 'subject_class'), + - replace: ["Index('archive', 'archive', 'subject_class'),", ""] + - replace: ["Index('secret', 'secret', unique=True)", ""] +arXiv_endorsement_requests_audit: + class_name: EndorsementRequestsAudit +arXiv_endorsements: + class_name: Endorsement + table_args: + - replace: ["Index('archive', 'archive', 'subject_class'),", ""] + - replace: ["Index('endorsee_id', 'endorsee_id'),", ""] + - replace: ["Index('endorser_id', 'endorser_id'),", ""] + # - replace: ["Index('endorser_id_2', 'endorser_id', 'endorsee_id', 'archive', 'subject_class', unique=True),", ""] + - replace: ["Index('request_id', 'request_id')", ""] +arXiv_endorsements_audit: + class_name: EndorsementsAudit +arXiv_freeze_log: + class_name: FreezeLog +arXiv_group_def: + class_name: GroupDef +arXiv_groups: + class_name: Group +arXiv_jref_control: + class_name: JrefControl + 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())" + table_args: + - replace: ["Index('arXiv_jref_control_ibfk_1', 'document_id'),", ""] + - replace: ["Index('arXiv_jref_control_ibfk_2', 'user_id'),", ""] + - replace: ["Index('ix_arXiv_jref_control_freeze_date', 'freeze_date'),", ""] + - replace: ["Index('ix_arXiv_jref_control_status', 'status')", ""] +arXiv_licenses: + class_name: License +arXiv_log_positions: + class_name: LogPosition +arXiv_metadata: + class_name: Metadata +# ForeignKeyConstraint( +# ["document_id"], +# ["arXiv_documents.document_id"], +# ondelete="CASCADE", +# onupdate="CASCADE", +# name="arXiv_metadata_fk_document_id", +# ), +# ForeignKeyConstraint( +# ["license"], ["arXiv_licenses.name"], name="arXiv_metadata_fk_license" +# ), +# ForeignKeyConstraint( +# ["submitter_id"], +# ["tapir_users.user_id"], +# name="arXiv_metadata_fk_submitter_id", +# ), +# Index("arXiv_metadata_idx_document_id", "document_id"), +# Index("arXiv_metadata_idx_license", "license"), +# Index("arXiv_metadata_idx_submitter_id", "submitter_id"), +# Index("pidv", "paper_id", "version", unique=True), + table_args: + - replace: ["Index('arXiv_metadata_idx_document_id', 'document_id'),", ""] + - replace: ["Index('arXiv_metadata_idx_license', 'license'),", ""] + - replace: ["Index('arXiv_metadata_idx_submitter_id', 'submitter_id'),", ""] + +arXiv_mirror_list: + class_name: MirrorList +arXiv_moderator_api_key: + class_name: ModeratorApiKey +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: + - replace: ["Index('endorsement_request_id', 'endorsement_request_id'),", ""] + - replace: ["Index('user_id', 'user_id')", ""] +arXiv_ownership_requests_audit: + class_name: OwnershipRequestsAudit +arXiv_paper_owners: + class_name: PaperOwner + table_args: + - replace: ["Index('user_id', 'user_id')", ""] +arXiv_paper_sessions: + class_name: PaperSession +arXiv_pilot_files: + class_name: PilotFile + table_args: + - replace: ["Index('arXiv_pilot_files_cdfk3', 'submission_id')", ""] +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('ix_arXiv_show_email_requests_dated', 'dated'),", ""] + - replace: ["Index('user_id', 'user_id', 'dated')", "Index('email_reqs_user_id', 'user_id', 'dated')"] + columns: + dated: "mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue())" +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 + table_args: + - replace: ["Index('arXiv_submission_category_idx_category', 'category'),", ""] + - replace: ["Index('arXiv_submission_category_idx_submission_id', 'submission_id')", ""] + +arXiv_submission_category_proposal: + class_name: SubmissionCategoryProposal + table_args: + - replace: ["Index('arXiv_submission_category_proposal_fk_prop_comment_id', 'proposal_comment_id'),", ""] + - replace: ["Index('arXiv_submission_category_proposal_fk_resp_comment_id', 'response_comment_id'),", ""] + - replace: ["Index('arXiv_submission_category_proposal_fk_user_id', 'user_id'),", ""] + - replace: ["Index('arXiv_submission_category_proposal_idx_category', 'category'),", ""] + - replace: ["Index('arXiv_submission_category_proposal_idx_is_primary', 'is_primary'),", ""] + - replace: ["Index('arXiv_submission_category_proposal_idx_key', 'proposal_id'),", ""] + - replace: ["Index('arXiv_submission_category_proposal_idx_submission_id', 'submission_id')", ""] + +arXiv_submission_control: + class_name: SubmissionControl + table_args: + - replace: ["ForeignKeyConstraint(['document_id'], ['arXiv_documents.document_id'], name='arXiv_submission_control_ibfk_1'),", ""] + - replace: ["ForeignKeyConstraint(['user_id'], ['tapir_users.user_id'], name='arXiv_submission_control_ibfk_2'),", ""] + - replace: ["Index('document_id', 'document_id', 'version', unique=True),", ""] + - replace: ["Index('freeze_date', 'freeze_date'),", ""] + - replace: ["Index('pending_paper_id', 'pending_paper_id'),", ""] + - replace: ["Index('request_date', 'request_date'),", ""] + - replace: ["Index('status', 'status'),", ""] + - replace: ["Index('user_id', 'user_id')", ""] + columns: + document_id: "mapped_column(ForeignKey('arXiv_documents.document_id'), nullable=False, server_default=FetchedValue())" + version: "mapped_column(Integer, nullable=False, server_default=FetchedValue())" + pending_paper_id: "mapped_column(String(20), nullable=False, index=True, server_default=FetchedValue())" + user_id: "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_column(Integer, nullable=False, index=True, server_default=FetchedValue())" + freeze_date: "mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue())" + publish_date: "mapped_column(Integer, nullable=False, server_default=FetchedValue())" + +arXiv_submission_flag: + class_name: SubmissionFlag + table_args: + - replace: ["Index('user_id', 'user_id')", ""] + +arXiv_submission_hold_reason: + class_name: SubmissionHoldReason + table_args: + - replace: ["Index('comment_id', 'comment_id'),", ""] + - replace: ["Index('submission_id', 'submission_id'),", ""] + - replace: ["Index('user_id', 'user_id')", ""] +arXiv_submission_near_duplicates: + class_name: SubmissionNearDuplicate +arXiv_submission_qa_reports: + class_name: SubmissionQaReport + table_args: + - replace: ["Index('submission_id', 'submission_id')", ""] + +arXiv_submission_view_flag: + class_name: SubmissionViewFlag + table_args: + - replace: ["Index('user_id', 'user_id')", ""] + +arXiv_submissions: + class_name: Submission +arXiv_pilot_datasets: + class_name: PilotDataset +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 + table_args: + - replace: ["Index('document_id', 'document_id')", ""] +arXiv_trackback_pings: + class_name: TrackbackPing +arXiv_trackback_sites: + class_name: TrackbackSite +arXiv_tracking: + class_name: Tracking +arXiv_updates: + class_name: Updates + +arXiv_versions: + class_name: Version + table_args: drop + columns: + document_id: mapped_column(ForeignKey('arXiv_documents.document_id'), primary_key=True, nullable=False, server_default=FetchedValue()) + version: mapped_column(Integer, primary_key=True, nullable=False, server_default=FetchedValue()) + request_date: mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + freeze_date: mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + publish_date: mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + flag_current: mapped_column(Integer, nullable=False, server_default=FetchedValue()) + +arXiv_versions_checksum: + class_name: VersionsChecksum +dbix_class_schema_versions: + class_name: DbixClassSchemaVersion +sessions: + class_name: Session +tapir_address: + class_name: TapirAddress +tapir_admin_audit: + class_name: TapirAdminAudit + columns: + data: mapped_column(String(255)) +tapir_countries: + class_name: TapirCountry +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 + table_args: + - replace: ["Index('created_by', 'created_by'),", ""] + - replace: ["Index('updated_by', 'updated_by')", ""] +tapir_email_templates: + class_name: TapirEmailTemplate +tapir_email_tokens: + class_name: TapirEmailToken + table_args: + - replace: ["Index('secret', 'secret')", ""] +tapir_integer_variables: + class_name: TapirIntegerVariable +tapir_nicknames: + class_name: TapirNickname +tapir_nicknames_audit: + class_name: TapirNicknamesAudit +tapir_permanent_tokens: + class_name: TapirPermanentToken + table_args: + - replace: ["Index('session_id', 'session_id')", ""] +tapir_phone: + class_name: TapirPhone +tapir_policy_classes: + class_name: TapirPolicyClass +tapir_presessions: + class_name: TapirPresession +tapir_recovery_tokens: + class_name: TapirRecoveryToken + table_args: + - replace: ["Index('secret', 'secret')", ""] +tapir_recovery_tokens_used: + class_name: TapirRecoveryTokensUsed + table_args: + - replace: ["Index('session_id', 'session_id')", ""] +tapir_sessions: + class_name: TapirSession + table_args: + - replace: ["Index('user_id', 'user_id')", ""] +tapir_sessions_audit: + class_name: TapirSessionsAudit + table_args: + - replace: ["Index('ip_addr', 'ip_addr'),", ""] + - replace: ["Index('tracking_cookie', 'tracking_cookie')", ""] + columns: + ip_addr: "mapped_column(String(16), nullable=False, index=True, server_default=FetchedValue())" + tracking_cookie: "mapped_column(String(255), nullable=False, index=True, server_default=FetchedValue())" +tapir_string_variables: + class_name: TapirStringVariable +tapir_strings: + class_name: TapirString +tapir_users: + class_name: TapirUser +arXiv_author_ids: + class_name: AuthorIds +arXiv_demographics: + class_name: Demographic + table_args: + - replace: ["Index('archive', 'archive', 'subject_class'),", ""] + - replace: ["Index('country', 'country'),", ""] + - replace: ["Index('type', 'type')", "Index('dem_archive', 'archive', 'subject_class')"] + + columns: + country: "mapped_column(String(2), nullable=False, index=True, server_default=FetchedValue())" + type: "mapped_column(SmallInteger, index=True)" + veto_status: | + :Mapped[Literal['ok', 'no-endorse', 'no-upload', 'no-replace']] = mapped_column(Enum('ok', 'no-endorse', 'no-upload', 'no-replace'), server_default=text("'ok'")) +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 + table_args: + - replace: ["Index('country', 'country'),", ""] + - replace: ["Index('postal_code', 'postal_code')", ""] +tapir_users_hot: + class_name: TapirUsersHot +tapir_users_password: + class_name: TapirUsersPassword +arXiv_latexml_doc: + class_name: DBLaTeXMLDocuments +arXiv_latexml_sub: + class_name: DBLaTeXMLSubmissions +feedback: + class_name: DBLaTeXMLFeedback diff --git a/arxiv/db/orig_models.py b/arxiv/db/orig_models.py new file mode 100644 index 000000000..509bf4db2 --- /dev/null +++ b/arxiv/db/orig_models.py @@ -0,0 +1,2102 @@ +"""These models represent the entire arXiv DB and the LaTeXML DB. + +This file was generated by using sqlacodgen +""" + +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, + ForeignKey, + ForeignKeyConstraint, + Index, + Integer, + JSON, + Numeric, + PrimaryKeyConstraint, + SmallInteger, + String, + Text, + Table, + TIMESTAMP, + Enum, + text, + Engine, +) +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 + +tb_secret = settings.TRACKBACK_SECRET +tz = gettz(settings.ARXIV_BUSINESS_TZ) + + +class MemberInstitution(Base): + __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): + __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()) + + arXiv_group = relationship('Group', primaryjoin='Archive.in_group == Group.group_id', backref='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' + + 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) + + 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']), + ) + + 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' + + 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()) + 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') + + + +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]] + + 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' + + 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') + 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): + __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') + + +class PilotDataset(Submission): + __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'),) + + 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')) + 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"ArXivUpdate(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_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') + + +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'")) + + 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 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)) + + +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/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/development/db_codegen.py b/development/db_codegen.py new file mode 100644 index 000000000..72aab6e61 --- /dev/null +++ b/development/db_codegen.py @@ -0,0 +1,284 @@ +from __future__ import annotations +import re +import sys +import os +import subprocess +from typing import Tuple +from ruamel.yaml import YAML + +# import ast +import libcst as cst + +tables_i_cannot_update = { + 'DBLPAuthor': True, + 'TapirNicknamesAudit': True, + 'MemberInstitutionIP': True, + + "t_arXiv_ownership_requests_papers": True, + "t_arXiv_updates_tmp": True, + "t_arXiv_admin_state": True, +} + +def first_target(body): + if hasattr(body, 'targets'): + return body.targets[0].id + if hasattr(body, 'target'): + return body.target.id + return None + + +def is_intpk(elem): + return hasattr(elem, 'annotation') and hasattr(elem.annotation, 'slice') and hasattr(elem.annotation.slice, 'id') and elem.annotation.slice.id == "intpk" + +def patch_mysql_types(contents: str): + # Define a mapping of MySQL dialect types to generic SQLAlchemy types + type_mapping = [ + (re.compile(r'= mapped_column\(BIGINT\s*\(\d+\)'), r'= mapped_column(BigInteger'), # Replace BIGINT(size) with BIGINT + (re.compile(r'= mapped_column\(DECIMAL\s*\((\d+),\s*(\d+)\)'), r'= mapped_column(Numeric(\1, \2)'), # Replace DECIMAL(m,n) with Numeric(m,n) + (re.compile(r'= mapped_column\(MEDIUMINT\s*\(\d+\)'), r'= mapped_column(Integer'), # Replace MEDIUMINT(size) with int + (re.compile(r'= mapped_column\(INTEGER\s*\(\d+\)'), r'= mapped_column(Integer'), # Replace INTEGER(size) with int + (re.compile(r'= mapped_column\(SMALLINT\s*\(\d+\)'), r'= mapped_column(Integer'), # Replace SMALLINT(size) with int + (re.compile(r'= mapped_column\(TINYINT\s*\(\d+\)'), r'= mapped_column(Integer'), # Replace TINYINT(size) with int + (re.compile(r'= mapped_column\(VARCHAR\s*\((\d+)\)'), r'= mapped_column(String(\1)'), # Replace VARCHAR(size) with String + (re.compile(r'= mapped_column\(MEDIUMTEXT\s*\((\d+)\)'), r'= mapped_column(Text(\1)'), # Replace MEDIUMTEXT with Text + (re.compile(r'= mapped_column\(TIMESTAMP'), r'= mapped_column(DateTime'), # Replace MEDIUMTEXT with Text + (re.compile(r'= mapped_column\(CHAR\s*\((\d+)\)'), r'= mapped_column(String(\1)'), # Replace CHAR(size) with str + (re.compile(r' CHAR\s*\((\d+)\),'), r' String(\1),'), # Replace CHAR(size) with str + (re.compile(r' class_:'), r' _class:'), # + (re.compile(r'Mapped\[decimal.Decimal\]'), r'Mapped[float]'), # + (re.compile(r'Mapped\[datetime.datetime\]'), r'Mapped[datetime]'), # + (re.compile(r'Optional\[datetime.datetime\]'), r'Optional[datetime]'), # + (re.compile(r'INTEGER\(\d+\)'), r'Integer'), + (re.compile(r'TINYINT\(\d+\)'), r'Integer'), + (re.compile(r'MEDIUMINT\(\d+\)'), r'Integer'), + (re.compile(r'SMALLINT\(\d+\)'), r'Integer'), + (re.compile(r'MEDIUMTEXT'), r'Text'), + (re.compile(r'text\("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"\)'), r'FetchdValue()'), + (re.compile(r'datetime\.date'), r'dt.date'), + + # Replace INTEGER(size) with int + ] + + # Perform the replacement using regex for all types + def mapper(line: str) -> 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 + + +def is_assign_expr(elem): + if isinstance(elem, cst.SimpleStatementLine): + return isinstance(elem.body[0], (cst.Assign, cst.AnnAssign)) + return False + +def is_table_def(node): + return isinstance(node, cst.SimpleStatementLine) and is_table_assign(node.body[0]) + +def is_table_assign(node): + 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: + 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""" + 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): + def __init__(self, latest_def, latest_tables): + self.latest_def = latest_def + self.latest_tables = latest_tables + + def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef) -> cst.CSTNode: + # + class_name = original_node.name.value + if class_name in tables_i_cannot_update: + return updated_node + + if class_name in self.latest_def: + latest_node = self.latest_def[class_name] + + # Collect the existing assignments from the original class body + existing_assignments = { + self.first_target(elem): elem for elem in original_node.body.body if + is_assign_expr(elem) + } + + updated_body = [] + + for elem in latest_node.body.body: + if is_assign_expr(elem): + 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 + if self.is_intpk(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): + 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 not processed again + del existing_assignments[target] + else: + updated_body.append(elem) + else: + updated_body.append(elem) + + for elem in original_node.body.body: + if not is_assign_expr(elem): + updated_body.append(elem) + + # Rebuild the class body with updated assignments + return updated_node.with_changes(body=updated_node.body.with_changes(body=updated_body)) + return updated_node + + def first_target(self, node): + 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): + 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 leave_Assign(self, original_node: cst.Assign, updated_node: cst.Assign) -> cst.CSTNode: + # 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): + return original_node + latest_table_def: cst.Assign = self.latest_tables.get(lhs_name) + if not latest_table_def: + return original_node + # updated_node = updated_node.with_changes(value=) + rh_new = latest_table_def.value + rh_old = updated_node.value + # Update the table def's RH with new's RH + if hasattr(rh_new, 'args') and hasattr(rh_old, 'args'): + 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("foo") + if isinstance(new_column.value, cst.Call) and new_column.value.func.value == "Column": + # column def + column_name = new_column.value.args[0].value.value + old_column = columns.get(column_name) + if old_column: + 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 main() -> None: + p_outfile = "arxiv/db/autogen_models.py" + + # + #with open(os.path.expanduser('~/.arxiv/arxiv-db-prod-readonly'), encoding='utf-8') as uri_fd: + # p_url: str = uri_fd.read().strip() + p_url = "mysql://testuser:testpassword@127.0.0.1/testdb" + sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "sqlacodegen", "src")) + subprocess.run(['development/sqlacodegen/venv/bin/python', '-m', 'sqlacodegen', p_url, '--outfile', p_outfile, '--model-metadata', "arxiv/db/arxiv-db-metadata.yaml"], check=True) + + with open(p_outfile, 'r') as src: + source = src.read() + + latest_tree = cst.parse_module(source) + latest_def = {} + latest_tables = {} + + for node in latest_tree.body: + if isinstance(node, cst.ClassDef): + latest_def[node.name.value] = node + if is_table_def(node): + latest_tables[node.body[0].targets[0].target.value] = node.body[0] + + with open(os.path.expanduser('arxiv/db/orig_models.py'), encoding='utf-8') as model_fd: + existing_models = model_fd.read() + existing_tree = cst.parse_module(existing_models) + + transformer = SchemaTransformer(latest_def, latest_tables) + updated_tree = existing_tree.visit(transformer) + + updated_model = 'arxiv/db/models.py' + with open(os.path.expanduser(updated_model), "w", encoding='utf-8') as updated_fd: + updated_fd.write(updated_tree.code) + + 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) + subprocess.run(['black', updated_model]) + + +if __name__ == "__main__": + """ + patch arxiv/db/autogen_models.py arxiv/db/autogen_models_patch.diff + """ + main() diff --git a/development/extract_class_n_table.py b/development/extract_class_n_table.py new file mode 100644 index 000000000..0d9aa6d89 --- /dev/null +++ b/development/extract_class_n_table.py @@ -0,0 +1,33 @@ +import json +import ast + +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__': + filename = 'arxiv/db/models.py' # Replace this with the path to your Python file + class_table_mapping = extract_class_table_mapping(filename) + json.dump(class_table_mapping, open('arxiv/db/model-options.json', 'w'), indent=4) diff --git a/development/patch_db_models.py b/development/patch_db_models.py new file mode 100644 index 000000000..e69de29bb 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/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..8cd3941e3 --- /dev/null +++ b/development/sqlacodegen/README.rst @@ -0,0 +1,203 @@ +.. image:: https://github.com/agronholm/sqlacodegen/actions/workflows/test.yml/badge.svg + :target: https://github.com/agronholm/sqlacodegen/actions/workflows/test.yml + :alt: Build Status +.. image:: https://coveralls.io/repos/github/agronholm/sqlacodegen/badge.svg?branch=master + :target: https://coveralls.io/github/agronholm/sqlacodegen?branch=master + :alt: Code Coverage + +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..3e948fc05 --- /dev/null +++ b/development/sqlacodegen/src/sqlacodegen/cli.py @@ -0,0 +1,120 @@ +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 + engine = create_engine(args.url) + metadata = MetaData() + 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..4824fdac6 --- /dev/null +++ b/development/sqlacodegen/src/sqlacodegen/generators.py @@ -0,0 +1,1542 @@ +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, +) + +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 + + + 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_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": + 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 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() + + 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] = {} + 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)) + + 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 + + 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): + args.append(self.render_index(index)) + + 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) -> str: + extra_args = [repr(col.name) for col in index.columns] + kwargs = {} + if index.unique: + kwargs["unique"] = True + + return render_callable("Index", repr(index.name), *extra_args, kwargs=kwargs) + + # TODO find better solution for is_table + def render_column( + self, column: Column[Any], show_name: bool, is_table: bool = False + ) -> 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 + ) + + 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) + 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: + 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] = [] + + # Render class variables / special declarations + class_vars: str = self.render_class_variables(model) + if class_vars: + sections.append(class_vars) + + # Render column attributes + 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) + ) + + 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 + ] + + 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) -> str: + variables = [f"__tablename__ = {model.table.name!r}"] + + # Render constraints and indexes as __table_args__ + table_args = self.render_table_args(model.table) + table_args = self.get_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) -> str: + args: list[str] = [] + kwargs: dict[str, str] = {} + + # Render constraints + 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 + + args.append(self.render_constraint(constraint)) + + # Render indexes + for index in sorted(table.indexes, key=lambda i: i.name): + if len(index.columns) > 1 or not uses_default_name(index): + args.append(self.render_index(index)) + + if table.schema: + kwargs["schema"] = table.schema + + if table.comment: + kwargs["comment"] = table.comment + + 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 and override[0] == ":": + return f"{column_attr.name}: {override[1:]}" + + rendered_column = override if override else self.render_column(column, column_attr.name != column.name) + + 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 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" + + 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_override('relationship', table, {}) + if relationship.name in relationship_override: + rendered_field = relationship_override[relationship.name] + 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/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/poetry.lock b/poetry.lock index 268df3c92..6d20bed87 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1064,6 +1064,29 @@ files = [ {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, ] +[[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" @@ -1213,6 +1236,17 @@ files = [ 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" @@ -1941,6 +1975,32 @@ lint = ["docutils-stubs", "flake8", "mypy"] test = ["pytest"] whoosh = ["sqlalchemy", "whoosh"] +[[package]] +name = "sqlacodegen" +version = "3.0.0rc5.post1" +description = "Automatic model code generator for SQLAlchemy" +optional = false +python-versions = ">=3.8" +files = [] +develop = false + +[package.dependencies] +inflect = ">=4.0.0" +SQLAlchemy = ">=2.0.23" + +[package.extras] +citext = ["sqlalchemy-citext (>=1.7.0)"] +geoalchemy2 = ["geoalchemy2 (>=0.11.1)"] +pgvector = ["pgvector (>=0.2.4)"] +sqlmodel = ["sqlmodel (>=0.0.12)"] +test = ["coverage (>=7)", "mysql-connector-python", "psycopg2-binary", "pytest (>=7.4)"] + +[package.source] +type = "git" +url = "https://github.com/agronholm/sqlacodegen.git" +reference = "HEAD" +resolved_reference = "eb7b95f47ea854291fd9db02c673f7de0f33f41f" + [[package]] name = "sqlalchemy" version = "2.0.30" @@ -2076,6 +2136,24 @@ files = [ trio = ">=0.11" wsproto = ">=0.14" +[[package]] +name = "typeguard" +version = "4.2.0" +description = "Run-time type checker for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typeguard-4.2.0-py3-none-any.whl", hash = "sha256:24bb8f05ccaee423309daf980ba19e978b18766334ee01994503b853fc44efde"}, + {file = "typeguard-4.2.0.tar.gz", hash = "sha256:2aeae510750fca88d0a2ceca3e86de7f71aa43b6c3e6c267737ce1f5effc4b34"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.7.0", markers = "python_version < \"3.12\""} + +[package.extras] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)"] +test = ["coverage[toml] (>=7)", "mypy (>=1.2.0)", "pytest (>=7)"] + [[package]] name = "types-requests" version = "2.32.0.20240712" @@ -2213,4 +2291,4 @@ sphinx = ["sphinx", "sphinx-autodoc-typehints", "sphinxcontrib-websupport"] [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "30b8ca7ca3f104f9d931cddc2beaa09859838aa5fb31be004df531912e0a9cea" +content-hash = "4c3b31b0ae121a5901272bbe5d032c0be8bf485ae5b423959b9b4c59cea3cd57" diff --git a/pyproject.toml b/pyproject.toml index 804becbfe..0227754bd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,6 +53,7 @@ pytest-mock = "^3.8.2" pytest-cov = "*" hypothesis = "*" fakeredis = "*" +sqlacodegen = {git = "https://github.com/agronholm/sqlacodegen.git"} click = "*" From 953bf1def0862224f4058a3f941a4a1ca9446911 Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Tue, 5 Nov 2024 18:13:46 -0500 Subject: [PATCH 05/32] Tests passed. --- .gitignore | 1 + Makefile | 7 +- arxiv/auth/legacy/tests/test_bootstrap.py | 15 + .../legacy/tests/test_endorsement_auto.py | 5 +- arxiv/auth/legacy/tests/test_endorsements.py | 10 +- arxiv/db/arxiv-db-metadata.yaml | 301 +-- arxiv/db/models.py | 1931 +++++++++-------- arxiv/db/orig_models.py | 216 +- arxiv/db/tests/test_db_schema.py | 32 +- development/db_codegen.py | 66 +- poetry.lock | 498 ++++- pyproject.toml | 15 +- pytest.ini | 2 +- 13 files changed, 2041 insertions(+), 1058 deletions(-) diff --git a/.gitignore b/.gitignore index 1e5fcb9c1..da454afb8 100644 --- a/.gitignore +++ b/.gitignore @@ -133,3 +133,4 @@ foo.json test.db-journal arxiv/db/.autogen_models.py +/arxiv/db/autogen_models.py diff --git a/Makefile b/Makefile index cbb07721d..19aa1ee4c 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,7 @@ +PROD_DB_PROXY_PORT := 2021 -.PHONY: db-models + +.PHONY: db-models prod-proxy default: venv/bin/poetry @@ -30,3 +32,6 @@ arxiv/db/autogen_models_patch.diff: @PROD_ARXIV_DB_URI=`cat ~/.arxiv/arxiv-db-prod-readonly`; . venv/bin/activate && \ poetry run sqlacodegen "$$PROD_ARXIV_DB_URI" --outfile arxiv/db/.autogen_models.py diff -c arxiv/db/.autogen_models.py arxiv/db/autogen_models.py > arxiv/db/autogen_models_patch.diff + +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 & diff --git a/arxiv/auth/legacy/tests/test_bootstrap.py b/arxiv/auth/legacy/tests/test_bootstrap.py index cff44538e..f457eeb6b 100644 --- a/arxiv/auth/legacy/tests/test_bootstrap.py +++ b/arxiv/auth/legacy/tests/test_bootstrap.py @@ -65,6 +65,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() @@ -192,6 +194,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, diff --git a/arxiv/auth/legacy/tests/test_endorsement_auto.py b/arxiv/auth/legacy/tests/test_endorsement_auto.py index eedbd8971..23d8d3e98 100644 --- a/arxiv/auth/legacy/tests/test_endorsement_auto.py +++ b/arxiv/auth/legacy/tests/test_endorsement_auto.py @@ -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(): diff --git a/arxiv/auth/legacy/tests/test_endorsements.py b/arxiv/auth/legacy/tests/test_endorsements.py index ad606be5b..0213344a5 100644 --- a/arxiv/auth/legacy/tests/test_endorsements.py +++ b/arxiv/auth/legacy/tests/test_endorsements.py @@ -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(): @@ -172,7 +175,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(): diff --git a/arxiv/db/arxiv-db-metadata.yaml b/arxiv/db/arxiv-db-metadata.yaml index ab120f076..9b83aef49 100644 --- a/arxiv/db/arxiv-db-metadata.yaml +++ b/arxiv/db/arxiv-db-metadata.yaml @@ -1,9 +1,22 @@ Subscription_UniversalInstitution: class_name: MemberInstitution + relationships: + Subscription_UniversalInstitutionContact: "" + Subscription_UniversalInstitutionIP: "" + Subscription_UniversalInstitutionContact: class_name: MemberInstitutionContact + table_args: drop + columns: + sid: "mapped_column(ForeignKey('Subscription_UniversalInstitution.id', ondelete='CASCADE'), nullable=False, index=True)" + relationships: + Subscription_UniversalInstitution: relationship('MemberInstitution', primaryjoin='MemberInstitutionContact.sid == MemberInstitution.id') + Subscription_UniversalInstitutionIP: class_name: MemberInstitutionIP + relationships: + Subscription_UniversalInstitution: relationship('MemberInstitution', primaryjoin='MemberInstitutionIP.sid == MemberInstitution.id') + arXiv_admin_log: class_name: AdminLog arXiv_admin_metadata: @@ -30,6 +43,14 @@ arXiv_bogus_countries: class_name: BogusCountries arXiv_categories: class_name: Category + relationships: + # give arXiv_demographics to use diffent back-ref name: demographic_categories + # don't forget to have this name on Demographic + arXiv_demographics: "" + additional_relationships: + - "demographic_categories: Mapped['Demographic'] = relationship('Demographic', back_populates='demographic_categories') # do not ues 'arXiv_archive ='" + - "arXiv_endorsement_domain = relationship('EndorsementDomain', primaryjoin='Category.endorsement_domain == EndorsementDomain.endorsement_domain', back_populates='arXiv_categories')" + arXiv_questionable_categories: class_name: QuestionableCategory arXiv_category_def: @@ -40,54 +61,64 @@ arXiv_cross_control: class_name: CrossControl table_args: - replace: ["Index('document_id', 'document_id', 'version'),", ""] - - replace: ["Index('user_id', 'user_id')", ""] - - replace: ["Index('ix_arXiv_cross_control_freeze_date', 'freeze_date'),", "" ] columns: freeze_date: "mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue())" + additional_relationships: + - "arXiv_category = relationship('Category', primaryjoin='and_(CrossControl.archive == Category.archive, CrossControl.subject_class == Category.subject_class)', back_populates='arXiv_cross_control')" arXiv_datacite_dois: class_name: DataciteDois - table_args: - - replace: ["Index('metadata_id', 'metadata_id')", ""] arXiv_dblp_authors: class_name: DBLPAuthor - table_args: - - replace: ["Index('author_id', 'author_id'),", ""] - - replace: ["Index('document_id', 'document_id')", ""] arXiv_dblp_document_authors: class_name: DBLPDocumentAuthor - table_args: - - replace: ["Index('author_id', 'author_id'),", ""] - - replace: ["Index('document_id', 'document_id')", ""] + table_args: drop + arXiv_document_category: class_name: DocumentCategory - table_args: - - replace: ["Index('category', 'category'),", ""] - - replace: ["Index('document_id', 'document_id')", ""] + arXiv_documents: class_name: Document + relationships: + arXiv_dblp_document_authors: "" + additional_relationships: + # This is a bit of hack + - | + @property + def owners(self): + return self.arXiv_paper_owners + arXiv_dblp: class_name: DBLP + arXiv_paper_pw: class_name: PaperPw + table_args: drop + 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 + arXiv_endorsement_requests: class_name: EndorsementRequest - table_args: - # Index('archive', 'archive', 'subject_class'), - - replace: ["Index('archive', 'archive', 'subject_class'),", ""] - - replace: ["Index('secret', 'secret', unique=True)", ""] + 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)" + additional_relationships: + - "endorsement = relationship('Endorsement', back_populates='request', uselist=False)" + - "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'),", ""] - - replace: ["Index('endorsee_id', 'endorsee_id'),", ""] - - replace: ["Index('endorser_id', 'endorser_id'),", ""] # - replace: ["Index('endorser_id_2', 'endorser_id', 'endorsee_id', 'archive', 'subject_class', unique=True),", ""] - - replace: ["Index('request_id', 'request_id')", ""] arXiv_endorsements_audit: class_name: EndorsementsAudit arXiv_freeze_log: @@ -98,43 +129,23 @@ arXiv_groups: class_name: 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())" - table_args: - - replace: ["Index('arXiv_jref_control_ibfk_1', 'document_id'),", ""] - - replace: ["Index('arXiv_jref_control_ibfk_2', 'user_id'),", ""] - - replace: ["Index('ix_arXiv_jref_control_freeze_date', 'freeze_date'),", ""] - - replace: ["Index('ix_arXiv_jref_control_status', 'status')", ""] arXiv_licenses: class_name: License arXiv_log_positions: class_name: LogPosition + arXiv_metadata: class_name: Metadata -# ForeignKeyConstraint( -# ["document_id"], -# ["arXiv_documents.document_id"], -# ondelete="CASCADE", -# onupdate="CASCADE", -# name="arXiv_metadata_fk_document_id", -# ), -# ForeignKeyConstraint( -# ["license"], ["arXiv_licenses.name"], name="arXiv_metadata_fk_license" -# ), -# ForeignKeyConstraint( -# ["submitter_id"], -# ["tapir_users.user_id"], -# name="arXiv_metadata_fk_submitter_id", -# ), -# Index("arXiv_metadata_idx_document_id", "document_id"), -# Index("arXiv_metadata_idx_license", "license"), -# Index("arXiv_metadata_idx_submitter_id", "submitter_id"), -# Index("pidv", "paper_id", "version", unique=True), - table_args: - - replace: ["Index('arXiv_metadata_idx_document_id', 'document_id'),", ""] - - replace: ["Index('arXiv_metadata_idx_license', 'license'),", ""] - - replace: ["Index('arXiv_metadata_idx_submitter_id', 'submitter_id'),", ""] + relationships: + document: "relationship('Document', primaryjoin='Metadata.document_id == Document.document_id', back_populates='arXiv_metadata')" + arXiv_license: "relationship('License', primaryjoin='Metadata.license == License.name', back_populates='arXiv_metadata_licenses')" + submitter: "relationship('TapirUser', primaryjoin='Metadata.submitter_id == TapirUser.user_id', back_populates='arXiv_metadata')" + sword: Mapped["Tracking"] = relationship("Tracking", primaryjoin="Submission.sword_id == Tracking.sword_id", back_populates="arXiv_submissions_sowrd") arXiv_mirror_list: class_name: MirrorList @@ -152,21 +163,52 @@ arXiv_orcid_config: class_name: OrcidConfig arXiv_ownership_requests: class_name: OwnershipRequest - table_args: - - replace: ["Index('endorsement_request_id', 'endorsement_request_id'),", ""] - - replace: ["Index('user_id', 'user_id')", ""] + 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)" + +# Have a mixed feelig about this. This is clearly hand-edited, and not really used 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: - - replace: ["Index('user_id', 'user_id')", ""] + # This is given by the document_id column - squalch 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'))" + 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 - table_args: - - replace: ["Index('arXiv_pilot_files_cdfk3', 'submission_id')", ""] arXiv_publish_log: class_name: PublishLog arXiv_reject_session_usernames: @@ -177,10 +219,8 @@ arXiv_show_email_requests: class_name: ShowEmailRequest table_args: - replace: ["Index('email_reqs_user_id', 'user_id', 'dated'),", ""] - - replace: ["Index('ix_arXiv_show_email_requests_dated', 'dated'),", ""] + # - replace: ["Index('ix_arXiv_show_email_requests_dated', 'dated'),", ""] - replace: ["Index('user_id', 'user_id', 'dated')", "Index('email_reqs_user_id', 'user_id', 'dated')"] - columns: - dated: "mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue())" arXiv_state: class_name: State arXiv_stats_monthly_downloads: @@ -191,68 +231,38 @@ arXiv_submission_agreements: class_name: SubmissionAgreement arXiv_submission_category: class_name: SubmissionCategory - table_args: - - replace: ["Index('arXiv_submission_category_idx_category', 'category'),", ""] - - replace: ["Index('arXiv_submission_category_idx_submission_id', 'submission_id')", ""] arXiv_submission_category_proposal: class_name: SubmissionCategoryProposal - table_args: - - replace: ["Index('arXiv_submission_category_proposal_fk_prop_comment_id', 'proposal_comment_id'),", ""] - - replace: ["Index('arXiv_submission_category_proposal_fk_resp_comment_id', 'response_comment_id'),", ""] - - replace: ["Index('arXiv_submission_category_proposal_fk_user_id', 'user_id'),", ""] - - replace: ["Index('arXiv_submission_category_proposal_idx_category', 'category'),", ""] - - replace: ["Index('arXiv_submission_category_proposal_idx_is_primary', 'is_primary'),", ""] - - replace: ["Index('arXiv_submission_category_proposal_idx_key', 'proposal_id'),", ""] - - replace: ["Index('arXiv_submission_category_proposal_idx_submission_id', 'submission_id')", ""] arXiv_submission_control: - class_name: SubmissionControl table_args: - - replace: ["ForeignKeyConstraint(['document_id'], ['arXiv_documents.document_id'], name='arXiv_submission_control_ibfk_1'),", ""] - - replace: ["ForeignKeyConstraint(['user_id'], ['tapir_users.user_id'], name='arXiv_submission_control_ibfk_2'),", ""] - - replace: ["Index('document_id', 'document_id', 'version', unique=True),", ""] - - replace: ["Index('freeze_date', 'freeze_date'),", ""] - - replace: ["Index('pending_paper_id', 'pending_paper_id'),", ""] - - replace: ["Index('request_date', 'request_date'),", ""] - - replace: ["Index('status', 'status'),", ""] - - replace: ["Index('user_id', 'user_id')", ""] - columns: - document_id: "mapped_column(ForeignKey('arXiv_documents.document_id'), nullable=False, server_default=FetchedValue())" - version: "mapped_column(Integer, nullable=False, server_default=FetchedValue())" - pending_paper_id: "mapped_column(String(20), nullable=False, index=True, server_default=FetchedValue())" - user_id: "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_column(Integer, nullable=False, index=True, server_default=FetchedValue())" - freeze_date: "mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue())" - publish_date: "mapped_column(Integer, nullable=False, server_default=FetchedValue())" + # 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 - table_args: - - replace: ["Index('user_id', 'user_id')", ""] - arXiv_submission_hold_reason: class_name: SubmissionHoldReason - table_args: - - replace: ["Index('comment_id', 'comment_id'),", ""] - - replace: ["Index('submission_id', 'submission_id'),", ""] - - replace: ["Index('user_id', 'user_id')", ""] arXiv_submission_near_duplicates: class_name: SubmissionNearDuplicate arXiv_submission_qa_reports: class_name: SubmissionQaReport - table_args: - - replace: ["Index('submission_id', 'submission_id')", ""] - arXiv_submission_view_flag: class_name: SubmissionViewFlag - table_args: - - replace: ["Index('user_id', 'user_id')", ""] - 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_check_results: "relationship('ArXivCheckResults', back_populates='submission')" + arXiv_submission_locks: "relationship('ArXivSubmissionLocks', back_populates='submission')" + additional_relationships: + - "arXiv_license = relationship('License', primaryjoin='Submission.license == License.name', back_populates='arXiv_submissions')" + arXiv_pilot_datasets: class_name: PilotDataset arXiv_submission_abs_classifier_data: @@ -265,44 +275,59 @@ arXiv_suspect_emails: class_name: SuspectEmail arXiv_titles: class_name: Title + arXiv_top_papers: class_name: TopPaper - table_args: - - replace: ["Index('document_id', 'document_id')", ""] + 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 arXiv_updates: class_name: Updates - -arXiv_versions: - class_name: Version table_args: drop columns: - document_id: mapped_column(ForeignKey('arXiv_documents.document_id'), primary_key=True, nullable=False, server_default=FetchedValue()) - version: mapped_column(Integer, primary_key=True, nullable=False, server_default=FetchedValue()) - request_date: mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) - freeze_date: mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) - publish_date: mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) - flag_current: mapped_column(Integer, nullable=False, server_default=FetchedValue()) + 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_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: + user: "relationship('TapirUser', primaryjoin='TapirAddress.user_id == TapirUser.user_id', back_populates='tapir_address')" tapir_email_change_tokens: class_name: TapirEmailChangeToken tapir_email_headers: @@ -311,15 +336,10 @@ tapir_email_log: class_name: TapirEmailLog tapir_email_mailings: class_name: TapirEmailMailing - table_args: - - replace: ["Index('created_by', 'created_by'),", ""] - - replace: ["Index('updated_by', 'updated_by')", ""] tapir_email_templates: class_name: TapirEmailTemplate tapir_email_tokens: class_name: TapirEmailToken - table_args: - - replace: ["Index('secret', 'secret')", ""] tapir_integer_variables: class_name: TapirIntegerVariable tapir_nicknames: @@ -328,8 +348,6 @@ tapir_nicknames_audit: class_name: TapirNicknamesAudit tapir_permanent_tokens: class_name: TapirPermanentToken - table_args: - - replace: ["Index('session_id', 'session_id')", ""] tapir_phone: class_name: TapirPhone tapir_policy_classes: @@ -338,44 +356,37 @@ tapir_presessions: class_name: TapirPresession tapir_recovery_tokens: class_name: TapirRecoveryToken - table_args: - - replace: ["Index('secret', 'secret')", ""] tapir_recovery_tokens_used: class_name: TapirRecoveryTokensUsed - table_args: - - replace: ["Index('session_id', 'session_id')", ""] tapir_sessions: class_name: TapirSession - table_args: - - replace: ["Index('user_id', 'user_id')", ""] + additional_relationships: + - "user = relationship('TapirUser', primaryjoin='TapirSession.user_id == TapirUser.user_id', back_populates='tapir_sessions')" tapir_sessions_audit: class_name: TapirSessionsAudit - table_args: - - replace: ["Index('ip_addr', 'ip_addr'),", ""] - - replace: ["Index('tracking_cookie', 'tracking_cookie')", ""] - columns: - ip_addr: "mapped_column(String(16), nullable=False, index=True, server_default=FetchedValue())" - tracking_cookie: "mapped_column(String(255), nullable=False, index=True, server_default=FetchedValue())" + additional_relationships: + - "session = relationship('TapirSession')" tapir_string_variables: class_name: TapirStringVariable tapir_strings: class_name: TapirString tapir_users: class_name: TapirUser + additional_relationships: + - "endorsee_of = relationship('Endorsement', foreign_keys='[Endorsement.endorsee_id]', back_populates='endorsee')" + - "endorses = relationship('Endorsement', foreign_keys='[Endorsement.endorser_id]', back_populates='endorser')" + - "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')" + arXiv_author_ids: class_name: AuthorIds arXiv_demographics: class_name: Demographic - table_args: - - replace: ["Index('archive', 'archive', 'subject_class'),", ""] - - replace: ["Index('country', 'country'),", ""] - - replace: ["Index('type', 'type')", "Index('dem_archive', 'archive', 'subject_class')"] - - columns: - country: "mapped_column(String(2), nullable=False, index=True, server_default=FetchedValue())" - type: "mapped_column(SmallInteger, index=True)" - veto_status: | - :Mapped[Literal['ok', 'no-endorse', 'no-upload', 'no-replace']] = mapped_column(Enum('ok', 'no-endorse', 'no-upload', 'no-replace'), server_default=text("'ok'")) + relationships: + # I have to drop to avoid the confusion. Instead use "demographic_categories" + arXiv_categories: "" + additional_relationships: + - "demographic_categories: Mapped['Category'] = relationship('Category', back_populates='demographic_categories')" arXiv_orcid_ids: class_name: OrcidIds arXiv_queue_view: @@ -386,13 +397,17 @@ arXiv_sword_licenses: class_name: SwordLicense tapir_demographics: class_name: TapirDemographic - table_args: - - replace: ["Index('country', 'country'),", ""] - - replace: ["Index('postal_code', 'postal_code')", ""] + additional_relationships: + - "tapir_countries: Mapped['TapirCountry'] = relationship('TapirCountry', 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: diff --git a/arxiv/db/models.py b/arxiv/db/models.py index beffeb239..f44432e1f 100644 --- a/arxiv/db/models.py +++ b/arxiv/db/models.py @@ -1,6 +1,15 @@ -"""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. + +This file was generated by using arxiv/development/db_codegen.py along with arxiv/development/sqlacodegen + +If anything that you want to keep 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 @@ -13,36 +22,32 @@ 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, + ForeignKey, + ForeignKeyConstraint, + Index, + Integer, + JSON, Numeric, - PrimaryKeyConstraint, - SmallInteger, - String, - Text, + PrimaryKeyConstraint, + SmallInteger, + String, + Text, Table, + TIMESTAMP, Enum, 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 @@ -51,55 +56,50 @@ class MemberInstitution(Base): - __tablename__ = 'Subscription_UniversalInstitution' + __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] + resolver_URL: Mapped[Optional[str]] = mapped_column(String(255)) + label: Mapped[Optional[str]] = mapped_column(String(255)) 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' + __tablename__ = "Subscription_UniversalInstitutionContact" + sid: Mapped[int] = mapped_column(ForeignKey("Subscription_UniversalInstitution.id", ondelete="CASCADE"), nullable=False, index=True) + id: Mapped[intpk] 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') - + 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" id: Mapped[intpk] + created: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=text("CURRENT_TIMESTAMP")) 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)) @@ -110,19 +110,25 @@ 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__ = (ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], ondelete="CASCADE", name="meta_doc_fk"), Index("arxiv_admin_pidv", "paper_id", "version", unique=True)) 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) + version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + document_id: Mapped[Optional[int]] = mapped_column(Integer, 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) @@ -140,81 +146,81 @@ class AdminMetadata(Base): 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') - + 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" 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" 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' + __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' + __tablename__ = "arXiv_archives" + __table_args__ = (ForeignKeyConstraint(["in_group"], ["arXiv_groups.group_id"], name="0_576"),) 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(String(16), 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_groups: Mapped["Group"] = relationship("Group", back_populates="arXiv_archives") + arXiv_categories: Mapped[List["Category"]] = relationship("Category", back_populates="arXiv_archives") + # 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" 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" 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)) @@ -222,23 +228,23 @@ 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()) + "arXiv_bad_pw", + metadata, + Column("user_id", Integer, nullable=False, server_default=FetchedValue()), ) class BibFeed(Base): - __tablename__ = 'arXiv_bib_feeds' + __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()) + strip_journal_ref: 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)) @@ -247,9 +253,8 @@ class BibFeed(Base): enabled: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) - class BibUpdate(Base): - __tablename__ = 'arXiv_bib_updates' + __tablename__ = "arXiv_bib_updates" update_id: Mapped[intpk] document_id: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) @@ -259,283 +264,315 @@ 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 BogusCountries(Base): - __tablename__ = 'arXiv_bogus_countries' + __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()) + "arXiv_bogus_subject_class", + metadata, + Column("document_id", Integer, nullable=False, server_default=FetchedValue()), + Column("category_name", String(255), nullable=False, server_default=FetchedValue()), ) class Category(Base): - __tablename__ = 'arXiv_categories' + __tablename__ = "arXiv_categories" + __table_args__ = ( + ForeignKeyConstraint(["archive"], ["arXiv_archives.archive_id"], name="0_578"), + ForeignKeyConstraint(["endorsement_domain"], ["arXiv_endorsement_domains.endorsement_domain"], name="0_753"), + ) - 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'")) + endorse_all: Mapped[str] = mapped_column(Enum("y", "n", "d"), nullable=False, server_default=text("'d'")) + endorse_email: Mapped[str] = 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'")) 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) + endorsement_domain: Mapped[Optional[str]] = mapped_column(String(32), index=True) + + arXiv_archives: Mapped["Archive"] = relationship("Archive", back_populates="arXiv_categories") + arXiv_endorsement_domains: Mapped["EndorsementDomain"] = relationship("EndorsementDomain", back_populates="arXiv_categories") + arXiv_cross_control: Mapped[List["CrossControl"]] = relationship("CrossControl", back_populates="arXiv_categories") + arXiv_endorsement_requests: Mapped[List["EndorsementRequest"]] = relationship("EndorsementRequest", back_populates="arXiv_categories") + arXiv_endorsements: Mapped[List["Endorsement"]] = relationship("Endorsement", back_populates="arXiv_categories") + demographic_categories: Mapped["Demographic"] = relationship("Demographic", back_populates="demographic_categories") # do not ues 'arXiv_archive =' + arXiv_endorsement_domain = relationship("EndorsementDomain", primaryjoin="Category.endorsement_domain == EndorsementDomain.endorsement_domain", back_populates="arXiv_categories") + + # 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"], name="0_756"),) 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" 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()) + 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' + __tablename__ = "arXiv_control_holds" __table_args__ = ( - Index('control_id', 'hold_type'), + ForeignKeyConstraint(["last_changed_by"], ["tapir_users.user_id"], name="arXiv_control_holds_ibfk_2"), + ForeignKeyConstraint(["placed_by"], ["tapir_users.user_id"], name="arXiv_control_holds_ibfk_1"), + Index("control_id", "control_id", "hold_type", unique=True), ) 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[str] = mapped_column(Enum("submission", "cross", "jref"), nullable=False, index=True, server_default=FetchedValue()) + hold_status: Mapped[str] = 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[str] = mapped_column(Enum("auto", "user", "admin", "moderator"), nullable=False, index=True, server_default=FetchedValue()) + placed_by: Mapped[Optional[int]] = mapped_column(Integer, index=True) + last_changed_by: Mapped[Optional[int]] = mapped_column(Integer, 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' + __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') + ForeignKeyConstraint(["archive", "subject_class"], ["arXiv_categories.archive", "arXiv_categories.subject_class"], name="arXiv_cross_control_ibfk_2"), + ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], name="arXiv_cross_control_ibfk_1"), + ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="arXiv_cross_control_ibfk_3"), + Index("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()) + document_id: Mapped[int] = mapped_column(Integer, 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(Integer, nullable=False, index=True, server_default=FetchedValue()) + status: Mapped[str] = mapped_column(Enum("new", "frozen", "published", "rejected"), 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()) 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()) + flag_must_notify: Mapped[Optional[str]] = mapped_column(Enum("0", "1"), 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_categories: Mapped["Category"] = relationship("Category", back_populates="arXiv_cross_control") + document: Mapped["Document"] = relationship("Document", back_populates="arXiv_cross_control") + user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_cross_control") + arXiv_category = relationship("Category", primaryjoin="and_(CrossControl.archive == Category.archive, CrossControl.subject_class == Category.subject_class)", back_populates="arXiv_cross_control") class DataciteDois(Base): - __tablename__ = 'arXiv_datacite_dois' - __table_args__ = ( - Index('account_paper_id', 'account', 'paper_id'), - ) + __tablename__ = "arXiv_datacite_dois" + __table_args__ = (ForeignKeyConstraint(["metadata_id"], ["arXiv_metadata.metadata_id"], name="arXiv_datacite_dois_ibfk_1"), Index("account_paper_id", "account", "paper_id", unique=True)) 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) + metadata_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) paper_id: Mapped[str] = mapped_column(String(64), nullable=False) + account: Mapped[Optional[str]] = mapped_column(Enum("test", "prod")) 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" + + # 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__ = ( + ForeignKeyConstraint(["category"], ["arXiv_category_def.category"], name="doc_cat_cat"), + ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], ondelete="CASCADE", name="doc_cat_doc"), + ) - 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(Integer, primary_key=True, nullable=False, index=True, server_default=FetchedValue()) + category: Mapped[str] = mapped_column(String(32), 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__ = (ForeignKeyConstraint(["submitter_id"], ["tapir_users.user_id"], name="0_580"),) 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, 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) dated: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + authors: Mapped[Optional[str]] = mapped_column(Text) + submitter_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) 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") + arXiv_admin_metadata: Mapped[List["AdminMetadata"]] = relationship("AdminMetadata", back_populates="document") + arXiv_cross_control: Mapped[List["CrossControl"]] = relationship("CrossControl", back_populates="document") + arXiv_document_category: Mapped[List["DocumentCategory"]] = relationship("DocumentCategory", back_populates="document") + arXiv_jref_control: 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_paper_owners: Mapped[List["PaperOwner"]] = relationship("PaperOwner", 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") + + @property + def owners(self): + return self.arXiv_paper_owners - 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__ = (ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], name="arXiv_DBLP_cdfk1"),) - document_id: Mapped[int] = mapped_column(ForeignKey('arXiv_documents.document_id'), primary_key=True, server_default=FetchedValue()) + document_id: Mapped[int] = mapped_column(Integer, 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" - 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)) -) +t_arXiv_duplicates = Table("arXiv_duplicates", metadata, Column("user_id", Integer, nullable=False, server_default=FetchedValue()), Column("email", String(255)), Column("username", String(255))) class EndorsementDomain(Base): - __tablename__ = 'arXiv_endorsement_domains' + __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()) + endorse_all: Mapped[str] = mapped_column(Enum("y", "n"), nullable=False, server_default=FetchedValue()) + mods_endorse_all: Mapped[str] = mapped_column(Enum("y", "n"), nullable=False, server_default=FetchedValue()) + endorse_email: Mapped[str] = 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_domains") 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"], name="0_723"), + ForeignKeyConstraint(["endorsee_id"], ["tapir_users.user_id"], name="0_722"), + Index("endorsee_id_2", "endorsee_id", "archive", "subject_class", unique=True), ) 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(Integer, 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, 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) + arXiv_endorsements: Mapped[List["Endorsement"]] = relationship("Endorsement", back_populates="request") + arXiv_ownership_requests: Mapped[List["OwnershipRequest"]] = relationship("OwnershipRequest", back_populates="endorsement_request") + endorsement = relationship("Endorsement", back_populates="request", uselist=False) + audit = relationship("EndorsementRequestsAudit", uselist=False) class EndorsementRequestsAudit(EndorsementRequest): - __tablename__ = 'arXiv_endorsement_requests_audit' + __tablename__ = "arXiv_endorsement_requests_audit" + __table_args__ = (ForeignKeyConstraint(["request_id"], ["arXiv_endorsement_requests.request_id"], name="0_725"),) - request_id: Mapped[int] = mapped_column(ForeignKey('arXiv_endorsement_requests.request_id'), primary_key=True, server_default=FetchedValue()) + request_id: Mapped[int] = mapped_column(Integer, 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' + __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"], name="0_729"), + ForeignKeyConstraint(["endorsee_id"], ["tapir_users.user_id"], name="0_728"), + ForeignKeyConstraint(["endorser_id"], ["tapir_users.user_id"], name="0_727"), + ForeignKeyConstraint(["request_id"], ["arXiv_endorsement_requests.request_id"], name="0_730"), + Index("endorser_id_2", "endorser_id", "endorsee_id", "archive", "subject_class", unique=True), ) 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()) + endorsee_id: Mapped[int] = mapped_column(Integer, 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) + endorser_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) + type: Mapped[Optional[str]] = mapped_column(Enum("user", "admin", "auto")) + request_id: Mapped[Optional[int]] = mapped_column(Integer, 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", foreign_keys=[endorsee_id], back_populates="arXiv_endorsements") + endorser: Mapped["TapirUser"] = relationship("TapirUser", foreign_keys=[endorser_id], back_populates="arXiv_endorsements_") + request: Mapped["EndorsementRequest"] = relationship("EndorsementRequest", back_populates="arXiv_endorsements") class EndorsementsAudit(Endorsement): - __tablename__ = 'arXiv_endorsements_audit' + __tablename__ = "arXiv_endorsements_audit" + __table_args__ = (ForeignKeyConstraint(["endorsement_id"], ["arXiv_endorsements.endorsement_id"], name="0_732"),) - endorsement_id: Mapped[int] = mapped_column(ForeignKey('arXiv_endorsements.endorsement_id'), primary_key=True, server_default=FetchedValue()) + endorsement_id: Mapped[int] = mapped_column(Integer, 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()) @@ -545,67 +582,67 @@ class EndorsementsAudit(Endorsement): comment: Mapped[Optional[str]] = mapped_column(Text) - class FreezeLog(Base): - __tablename__ = 'arXiv_freeze_log' + __tablename__ = "arXiv_freeze_log" date: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) - class GroupDef(Base): - __tablename__ = 'arXiv_group_def' + __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' + __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()) + arXiv_archives: Mapped[List["Archive"]] = relationship("Archive", back_populates="arXiv_groups") 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", Integer, nullable=False, 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' + __tablename__ = "arXiv_jref_control" __table_args__ = ( - Index('jref_ctrl_document_id', 'document_id', 'version'), + ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], name="arXiv_jref_control_ibfk_1"), + ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="arXiv_jref_control_ibfk_2"), + Index("jref_ctrl_document_id", "document_id", "version", unique=True), ) 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(Integer, 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(Integer, nullable=False, index=True, server_default=FetchedValue()) + status: Mapped[str] = mapped_column(Enum("new", "frozen", "published", "rejected"), nullable=False, index=True, 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()) + flag_must_notify: Mapped[Optional[str]] = mapped_column(Enum("0", "1"), 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_control") + user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_jref_control") class License(Base): - __tablename__ = 'arXiv_licenses' + __tablename__ = "arXiv_licenses" name: Mapped[str] = mapped_column(String(255), primary_key=True) label: Mapped[Optional[str]] = mapped_column(String(255)) @@ -613,33 +650,39 @@ class License(Base): note: Mapped[Optional[str]] = mapped_column(String(400)) sequence: Mapped[Optional[int]] = mapped_column(Integer) + arXiv_metadata: Mapped[List["Metadata"]] = relationship("Metadata", back_populates="arXiv_licenses") + arXiv_submissions: Mapped[List["Submission"]] = relationship("Submission", back_populates="arXiv_licenses") class LogPosition(Base): - __tablename__ = 'arXiv_log_positions' + __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]] - + position: Mapped[Optional[int]] = mapped_column(Integer) + date: Mapped[Optional[int]] = mapped_column(Integer) class Metadata(Base): - __tablename__ = 'arXiv_metadata' + __tablename__ = "arXiv_metadata" __table_args__ = ( - Index('pidv', 'paper_id', 'version'), + ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], ondelete="CASCADE", onupdate="CASCADE", name="arXiv_metadata_fk_document_id"), + ForeignKeyConstraint(["license"], ["arXiv_licenses.name"], name="arXiv_metadata_fk_license"), + ForeignKeyConstraint(["submitter_id"], ["tapir_users.user_id"], name="arXiv_metadata_fk_submitter_id"), + Index("pidv", "paper_id", "version", unique=True), ) 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(Integer, 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) + version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + is_withdrawn: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + created: Mapped[Optional[datetime]] = mapped_column(DateTime) + updated: Mapped[Optional[datetime]] = mapped_column(DateTime) + submitter_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) 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[str]] = 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) @@ -652,73 +695,71 @@ class Metadata(Base): 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()) + license: Mapped[Optional[str]] = mapped_column(String(255), index=True) 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") + arXiv_licenses: Mapped["License"] = relationship("License", 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_") class MirrorList(Base): - __tablename__ = 'arXiv_mirror_list' + __tablename__ = "arXiv_mirror_list" + __table_args__ = (ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], name="arXiv_mirror_list_fk_document_id"),) 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()) + document_id: Mapped[int] = mapped_column(Integer, 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()) + created: Mapped[Optional[datetime]] = mapped_column(DateTime) + updated: Mapped[Optional[datetime]] = mapped_column(DateTime) - 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__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="arXiv_moderator_api_key_ibfk_1"),) - 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(Integer, 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", back_populates="arXiv_moderator_api_key") 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", Integer, nullable=False, server_default=FetchedValue()), + Column("archive", String(16), 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, server_default=FetchedValue()), + Column("no_web_email", Integer, server_default=FetchedValue()), + Column("no_reply_to", Integer, 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' + __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' + __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()) @@ -729,35 +770,30 @@ 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" 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"),) 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()) + is_written: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + paper_id: Mapped[Optional[str]] = mapped_column(String(20)) 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" domain: Mapped[str] = mapped_column(String(75), primary_key=True, nullable=False) keyname: Mapped[str] = mapped_column(String(60), primary_key=True, nullable=False) @@ -765,66 +801,66 @@ 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" 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()) + workflow_status: Mapped[str] = mapped_column(Enum("pending", "accepted", "rejected"), nullable=False, server_default=FetchedValue()) + endorsement_request_id: Mapped[Optional[int]] = mapped_column(ForeignKey("arXiv_endorsement_requests.request_id"), index=True) - 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") + request_audit = relationship("OwnershipRequestsAudit", back_populates="ownership_request", uselist=False) documents = relationship("Document", secondary=t_arXiv_ownership_requests_papers) + class OwnershipRequestsAudit(Base): - __tablename__ = 'arXiv_ownership_requests_audit' + __tablename__ = "arXiv_ownership_requests_audit" - 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__ = (ForeignKeyConstraint(["added_by"], ["tapir_users.user_id"], name="0_595"), PrimaryKeyConstraint("document_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_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=FetchedValue()) + added_by: Mapped[int] = mapped_column(Integer, nullable=False, index=True, 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(32), nullable=False, server_default=FetchedValue()) + valid: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + flag_author: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + flag_auto: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - document = relationship('Document', back_populates='owners') - owner = relationship('TapirUser', foreign_keys="[PaperOwner.user_id]", back_populates='owned_papers') + tapir_users: Mapped["TapirUser"] = relationship("TapirUser", foreign_keys=[added_by], back_populates="arXiv_paper_owners") + document: Mapped["Document"] = relationship("Document", back_populates="arXiv_paper_owners") + user: Mapped["TapirUser"] = relationship("TapirUser", foreign_keys=[user_id], back_populates="arXiv_paper_owners_") + owner = relationship("TapirUser", foreign_keys="[PaperOwner.user_id]", back_populates="owned_papers") class PaperSession(Base): - __tablename__ = 'arXiv_paper_sessions' + __tablename__ = "arXiv_paper_sessions" paper_session_id: Mapped[intpk] paper_id: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) @@ -833,58 +869,52 @@ class PaperSession(Base): ip_name: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) - class PilotFile(Base): - __tablename__ = 'arXiv_pilot_files' + __tablename__ = "arXiv_pilot_files" + __table_args__ = (ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], name="arXiv_pilot_files_cdfk3"),) 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(Integer, 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" 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" username: Mapped[str] = mapped_column(String(64), primary_key=True, server_default=FetchedValue()) - class SciencewisePing(Base): - __tablename__ = 'arXiv_sciencewise_pings' + __tablename__ = "arXiv_sciencewise_pings" 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' + __tablename__ = "arXiv_show_email_requests" __table_args__ = ( - Index('email_reqs_user_id', 'user_id', 'dated'), + ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], name="arXiv_show_email_requests_ibfk_1"), + ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="arXiv_show_email_requests_ibfk_2"), + 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()) + document_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(Integer, 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()) @@ -893,270 +923,314 @@ 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" 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" - 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" - 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" - agreement_id: Mapped[int] = mapped_column(SmallInteger, primary_key=True) - effective_date: Mapped[Optional[datetime]] = mapped_column(DateTime, server_default=FetchedValue()) + agreement_id: Mapped[int] = mapped_column(Integer, primary_key=True) commit_ref: Mapped[str] = mapped_column(String(255), nullable=False) + effective_date: Mapped[Optional[datetime]] = mapped_column(DateTime, server_default=FetchedValue()) 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__ = ( + ForeignKeyConstraint(["category"], ["arXiv_category_def.category"], name="arXiv_submission_category_fk_category"), + ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], ondelete="CASCADE", onupdate="CASCADE", name="arXiv_submission_category_fk_submission_id"), + ) - 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(Integer, primary_key=True, nullable=False, index=True) + category: Mapped[str] = mapped_column(String(32), 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__ = ( + ForeignKeyConstraint(["category"], ["arXiv_category_def.category"], name="arXiv_submission_category_proposal_fk_category"), + ForeignKeyConstraint(["proposal_comment_id"], ["arXiv_admin_log.id"], name="arXiv_submission_category_proposal_fk_prop_comment_id"), + ForeignKeyConstraint(["response_comment_id"], ["arXiv_admin_log.id"], name="arXiv_submission_category_proposal_fk_resp_comment_id"), + ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], ondelete="CASCADE", onupdate="CASCADE", name="arXiv_submission_category_proposal_fk_submission_id"), + ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="arXiv_submission_category_proposal_fk_user_id"), + ) 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(Integer, primary_key=True, nullable=False, index=True) + category: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False, index=True) is_primary: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, index=True, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) 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') + updated: Mapped[Optional[datetime]] = mapped_column(DateTime) + proposal_comment_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) + response_comment_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) + arXiv_category_def: Mapped["CategoryDef"] = relationship("CategoryDef", back_populates="arXiv_submission_category_proposal") + proposal_comment: Mapped["AdminLog"] = relationship("AdminLog", foreign_keys=[proposal_comment_id], back_populates="arXiv_submission_category_proposal") + response_comment: Mapped["AdminLog"] = relationship("AdminLog", foreign_keys=[response_comment_id], back_populates="arXiv_submission_category_proposal_") + submission: Mapped["Submission"] = relationship("Submission", back_populates="arXiv_submission_category_proposal") + user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_submission_category_proposal") class SubmissionControl(Base): - __tablename__ = 'arXiv_submission_control' + __tablename__ = "arXiv_submission_control" __table_args__ = ( - Index('sub_ctrl_document_id', 'document_id', 'version'), + ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], name="arXiv_submission_control_ibfk_1"), + ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="arXiv_submission_control_ibfk_2"), + Index("sub_ctrl_document_id", "document_id", "version", unique=True), ) 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(Integer, 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(Integer, nullable=False, index=True, server_default=FetchedValue()) + status: Mapped[str] = mapped_column(Enum("new", "frozen", "published", "rejected"), nullable=False, index=True, 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()) + flag_must_notify: Mapped[Optional[str]] = mapped_column(Enum("0", "1"), 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' + __tablename__ = "arXiv_submission_flag" __table_args__ = ( - Index('uniq_one_flag_per_mod', 'submission_id', 'user_id'), + ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], ondelete="CASCADE", name="arXiv_submission_flag_ibfk_2"), + ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], ondelete="CASCADE", name="arXiv_submission_flag_ibfk_1"), + Index("uniq_one_flag_per_mod", "submission_id", "user_id", unique=True), ) 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(Integer, nullable=False, index=True, server_default=FetchedValue()) + submission_id: Mapped[int] = mapped_column(Integer, 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__ = ( + ForeignKeyConstraint(["comment_id"], ["arXiv_admin_log.id"], name="arXiv_submission_hold_reason_ibfk_3"), + ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], ondelete="CASCADE", name="arXiv_submission_hold_reason_ibfk_1"), + ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], ondelete="CASCADE", name="arXiv_submission_hold_reason_ibfk_2"), + ) 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(Integer, nullable=False, index=True) + user_id: Mapped[int] = mapped_column(Integer, 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(Integer, 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' + __tablename__ = "arXiv_submission_near_duplicates" __table_args__ = ( - Index('match', 'submission_id', 'matching_id'), + ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], ondelete="CASCADE", name="arXiv_submission_near_duplicates_ibfk_1"), + Index("match", "submission_id", "matching_id", unique=True), ) - 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(Integer, 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__ = (ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], name="arXiv_submission_qa_reports_ibfk_1"),) id: Mapped[intpk] - submission_id: Mapped[int] = mapped_column(ForeignKey('arXiv_submissions.submission_id'), nullable=False, index=True) + submission_id: Mapped[int] = mapped_column(Integer, 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) + created: Mapped[Optional[datetime]] = mapped_column(DateTime, server_default=FetchedValue()) 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__ = ( + ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], ondelete="CASCADE", name="arXiv_submission_view_flag_ibfk_1"), + ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], ondelete="CASCADE", name="arXiv_submission_view_flag_ibfk_2"), + ) - submission_id: Mapped[int] = mapped_column(ForeignKey('arXiv_submissions.submission_id', ondelete='CASCADE'), primary_key=True, nullable=False) + submission_id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False) + user_id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, index=True) 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') + 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__ = ( + ForeignKeyConstraint(["agreement_id"], ["arXiv_submission_agreements.agreement_id"], name="agreement_fk"), + ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], ondelete="CASCADE", onupdate="CASCADE", name="arXiv_submissions_fk_document_id"), + ForeignKeyConstraint(["license"], ["arXiv_licenses.name"], onupdate="CASCADE", name="arXiv_submissions_fk_license"), + ForeignKeyConstraint(["submitter_id"], ["tapir_users.user_id"], ondelete="CASCADE", onupdate="CASCADE", name="arXiv_submissions_fk_submitter_id"), + ForeignKeyConstraint(["sword_id"], ["arXiv_tracking.sword_id"], name="arXiv_submissions_fk_sword_id"), + ) submission_id: Mapped[intpk] - document_id: Mapped[Optional[int]] = mapped_column(ForeignKey('arXiv_documents.document_id', ondelete='CASCADE', onupdate='CASCADE'), index=True) + is_author: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + status: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + is_withdrawn: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) + 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()) + is_locked: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + 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'")) + document_id: Mapped[Optional[int]] = mapped_column(Integer, 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(Integer, 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(Integer, 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'")) + created: Mapped[Optional[datetime]] = mapped_column(DateTime) + updated: Mapped[Optional[datetime]] = mapped_column(DateTime) 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)) 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")) + 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', onupdate='CASCADE'), index=True) - version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) + license: Mapped[Optional[str]] = mapped_column(String(255), index=True) 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') + agreement_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) + data_queued_time: Mapped[Optional[datetime]] = mapped_column(DateTime) + metadata_queued_time: Mapped[Optional[datetime]] = mapped_column(DateTime) + + 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_licenses: Mapped["License"] = relationship("License", 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") + arXiv_check_results: Mapped[List["ArXivCheckResults"]] = relationship("ArXivCheckResults", back_populates="submission") + 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_locks: Mapped[List["ArXivSubmissionLocks"]] = relationship("ArXivSubmissionLocks", 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") + arXiv_license = relationship("License", primaryjoin="Submission.license == License.name", back_populates="arXiv_submissions") class PilotDataset(Submission): - __tablename__ = 'arXiv_pilot_datasets' + __tablename__ = "arXiv_pilot_datasets" + __table_args__ = (ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], name="arXiv_pilot_datasets_cdfk3"),) - 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()) + submission_id: Mapped[int] = mapped_column(Integer, primary_key=True) + created: Mapped[datetime] = mapped_column(DateTime, nullable=False) # created: Mapped[datetime] = mapped_column(DateTime, nullable=False) # ^This column is inherited last_checked: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) + 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()) class SubmissionAbsClassifierDatum(Base): - __tablename__ = 'arXiv_submission_abs_classifier_data' + __tablename__ = "arXiv_submission_abs_classifier_data" + __table_args__ = (ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], ondelete="CASCADE", name="arXiv_submission_abs_classifier_data_ibfk_1"),) - 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) + submission_id: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) 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')) + json: Mapped[Optional[str]] = mapped_column(Text) + status: Mapped[Optional[str]] = 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) @@ -1166,27 +1240,27 @@ class SubmissionAbsClassifierDatum(Base): class SubmissionClassifierDatum(Base): - __tablename__ = 'arXiv_submission_classifier_data' + __tablename__ = "arXiv_submission_classifier_data" + __table_args__ = (ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], ondelete="CASCADE", name="arXiv_submission_classifier_data_ibfk_1"),) - 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) + submission_id: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) 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')) + json: Mapped[Optional[str]] = mapped_column(Text) + status: Mapped[Optional[str]] = 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" 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' + __tablename__ = "arXiv_suspect_emails" id: Mapped[intpk] type: Mapped[str] = mapped_column(String(10), nullable=False) @@ -1195,9 +1269,8 @@ class SuspectEmail(Base): updated: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) - class Title(Base): - __tablename__ = 'arXiv_titles' + __tablename__ = "arXiv_titles" paper_id: Mapped[str] = mapped_column(String(64), primary_key=True) title: Mapped[Optional[str]] = mapped_column(String(255), index=True) @@ -1205,25 +1278,23 @@ class Title(Base): date: Mapped[Optional[dt.date]] = mapped_column(Date) - class TopPaper(Base): - __tablename__ = 'arXiv_top_papers' + __tablename__ = "arXiv_top_papers" + __table_args__ = (ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], name="arXiv_top_papers_ibfk_1"),) - 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=text("''")) + rank: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, server_default=FetchedValue()) + document_id: Mapped[int] = mapped_column(Integer, 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" 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()) @@ -1234,7 +1305,10 @@ 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() + ) + document_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) site_id: Mapped[Optional[int]] = mapped_column(Integer) @property @@ -1246,7 +1320,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: @@ -1261,153 +1342,147 @@ 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" 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" 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, 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()) + submission_errors: Mapped[Optional[str]] = mapped_column(Text) + arXiv_submissions: Mapped[List["Submission"]] = relationship("Submission", back_populates="sword") class Updates(Base): __tablename__ = "arXiv_updates" - __table_args__ = (PrimaryKeyConstraint('document_id', 'date', 'action', 'category'),) + version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) + + # 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'"), + primary_key=True, ) - 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__ = (ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], name="arXiv_versions_ibfk_1"),) - 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(Integer, 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"], name="arXiv_versions_checksum_ibfk_1"),) 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) - - + abs_md5sum: Mapped[Optional[bytes]] = 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)) 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" 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", 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' + __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' + __tablename__ = "tapir_address" - 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()) @@ -1415,49 +1490,54 @@ 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_countries: Mapped["TapirCountry"] = relationship("TapirCountry", 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__ = ( + ForeignKeyConstraint(["admin_user"], ["tapir_users.user_id"], name="0_554"), + ForeignKeyConstraint(["affected_user"], ["tapir_users.user_id"], name="0_555"), + ForeignKeyConstraint(["session_id"], ["tapir_sessions.session_id"], name="0_553"), + ) 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()) + affected_user: Mapped[int] = mapped_column(Integer, 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) + data: Mapped[str] = mapped_column(String(255)) comment: Mapped[str] = mapped_column(Text, nullable=False) entry_id: Mapped[intpk] + session_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) + admin_user: Mapped[Optional[int]] = mapped_column(Integer, index=True) - 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" 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_countries") + tapir_demographics: Mapped[List["TapirDemographic"]] = relationship("TapirDemographic", back_populates="tapir_countries") + class TapirEmailChangeToken(Base): - __tablename__ = 'tapir_email_change_tokens' + __tablename__ = "tapir_email_change_tokens" + __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_535"),) - 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)) + user_id: Mapped[int] = mapped_column(Integer, 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()) @@ -1466,71 +1546,79 @@ class TapirEmailChangeToken(Base): 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()) + old_email: Mapped[Optional[str]] = mapped_column(String(255)) + new_email: Mapped[Optional[str]] = mapped_column(String(255)) 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", Integer, nullable=False, 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", Integer, nullable=False, server_default=FetchedValue()), ) class TapirEmailHeader(Base): - __tablename__ = 'tapir_email_headers' + __tablename__ = "tapir_email_headers" + __table_args__ = (ForeignKeyConstraint(["template_id"], ["tapir_email_templates.template_id"], name="0_563"),) - 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(Integer, 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" mail_id: Mapped[intpk] + sent_date: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + template_id: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) 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' + __tablename__ = "tapir_email_mailings" + __table_args__ = ( + ForeignKeyConstraint(["created_by"], ["tapir_users.user_id"], name="0_565"), + ForeignKeyConstraint(["sent_by"], ["tapir_users.user_id"], name="0_566"), + ForeignKeyConstraint(["template_id"], ["tapir_email_templates.template_id"], name="0_567"), + ) 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(Integer, index=True) + created_by: Mapped[Optional[int]] = mapped_column(Integer, index=True) + sent_by: Mapped[Optional[int]] = mapped_column(Integer, 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') - + 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' + __tablename__ = "tapir_email_templates" __table_args__ = ( - Index('short_name', 'short_name', 'lang'), + ForeignKeyConstraint(["created_by"], ["tapir_users.user_id"], name="0_560"), + ForeignKeyConstraint(["updated_by"], ["tapir_users.user_id"], name="0_561"), + Index("short_name", "short_name", "lang", unique=True), ) template_id: Mapped[intpk] @@ -1540,20 +1628,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(Integer, nullable=False, index=True, server_default=FetchedValue()) + updated_by: Mapped[int] = mapped_column(Integer, 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__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_530"),) - 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(Integer, 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()) @@ -1562,66 +1652,61 @@ 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", Integer, nullable=False, 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", Integer, nullable=False, 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, server_default=FetchedValue()), + Column("user_id", Integer, index=True), + Column("session_id", Integer, index=True), + Column("ip_addr", String(16), nullable=False, server_default=FetchedValue()), + Column("remote_host", String(255), nullable=False, server_default=FetchedValue()), + Column("tracking_cookie", String(32), nullable=False, server_default=FetchedValue()), + Column("message", String(32), nullable=False, 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" 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__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_570"), Index("user_id", "user_id", "user_seq", unique=True)) 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, index=True, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(Integer, 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()) @@ -1630,69 +1715,72 @@ 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, server_default=FetchedValue()), Column("entry", Text)) class TapirPermanentToken(Base): - __tablename__ = 'tapir_permanent_tokens' + __tablename__ = "tapir_permanent_tokens" + __table_args__ = (ForeignKeyConstraint(["session_id"], ["tapir_sessions.session_id"], name="0_541"), ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_540")) - 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(Integer, 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(Integer, 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", Integer, nullable=False, server_default=FetchedValue()), ) - class TapirPhone(Base): - __tablename__ = 'tapir_phone' + __tablename__ = "tapir_phone" + __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_520"),) - 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(Integer, 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()) + phone_number: Mapped[Optional[str]] = mapped_column(String(32), index=True) - 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" + + 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 @@ -1703,17 +1791,9 @@ 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" presession_id: Mapped[intpk] ip_num: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) @@ -1722,11 +1802,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__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_546"),) - 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(Integer, 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()) @@ -1735,68 +1815,72 @@ 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__ = (ForeignKeyConstraint(["session_id"], ["tapir_sessions.session_id"], name="0_549"), ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_548")) - 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(Integer, primary_key=True, nullable=False, server_default=FetchedValue()) secret: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False, server_default=FetchedValue()) + remote_host: Mapped[str] = mapped_column(String(255), 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(Integer, 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', Text, nullable=False), - Column('seq', Integer, nullable=False, server_default=FetchedValue()) + "tapir_save_post_variables", + metadata, + Column("presession_id", Integer, nullable=False, 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__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_525"),) - 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(Integer, 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") + 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") + user = relationship("TapirUser", primaryjoin="TapirSession.user_id == TapirUser.user_id", back_populates="tapir_sessions") class TapirSessionsAudit(Base): - __tablename__ = 'tapir_sessions_audit' + __tablename__ = "tapir_sessions_audit" + __table_args__ = (ForeignKeyConstraint(["session_id"], ["tapir_sessions.session_id"], name="0_527"),) - 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(Integer, 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" 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" 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()) @@ -1804,40 +1888,18 @@ 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'), - # 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') - ) + __tablename__ = "tapir_users" + __table_args__ = (ForeignKeyConstraint(["policy_class"], ["tapir_policy_classes.class_id"], name="0_510"),) 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("''")) + email: Mapped[str] = mapped_column(String(255), nullable=False, 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(Integer, 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'")) @@ -1851,73 +1913,77 @@ class TapirUser(Base): 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'")) + 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)) + joined_ip_num: Mapped[Optional[str]] = mapped_column(String(16), index=True) - 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_key: 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_control: Mapped[List["CrossControl"]] = relationship("CrossControl", back_populates="user") + arXiv_endorsement_requests: Mapped[List["EndorsementRequest"]] = relationship("EndorsementRequest", back_populates="endorsee") + arXiv_jref_control: Mapped[List["JrefControl"]] = relationship("JrefControl", back_populates="user") + arXiv_metadata: Mapped[List["Metadata"]] = relationship("Metadata", back_populates="submitter") + arXiv_paper_owners: Mapped[List["PaperOwner"]] = relationship("PaperOwner", foreign_keys="[PaperOwner.added_by]", back_populates="tapir_users") + arXiv_paper_owners_: Mapped[List["PaperOwner"]] = relationship("PaperOwner", foreign_keys="[PaperOwner.user_id]", back_populates="user") + 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") + arXiv_check_results: Mapped[List["ArXivCheckResults"]] = relationship("ArXivCheckResults", back_populates="user") + arXiv_endorsements: Mapped[List["Endorsement"]] = relationship("Endorsement", foreign_keys="[Endorsement.endorsee_id]", back_populates="endorsee") + arXiv_endorsements_: 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["ArXivSubmissionLocks"]] = relationship("ArXivSubmissionLocks", back_populates="user") + arXiv_submission_view_flag: Mapped[List["SubmissionViewFlag"]] = relationship("SubmissionViewFlag", back_populates="user") + arXiv_check_responses: Mapped[List["ArXivCheckResponses"]] = relationship("ArXivCheckResponses", 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") + 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' + __tablename__ = "arXiv_author_ids" + __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="arXiv_author_ids_ibfk_1"),) - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True) + user_id: Mapped[int] = mapped_column(Integer, 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' + __tablename__ = "arXiv_demographics" __table_args__ = ( - ForeignKeyConstraint(['archive', 'subject_class'], ['arXiv_categories.archive', 'arXiv_categories.subject_class']), - Index('dem_archive', 'archive', 'subject_class') + ForeignKeyConstraint(["archive", "subject_class"], ["arXiv_categories.archive", "arXiv_categories.subject_class"], name="0_588"), + ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_587"), ) - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(Integer, 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'")) @@ -1932,98 +1998,260 @@ 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[str] = mapped_column(Enum("ok", "no-endorse", "no-upload", "no-replace"), nullable=False, server_default=text("'ok'")) + 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)) + flag_group_physics: Mapped[Optional[int]] = mapped_column(Integer, index=True) - 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'), - ] + demographic_categories: Mapped["Category"] = relationship("Category", back_populates="demographic_categories") @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") + + # associate the category + 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"), + ] class OrcidIds(Base): - __tablename__ = 'arXiv_orcid_ids' + __tablename__ = "arXiv_orcid_ids" + __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="arXiv_orcid_ids_ibfk_1"),) - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True) + user_id: Mapped[int] = mapped_column(Integer, 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__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], ondelete="CASCADE", name="arXiv_queue_view_ibfk_1"),) - 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(Integer, primary_key=True, server_default=FetchedValue()) total_views: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + last_view: Mapped[Optional[datetime]] = mapped_column(DateTime) + second_last_view: Mapped[Optional[datetime]] = mapped_column(DateTime) class SuspiciousName(Base): - __tablename__ = 'arXiv_suspicious_names' + __tablename__ = "arXiv_suspicious_names" + __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_606"),) - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(Integer, 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__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="user_id_fk"),) - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True) - license: Mapped[Optional[str]] = mapped_column(String(127)) + user_id: Mapped[int] = mapped_column(Integer, primary_key=True) updated: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) + license: Mapped[Optional[str]] = mapped_column(String(127)) class TapirDemographic(Base): - __tablename__ = 'tapir_demographics' + __tablename__ = "tapir_demographics" + __table_args__ = (ForeignKeyConstraint(["country"], ["tapir_countries.digraph"], name="0_518"), ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_517")) - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(Integer, 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()) + country: Mapped[str] = mapped_column(String(2), 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()) + birthday: Mapped[Optional[dt.date]] = mapped_column(Date, index=True) - tapir_country = relationship('TapirCountry', primaryjoin='TapirDemographic.country == TapirCountry.digraph', backref='tapir_demographics') + tapir_countries: Mapped["TapirCountry"] = relationship("TapirCountry", back_populates="tapir_demographics") + tapir_countries: Mapped["TapirCountry"] = relationship("TapirCountry", back_populates="tapir_demographics") class TapirUsersHot(Base): - __tablename__ = 'tapir_users_hot' + __tablename__ = "tapir_users_hot" + __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_514"),) - user_id: Mapped[int] = mapped_column(ForeignKey('tapir_users.user_id'), primary_key=True, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(Integer, 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" - 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 ArXivCheckResults(Base): + __tablename__ = "arXiv_check_results" + __table_args__ = ( + ForeignKeyConstraint(["check_id"], ["arXiv_checks.check_id"], name="check_results_checks_fk"), + ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], name="check_results_sub_fk"), + ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="check_results_user_fk"), + ) + + check_result_id: Mapped[int] = mapped_column(Integer, primary_key=True) + submission_id: Mapped[int] = mapped_column(Integer, 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(Integer, nullable=False, index=True) + user_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) + ok: Mapped[int] = mapped_column(Integer, nullable=False) + created: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=text("CURRENT_TIMESTAMP")) + message: Mapped[Optional[str]] = mapped_column(String(40)) + data: Mapped[Optional[str]] = mapped_column(String(2000)) + + check: Mapped["ArXivChecks"] = relationship("ArXivChecks", back_populates="arXiv_check_results") + submission: Mapped["Submission"] = relationship("Submission", back_populates="arXiv_check_results") + user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_check_results") + arXiv_check_responses: Mapped[List["ArXivCheckResponses"]] = relationship("ArXivCheckResponses", back_populates="check_result") + + +class ArXivCheckResponses(Base): + __tablename__ = "arXiv_check_responses" + __table_args__ = ( + ForeignKeyConstraint(["check_result_id"], ["arXiv_check_results.check_result_id"], name="check_responses_results_fk"), + ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="check_responses_user_fk"), + ) + + check_response_id: Mapped[int] = mapped_column(Integer, primary_key=True) + check_result_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) + user_id: Mapped[int] = mapped_column(Integer, 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=text("CURRENT_TIMESTAMP")) + message: Mapped[Optional[str]] = mapped_column(String(200)) + + check_result: Mapped["ArXivCheckResults"] = relationship("ArXivCheckResults", back_populates="arXiv_check_responses") + user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_check_responses") + + +class ArXivCheckResultViews(Base): + __tablename__ = "arXiv_check_result_views" + + 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)) + + arXiv_checks: Mapped[List["ArXivChecks"]] = relationship("ArXivChecks", back_populates="check_result_view") + + +class ArXivCheckRoles(Base): + __tablename__ = "arXiv_check_roles" + + 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)) + + arXiv_checks: Mapped[List["ArXivChecks"]] = relationship("ArXivChecks", back_populates="check_role") + + +class ArXivCheckTargets(Base): + __tablename__ = "arXiv_check_targets" + + 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)) + + arXiv_checks: Mapped[List["ArXivChecks"]] = relationship("ArXivChecks", back_populates="check_target") + + +class ArXivChecks(Base): + __tablename__ = "arXiv_checks" + __table_args__ = ( + ForeignKeyConstraint(["check_result_view_id"], ["arXiv_check_result_views.check_result_view_id"], name="checks_result_views_fk"), + ForeignKeyConstraint(["check_role_id"], ["arXiv_check_roles.check_role_id"], name="checks_roles_fk"), + ForeignKeyConstraint(["check_target_id"], ["arXiv_check_targets.check_target_id"], name="checks_content_fk"), + ) + + check_id: Mapped[int] = mapped_column(Integer, primary_key=True) + check_target_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) + check_role_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) + check_result_view_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'1'")) + name: Mapped[str] = mapped_column(String(40), nullable=False) + 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'")) + description: Mapped[Optional[str]] = mapped_column(String(200)) + + check_result_view: Mapped["ArXivCheckResultViews"] = relationship("ArXivCheckResultViews", back_populates="arXiv_checks") + check_role: Mapped["ArXivCheckRoles"] = relationship("ArXivCheckRoles", back_populates="arXiv_checks") + check_target: Mapped["ArXivCheckTargets"] = relationship("ArXivCheckTargets", back_populates="arXiv_checks") + arXiv_check_results: Mapped[List["ArXivCheckResults"]] = relationship("ArXivCheckResults", back_populates="check") + + +class ArXivSubmissionLocks(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' + __tablename__ = "arXiv_latexml_doc" paper_id: Mapped[str] = mapped_column(String(20), primary_key=True) document_version: Mapped[intpk] @@ -2038,11 +2266,12 @@ class DBLaTeXMLDocuments(LaTeXMLBase): 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 @@ -2052,9 +2281,10 @@ class DBLaTeXMLSubmissions (LaTeXMLBase): 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]] = mapped_column(String(255)) conversion_url: Mapped[Optional[str]] = mapped_column(String(255)) @@ -2068,34 +2298,37 @@ class DBLaTeXMLFeedback (LaTeXMLBase): 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 index 509bf4db2..144867515 100644 --- a/arxiv/db/orig_models.py +++ b/arxiv/db/orig_models.py @@ -1,6 +1,15 @@ -"""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. + +This file was generated by using arxiv/development/db_codegen.py along with arxiv/development/sqlacodegen + +If anything that you want to keep 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 @@ -63,7 +72,6 @@ class MemberInstitution(Base): note: Mapped[Optional[str]] = mapped_column(String(255)) - class MemberInstitutionContact(Base): __tablename__ = 'Subscription_UniversalInstitutionContact' @@ -194,7 +202,8 @@ class Archive(Base): 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') + # additional relation + arXiv_group = relationship('Group', primaryjoin='Archive.in_group == Group.group_id', back_populates='arXiv_archives') @@ -291,6 +300,7 @@ class BogusCountries(Base): 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'")) @@ -301,9 +311,10 @@ class Category(Base): 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) - arXiv_archive = relationship('Archive', primaryjoin='Category.archive == Archive.archive_id', backref='arXiv_categories') + # 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', backref='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): @@ -402,11 +413,18 @@ class DBLPAuthor(Base): 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') @@ -436,8 +454,9 @@ class Document(Base): primary_subject_class: Mapped[Optional[str]] = mapped_column(String(16)) created: Mapped[Optional[datetime]] - owners = relationship('PaperOwner', back_populates='document') + # 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): @@ -811,14 +830,14 @@ class PaperOwner(Base): 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'")) + date: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + added_by: 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(32), nullable=False, server_default=FetchedValue()) + valid: Mapped[int] = mapped_column(SmallInteger, nullable=False, server_default=FetchedValue()) + flag_author: Mapped[int] = mapped_column(SmallInteger, nullable=False, server_default=FetchedValue()) + flag_auto: Mapped[int] = mapped_column(SmallInteger, nullable=False, server_default=FetchedValue()) document = relationship('Document', back_populates='owners') owner = relationship('TapirUser', foreign_keys="[PaperOwner.user_id]", back_populates='owned_papers') @@ -1134,6 +1153,8 @@ class Submission(Base): 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') + arXiv_check_results: Mapped[List["ArXivCheckResults"]] = relationship("ArXivCheckResults", back_populates="submission") + arXiv_submission_locks: Mapped[List["ArXivSubmissionLocks"]] = relationship("ArXivSubmissionLocks", back_populates="submission") class PilotDataset(Submission): @@ -1284,13 +1305,11 @@ class Tracking(Base): 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"), - nullable=False, - index=True, - server_default=text("'0'"), + primary_key=True, ) version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) date: Mapped[Optional[dt.date]] = mapped_column(Date, index=True) @@ -1299,7 +1318,7 @@ class Updates(Base): category: Mapped[Optional[int]] = 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( @@ -1888,10 +1907,12 @@ class TapirUser(Base): 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["ArXivSubmissionLocks"]] = relationship("ArXivSubmissionLocks", back_populates="user") arXiv_submission_view_flag = relationship('SubmissionViewFlag', back_populates='user') + arXiv_check_results: Mapped[List["ArXivCheckResults"]] = relationship("ArXivCheckResults", back_populates="user") + arXiv_check_responses: Mapped[List["ArXivCheckResponses"]] = relationship("ArXivCheckResponses", 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') @@ -1935,7 +1956,10 @@ class Demographic(Base): 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') + + # associate the category arXiv_category = relationship('Category', primaryjoin='and_(Demographic.archive == Category.archive, Demographic.subject_class == Category.subject_class)', backref='arXiv_demographics') GROUP_FLAGS = [ @@ -1974,6 +1998,7 @@ class QueueView(Base): total_views: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + class SuspiciousName(Base): __tablename__ = 'arXiv_suspicious_names' @@ -2023,6 +2048,155 @@ class TapirUsersPassword(Base): user = relationship('TapirUser') +class ArXivCheckResults(Base): + __tablename__ = 'arXiv_check_results' + __table_args__ = ( + ForeignKeyConstraint(['check_id'], ['arXiv_checks.check_id'], name='check_results_checks_fk'), + ForeignKeyConstraint(['submission_id'], ['arXiv_submissions.submission_id'], name='check_results_sub_fk'), + ForeignKeyConstraint(['user_id'], ['tapir_users.user_id'], name='check_results_user_fk') + ) + + check_result_id: Mapped[int] = mapped_column(Integer, primary_key=True) + submission_id: Mapped[int] = mapped_column(Integer, 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(Integer, nullable=False, index=True) + user_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) + ok: Mapped[int] = mapped_column(Integer, nullable=False) + created: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=text('CURRENT_TIMESTAMP')) + message: Mapped[Optional[str]] = mapped_column(String(40)) + data: Mapped[Optional[str]] = mapped_column(String(2000)) + + check: Mapped['ArXivChecks'] = relationship('ArXivChecks', back_populates='arXiv_check_results') + submission: Mapped['Submission'] = relationship('Submission', back_populates='arXiv_check_results') + user: Mapped['TapirUser'] = relationship('TapirUser', back_populates='arXiv_check_results') + arXiv_check_responses: Mapped[List['ArXivCheckResponses']] = relationship('ArXivCheckResponses', back_populates='check_result') + + +class ArXivCheckResponses(Base): + __tablename__ = 'arXiv_check_responses' + __table_args__ = ( + ForeignKeyConstraint(['check_result_id'], ['arXiv_check_results.check_result_id'], name='check_responses_results_fk'), + ForeignKeyConstraint(['user_id'], ['tapir_users.user_id'], name='check_responses_user_fk') + ) + + check_response_id: Mapped[int] = mapped_column(Integer, primary_key=True) + check_result_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) + user_id: Mapped[int] = mapped_column(Integer, 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=text('CURRENT_TIMESTAMP')) + message: Mapped[Optional[str]] = mapped_column(String(200)) + + check_result: Mapped['ArXivCheckResults'] = relationship('ArXivCheckResults', back_populates='arXiv_check_responses') + user: Mapped['TapirUser'] = relationship('TapirUser', back_populates='arXiv_check_responses') + + +class ArXivCheckResultViews(Base): + __tablename__ = 'arXiv_check_result_views' + + 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)) + + arXiv_checks: Mapped[List['ArXivChecks']] = relationship('ArXivChecks', back_populates='check_result_view') + + +class ArXivCheckRoles(Base): + __tablename__ = 'arXiv_check_roles' + + 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)) + + arXiv_checks: Mapped[List['ArXivChecks']] = relationship('ArXivChecks', back_populates='check_role') + + +class ArXivCheckTargets(Base): + __tablename__ = 'arXiv_check_targets' + + 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)) + + arXiv_checks: Mapped[List['ArXivChecks']] = relationship('ArXivChecks', back_populates='check_target') + + +class ArXivChecks(Base): + __tablename__ = 'arXiv_checks' + __table_args__ = ( + ForeignKeyConstraint(['check_result_view_id'], ['arXiv_check_result_views.check_result_view_id'], name='checks_result_views_fk'), + ForeignKeyConstraint(['check_role_id'], ['arXiv_check_roles.check_role_id'], name='checks_roles_fk'), + ForeignKeyConstraint(['check_target_id'], ['arXiv_check_targets.check_target_id'], name='checks_content_fk') + ) + + check_id: Mapped[int] = mapped_column(Integer, primary_key=True) + check_target_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) + check_role_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) + check_result_view_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'1'")) + name: Mapped[str] = mapped_column(String(40), nullable=False) + 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'")) + description: Mapped[Optional[str]] = mapped_column(String(200)) + + check_result_view: Mapped['ArXivCheckResultViews'] = relationship('ArXivCheckResultViews', back_populates='arXiv_checks') + check_role: Mapped['ArXivCheckRoles'] = relationship('ArXivCheckRoles', back_populates='arXiv_checks') + check_target: Mapped['ArXivCheckTargets'] = relationship('ArXivCheckTargets', back_populates='arXiv_checks') + arXiv_check_results: Mapped[List['ArXivCheckResults']] = relationship('ArXivCheckResults', back_populates='check') + + + +class ArXivSubmissionLocks(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' diff --git a/arxiv/db/tests/test_db_schema.py b/arxiv/db/tests/test_db_schema.py index 8104fb61b..63da365fb 100644 --- a/arxiv/db/tests/test_db_schema.py +++ b/arxiv/db/tests/test_db_schema.py @@ -1,14 +1,16 @@ 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 test_db_schema(): - db_engine = create_engine(os.environ['TEST_ARXIV_DB_URI']) +def _make_schemas(db_uri: str): + db_engine = create_engine(db_uri) SessionLocal = sessionmaker(autocommit=False, autoflush=True) SessionLocal.configure(bind=db_engine) @@ -21,3 +23,29 @@ def test_db_schema(): LaTeXMLBase.metadata.create_all(db_engine) db_session.commit() + + +def test_db_schema(): + db_uri = os.environ.get('TEST_ARXIV_DB_URI') + if db_uri is None: + print("db_uri is not defined") + 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/development/db_codegen.py b/development/db_codegen.py index 72aab6e61..7e61f70cd 100644 --- a/development/db_codegen.py +++ b/development/db_codegen.py @@ -4,11 +4,17 @@ import os import subprocess from typing import Tuple +import logging + +from libcst.matchers import SimpleStatementLine from ruamel.yaml import YAML # import ast import libcst as cst +logging.basicConfig(level=logging.INFO) + + tables_i_cannot_update = { 'DBLPAuthor': True, 'TapirNicknamesAudit': True, @@ -48,11 +54,11 @@ def patch_mysql_types(contents: str): (re.compile(r'Mapped\[decimal.Decimal\]'), r'Mapped[float]'), # (re.compile(r'Mapped\[datetime.datetime\]'), r'Mapped[datetime]'), # (re.compile(r'Optional\[datetime.datetime\]'), r'Optional[datetime]'), # - (re.compile(r'INTEGER\(\d+\)'), r'Integer'), - (re.compile(r'TINYINT\(\d+\)'), r'Integer'), - (re.compile(r'MEDIUMINT\(\d+\)'), r'Integer'), - (re.compile(r'SMALLINT\(\d+\)'), r'Integer'), - (re.compile(r'MEDIUMTEXT'), r'Text'), + (re.compile(r'INTEGER(\(\d+\)){0,1}'), r'Integer'), + (re.compile(r'TINYINT(\(\d+\)){0,1}'), r'Integer'), + (re.compile(r'MEDIUMINT(\(\d+\)){0,1}'), r'Integer'), + (re.compile(r'SMALLINT(\(\d+\)){0,1}'), r'Integer'), + (re.compile(r'MEDIUMTEXT(\(\d+\)){0,1}'), r'Text'), (re.compile(r'text\("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"\)'), r'FetchdValue()'), (re.compile(r'datetime\.date'), r'dt.date'), @@ -142,7 +148,8 @@ def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef if target in existing_assignments: existing_elem = existing_assignments[target] # Use the original element if it's marked as int primary key or similar - if self.is_intpk(existing_elem): + # 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): @@ -165,6 +172,28 @@ def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef if not is_assign_expr(elem): updated_body.append(elem) + if existing_assignments: + logging.info("#========================================================================") + logging.info(f"# {class_name}") + for remain_key, remain_value in existing_assignments.items(): + logging.info(f" {remain_key}") + logging.info("#========================================================================") + + a_key: str + 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) + 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) + continue + # Rebuild the class body with updated assignments return updated_node.with_changes(body=updated_node.body.with_changes(body=updated_body)) return updated_node @@ -189,6 +218,11 @@ def is_intpk(self, elem): return True return False + def has_comment(self, elem): + if isinstance(elem, cst.SimpleStatementLine): + return elem.leading_lines and elem.leading_lines[-1].comment + return False + def leave_Assign(self, original_node: cst.Assign, updated_node: cst.Assign) -> cst.CSTNode: # Check if the value of the assignment is a Table call lhs_name = original_node.targets[0].target.value @@ -200,6 +234,12 @@ def leave_Assign(self, original_node: cst.Assign, updated_node: cst.Assign) -> c 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 + # updated_node = updated_node.with_changes(value=) rh_new = latest_table_def.value rh_old = updated_node.value @@ -238,17 +278,25 @@ def leave_Assign(self, original_node: cst.Assign, updated_node: cst.Assign) -> c def main() -> None: p_outfile = "arxiv/db/autogen_models.py" - # #with open(os.path.expanduser('~/.arxiv/arxiv-db-prod-readonly'), encoding='utf-8') as uri_fd: # p_url: str = uri_fd.read().strip() + #with open(os.path.expanduser('~/.arxiv/arxiv-db-dev-proxy'), encoding='utf-8') as uri_fd: + # p_url: str = uri_fd.read().strip() p_url = "mysql://testuser:testpassword@127.0.0.1/testdb" sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "sqlacodegen", "src")) subprocess.run(['development/sqlacodegen/venv/bin/python', '-m', 'sqlacodegen', p_url, '--outfile', p_outfile, '--model-metadata', "arxiv/db/arxiv-db-metadata.yaml"], check=True) + subprocess.run(['development/sqlacodegen/venv/bin/python', '-m', 'sqlacodegen', p_url, '--outfile', "arxiv/db/raw-autogen_models.py"], check=True) + with open(p_outfile, 'r') as src: source = src.read() - latest_tree = cst.parse_module(source) + try: + latest_tree = cst.parse_module(source) + except Exception as exc: + logging.error("%s: failed to parse", p_outfile, exc_info=exc) + exit(1) + latest_def = {} latest_tables = {} @@ -274,7 +322,7 @@ def main() -> None: contents = patch_mysql_types(contents) with open(updated_model, 'w', encoding='utf-8') as updated_fd: updated_fd.write(contents) - subprocess.run(['black', updated_model]) + subprocess.run(['black', "-l", "200", updated_model]) if __name__ == "__main__": diff --git a/poetry.lock b/poetry.lock index 6d20bed87..25fcccba7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -30,6 +30,20 @@ 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]"] +[[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" @@ -44,6 +58,50 @@ files = [ [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" @@ -310,6 +368,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" @@ -445,6 +520,20 @@ files = [ {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, ] +[[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" @@ -538,6 +627,43 @@ Boto3 = ">=1.1.1" Flask = "*" six = "*" +[[package]] +name = "functions-framework" +version = "3.8.1" +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.1-py3-none-any.whl", hash = "sha256:fc5a09b55753838d438d473bdf8407182b47b7717404af093a4ea4250b54b326"}, + {file = "functions_framework-3.8.1.tar.gz", hash = "sha256:f976d59701f9a6bbb2fd192bf5407f691c274bbeb0dc5b7e07d76a3400fac1e7"}, +] + +[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" @@ -618,6 +744,37 @@ files = [ 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" +[[package]] +name = "google-cloud-bigquery" +version = "3.26.0" +description = "Google BigQuery API client library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "google_cloud_bigquery-3.26.0-py2.py3-none-any.whl", hash = "sha256:e0e9ad28afa67a18696e624cbccab284bf2c0a3f6eeb9eeb0426c69b943793a8"}, + {file = "google_cloud_bigquery-3.26.0.tar.gz", hash = "sha256:edbdc788beea659e04c0af7fe4dcd6d9155344b98951a0d5055bd2f15da4ba23"}, +] + +[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" version = "2.4.1" @@ -999,6 +1156,27 @@ googleapis-common-protos = ">=1.5.5" grpcio = ">=1.62.2" protobuf = ">=4.21.6" +[[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" version = "0.14.0" @@ -1152,6 +1330,52 @@ files = [ cryptography = ">=3.4" typing-extensions = ">=4.5.0" +[[package]] +name = "libcst" +version = "1.5.0" +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.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:23d0e07fd3ed11480f8993a1e99d58a45f914a711b14f858b8db08ae861a8a34"}, + {file = "libcst-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d92c5ae2e2dc9356ad7e3d05077d9b7e5065423e45788fd86729c88729e45c6e"}, + {file = "libcst-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96adc45e96476350df6b8a5ddbb1e1d6a83a7eb3f13087e52eb7cd2f9b65bcc7"}, + {file = "libcst-1.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d5978fd60c66794bb60d037b2e6427ea52d032636e84afce32b0f04e1cf500a"}, + {file = "libcst-1.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6502aeb11412afc759036160c686be1107eb5a4466db56b207c786b9b4da7c4"}, + {file = "libcst-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:9cccfc0a78e110c0d0a9d2c6fdeb29feb5274c9157508a8baef7edf352420f6d"}, + {file = "libcst-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:585b3aa705b3767d717d2100935d8ef557275ecdd3fac81c3e28db0959efb0ea"}, + {file = "libcst-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8935dd3393e30c2f97344866a4cb14efe560200e232166a8db1de7865c2ef8b2"}, + {file = "libcst-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc80ea16c7d44e38f193e4d4ef7ff1e0ba72d8e60e8b61ac6f4c87f070a118bd"}, + {file = "libcst-1.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02be4aab728261bb76d16e77c9a457884cebb60d09c8edee844de43b0e08aff7"}, + {file = "libcst-1.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a8fcd78be4d9ce3c36d0c5d0bdd384e0c7d5f72970a9e4ebd56070141972b4ad"}, + {file = "libcst-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:52b6aadfe54e3ae52c3b815eaaa17ba4da9ff010d5e8adf6a70697872886dd10"}, + {file = "libcst-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:83bc5fbe34d33597af1d5ea113dcb9b5dd5afe5a5f4316bac4293464d5e3971a"}, + {file = "libcst-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5f10124bf99a0b075eae136ef0ce06204e5f6b8da4596a9c4853a0663e80ddf3"}, + {file = "libcst-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48e581af6127c5af4c9f483e5986d94f0c6b2366967ee134f0a8eba0aa4c8c12"}, + {file = "libcst-1.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7dba93cca0a5c6d771ed444c44d21ce8ea9b277af7036cea3743677aba9fbbb8"}, + {file = "libcst-1.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80b5c4d87721a7bab265c202575809b810815ab81d5e2e7a5d4417a087975840"}, + {file = "libcst-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:b48bf71d52c1e891a0948465a94d9817b5fc1ec1a09603566af90585f3b11948"}, + {file = "libcst-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:88520b6dea59eaea0cae80f77c0a632604a82c5b2d23dedb4b5b34035cbf1615"}, + {file = "libcst-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:208ea92d80b2eeed8cbc879d5f39f241582a5d56b916b1b65ed2be2f878a2425"}, + {file = "libcst-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4592872aaf5b7fa5c2727a7d73c0985261f1b3fe7eff51f4fd5b8174f30b4e2"}, + {file = "libcst-1.5.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2788b2b5838b78fe15df8e9fa6b6903195ea49b2d2ba43e8f423f6c90e4b69f"}, + {file = "libcst-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b5b5bcd3a9ba92840f27ad34eaa038acbee195ec337da39536c0a2efbbf28efd"}, + {file = "libcst-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:4d6acb0bdee1e55b44c6215c59755ec4693ac01e74bb1fde04c37358b378835d"}, + {file = "libcst-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6453b5a8755a6eee3ad67ee246f13a8eac9827d2cfc8e4a269e8bf0393db74bc"}, + {file = "libcst-1.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:40748361f4ea66ab6cdd82f8501c82c29808317ac7a3bd132074efd5fd9bfae2"}, + {file = "libcst-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f71aed85932c2ea92058fd9bbd99a6478bd69eada041c3726b4f4c9af1f564e"}, + {file = "libcst-1.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60b09abcc2848ab52d479c3a9b71b606d91a941e3779616efd083bb87dbe8ad"}, + {file = "libcst-1.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fb324ed20f3a725d152df5dba8d80f7e126d9c93cced581bf118a5fc18c1065"}, + {file = "libcst-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:99e7c52150a135d66716b03e00c7b1859a44336dc2a2bf8f9acc164494308531"}, + {file = "libcst-1.5.0.tar.gz", hash = "sha256:8478abf21ae3861a073e898d80b822bd56e578886331b33129ba77fec05b8c24"}, +] + +[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" @@ -1322,6 +1546,68 @@ files = [ {file = "mysqlclient-2.2.4.tar.gz", hash = "sha256:33bc9fb3464e7d7c10b1eaf7336c5ff8f2a3d3b88bab432116ad2490beb3bf41"}, ] +[[package]] +name = "numpy" +version = "2.1.2" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.10" +files = [ + {file = "numpy-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:30d53720b726ec36a7f88dc873f0eec8447fbc93d93a8f079dfac2629598d6ee"}, + {file = "numpy-2.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8d3ca0a72dd8846eb6f7dfe8f19088060fcb76931ed592d29128e0219652884"}, + {file = "numpy-2.1.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:fc44e3c68ff00fd991b59092a54350e6e4911152682b4782f68070985aa9e648"}, + {file = "numpy-2.1.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:7c1c60328bd964b53f8b835df69ae8198659e2b9302ff9ebb7de4e5a5994db3d"}, + {file = "numpy-2.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6cdb606a7478f9ad91c6283e238544451e3a95f30fb5467fbf715964341a8a86"}, + {file = "numpy-2.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d666cb72687559689e9906197e3bec7b736764df6a2e58ee265e360663e9baf7"}, + {file = "numpy-2.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c6eef7a2dbd0abfb0d9eaf78b73017dbfd0b54051102ff4e6a7b2980d5ac1a03"}, + {file = "numpy-2.1.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:12edb90831ff481f7ef5f6bc6431a9d74dc0e5ff401559a71e5e4611d4f2d466"}, + {file = "numpy-2.1.2-cp310-cp310-win32.whl", hash = "sha256:a65acfdb9c6ebb8368490dbafe83c03c7e277b37e6857f0caeadbbc56e12f4fb"}, + {file = "numpy-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:860ec6e63e2c5c2ee5e9121808145c7bf86c96cca9ad396c0bd3e0f2798ccbe2"}, + {file = "numpy-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b42a1a511c81cc78cbc4539675713bbcf9d9c3913386243ceff0e9429ca892fe"}, + {file = "numpy-2.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:faa88bc527d0f097abdc2c663cddf37c05a1c2f113716601555249805cf573f1"}, + {file = "numpy-2.1.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:c82af4b2ddd2ee72d1fc0c6695048d457e00b3582ccde72d8a1c991b808bb20f"}, + {file = "numpy-2.1.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:13602b3174432a35b16c4cfb5de9a12d229727c3dd47a6ce35111f2ebdf66ff4"}, + {file = "numpy-2.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ebec5fd716c5a5b3d8dfcc439be82a8407b7b24b230d0ad28a81b61c2f4659a"}, + {file = "numpy-2.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2b49c3c0804e8ecb05d59af8386ec2f74877f7ca8fd9c1e00be2672e4d399b1"}, + {file = "numpy-2.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2cbba4b30bf31ddbe97f1c7205ef976909a93a66bb1583e983adbd155ba72ac2"}, + {file = "numpy-2.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8e00ea6fc82e8a804433d3e9cedaa1051a1422cb6e443011590c14d2dea59146"}, + {file = "numpy-2.1.2-cp311-cp311-win32.whl", hash = "sha256:5006b13a06e0b38d561fab5ccc37581f23c9511879be7693bd33c7cd15ca227c"}, + {file = "numpy-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:f1eb068ead09f4994dec71c24b2844f1e4e4e013b9629f812f292f04bd1510d9"}, + {file = "numpy-2.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d7bf0a4f9f15b32b5ba53147369e94296f5fffb783db5aacc1be15b4bf72f43b"}, + {file = "numpy-2.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b1d0fcae4f0949f215d4632be684a539859b295e2d0cb14f78ec231915d644db"}, + {file = "numpy-2.1.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:f751ed0a2f250541e19dfca9f1eafa31a392c71c832b6bb9e113b10d050cb0f1"}, + {file = "numpy-2.1.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:bd33f82e95ba7ad632bc57837ee99dba3d7e006536200c4e9124089e1bf42426"}, + {file = "numpy-2.1.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b8cde4f11f0a975d1fd59373b32e2f5a562ade7cde4f85b7137f3de8fbb29a0"}, + {file = "numpy-2.1.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d95f286b8244b3649b477ac066c6906fbb2905f8ac19b170e2175d3d799f4df"}, + {file = "numpy-2.1.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ab4754d432e3ac42d33a269c8567413bdb541689b02d93788af4131018cbf366"}, + {file = "numpy-2.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e585c8ae871fd38ac50598f4763d73ec5497b0de9a0ab4ef5b69f01c6a046142"}, + {file = "numpy-2.1.2-cp312-cp312-win32.whl", hash = "sha256:9c6c754df29ce6a89ed23afb25550d1c2d5fdb9901d9c67a16e0b16eaf7e2550"}, + {file = "numpy-2.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:456e3b11cb79ac9946c822a56346ec80275eaf2950314b249b512896c0d2505e"}, + {file = "numpy-2.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a84498e0d0a1174f2b3ed769b67b656aa5460c92c9554039e11f20a05650f00d"}, + {file = "numpy-2.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4d6ec0d4222e8ffdab1744da2560f07856421b367928026fb540e1945f2eeeaf"}, + {file = "numpy-2.1.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:259ec80d54999cc34cd1eb8ded513cb053c3bf4829152a2e00de2371bd406f5e"}, + {file = "numpy-2.1.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:675c741d4739af2dc20cd6c6a5c4b7355c728167845e3c6b0e824e4e5d36a6c3"}, + {file = "numpy-2.1.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05b2d4e667895cc55e3ff2b56077e4c8a5604361fc21a042845ea3ad67465aa8"}, + {file = "numpy-2.1.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43cca367bf94a14aca50b89e9bc2061683116cfe864e56740e083392f533ce7a"}, + {file = "numpy-2.1.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:76322dcdb16fccf2ac56f99048af32259dcc488d9b7e25b51e5eca5147a3fb98"}, + {file = "numpy-2.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:32e16a03138cabe0cb28e1007ee82264296ac0983714094380b408097a418cfe"}, + {file = "numpy-2.1.2-cp313-cp313-win32.whl", hash = "sha256:242b39d00e4944431a3cd2db2f5377e15b5785920421993770cddb89992c3f3a"}, + {file = "numpy-2.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:f2ded8d9b6f68cc26f8425eda5d3877b47343e68ca23d0d0846f4d312ecaa445"}, + {file = "numpy-2.1.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2ffef621c14ebb0188a8633348504a35c13680d6da93ab5cb86f4e54b7e922b5"}, + {file = "numpy-2.1.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:ad369ed238b1959dfbade9018a740fb9392c5ac4f9b5173f420bd4f37ba1f7a0"}, + {file = "numpy-2.1.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d82075752f40c0ddf57e6e02673a17f6cb0f8eb3f587f63ca1eaab5594da5b17"}, + {file = "numpy-2.1.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:1600068c262af1ca9580a527d43dc9d959b0b1d8e56f8a05d830eea39b7c8af6"}, + {file = "numpy-2.1.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a26ae94658d3ba3781d5e103ac07a876b3e9b29db53f68ed7df432fd033358a8"}, + {file = "numpy-2.1.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13311c2db4c5f7609b462bc0f43d3c465424d25c626d95040f073e30f7570e35"}, + {file = "numpy-2.1.2-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:2abbf905a0b568706391ec6fa15161fad0fb5d8b68d73c461b3c1bab6064dd62"}, + {file = "numpy-2.1.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ef444c57d664d35cac4e18c298c47d7b504c66b17c2ea91312e979fcfbdfb08a"}, + {file = "numpy-2.1.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:bdd407c40483463898b84490770199d5714dcc9dd9b792f6c6caccc523c00952"}, + {file = "numpy-2.1.2-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:da65fb46d4cbb75cb417cddf6ba5e7582eb7bb0b47db4b99c9fe5787ce5d91f5"}, + {file = "numpy-2.1.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c193d0b0238638e6fc5f10f1b074a6993cb13b0b431f64079a509d63d3aa8b7"}, + {file = "numpy-2.1.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a7d80b2e904faa63068ead63107189164ca443b42dd1930299e0d1cb041cec2e"}, + {file = "numpy-2.1.2.tar.gz", hash = "sha256:13532a088217fa624c99b843eeb54640de23b3414b14aa66d023805eb731066c"}, +] + [[package]] name = "outcome" version = "1.3.0.post0" @@ -1347,6 +1633,47 @@ files = [ {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, ] +[[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.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 = "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" @@ -1435,6 +1762,17 @@ files = [ [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" @@ -1638,6 +1976,68 @@ files = [ {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, ] +[[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]] name = "redis" version = "2.10.6" @@ -1975,32 +2375,6 @@ lint = ["docutils-stubs", "flake8", "mypy"] test = ["pytest"] whoosh = ["sqlalchemy", "whoosh"] -[[package]] -name = "sqlacodegen" -version = "3.0.0rc5.post1" -description = "Automatic model code generator for SQLAlchemy" -optional = false -python-versions = ">=3.8" -files = [] -develop = false - -[package.dependencies] -inflect = ">=4.0.0" -SQLAlchemy = ">=2.0.23" - -[package.extras] -citext = ["sqlalchemy-citext (>=1.7.0)"] -geoalchemy2 = ["geoalchemy2 (>=0.11.1)"] -pgvector = ["pgvector (>=0.2.4)"] -sqlmodel = ["sqlmodel (>=0.0.12)"] -test = ["coverage (>=7)", "mysql-connector-python", "psycopg2-binary", "pytest (>=7.4)"] - -[package.source] -type = "git" -url = "https://github.com/agronholm/sqlacodegen.git" -reference = "HEAD" -resolved_reference = "eb7b95f47ea854291fd9db02c673f7de0f33f41f" - [[package]] name = "sqlalchemy" version = "2.0.30" @@ -2088,6 +2462,34 @@ 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" @@ -2210,6 +2612,48 @@ files = [ {file = "validators-0.28.1.tar.gz", hash = "sha256:5ac88e7916c3405f0ce38ac2ac82a477fcf4d90dbbeddd04c8193171fc17f7dc"}, ] +[[package]] +name = "watchdog" +version = "5.0.3" +description = "Filesystem events monitoring" +optional = false +python-versions = ">=3.9" +files = [ + {file = "watchdog-5.0.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:85527b882f3facda0579bce9d743ff7f10c3e1e0db0a0d0e28170a7d0e5ce2ea"}, + {file = "watchdog-5.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:53adf73dcdc0ef04f7735066b4a57a4cd3e49ef135daae41d77395f0b5b692cb"}, + {file = "watchdog-5.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e25adddab85f674acac303cf1f5835951345a56c5f7f582987d266679979c75b"}, + {file = "watchdog-5.0.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f01f4a3565a387080dc49bdd1fefe4ecc77f894991b88ef927edbfa45eb10818"}, + {file = "watchdog-5.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:91b522adc25614cdeaf91f7897800b82c13b4b8ac68a42ca959f992f6990c490"}, + {file = "watchdog-5.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d52db5beb5e476e6853da2e2d24dbbbed6797b449c8bf7ea118a4ee0d2c9040e"}, + {file = "watchdog-5.0.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:94d11b07c64f63f49876e0ab8042ae034674c8653bfcdaa8c4b32e71cfff87e8"}, + {file = "watchdog-5.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:349c9488e1d85d0a58e8cb14222d2c51cbc801ce11ac3936ab4c3af986536926"}, + {file = "watchdog-5.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:53a3f10b62c2d569e260f96e8d966463dec1a50fa4f1b22aec69e3f91025060e"}, + {file = "watchdog-5.0.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:950f531ec6e03696a2414b6308f5c6ff9dab7821a768c9d5788b1314e9a46ca7"}, + {file = "watchdog-5.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ae6deb336cba5d71476caa029ceb6e88047fc1dc74b62b7c4012639c0b563906"}, + {file = "watchdog-5.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1021223c08ba8d2d38d71ec1704496471ffd7be42cfb26b87cd5059323a389a1"}, + {file = "watchdog-5.0.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:752fb40efc7cc8d88ebc332b8f4bcbe2b5cc7e881bccfeb8e25054c00c994ee3"}, + {file = "watchdog-5.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a2e8f3f955d68471fa37b0e3add18500790d129cc7efe89971b8a4cc6fdeb0b2"}, + {file = "watchdog-5.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b8ca4d854adcf480bdfd80f46fdd6fb49f91dd020ae11c89b3a79e19454ec627"}, + {file = "watchdog-5.0.3-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:90a67d7857adb1d985aca232cc9905dd5bc4803ed85cfcdcfcf707e52049eda7"}, + {file = "watchdog-5.0.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:720ef9d3a4f9ca575a780af283c8fd3a0674b307651c1976714745090da5a9e8"}, + {file = "watchdog-5.0.3-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:223160bb359281bb8e31c8f1068bf71a6b16a8ad3d9524ca6f523ac666bb6a1e"}, + {file = "watchdog-5.0.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:560135542c91eaa74247a2e8430cf83c4342b29e8ad4f520ae14f0c8a19cfb5b"}, + {file = "watchdog-5.0.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:dd021efa85970bd4824acacbb922066159d0f9e546389a4743d56919b6758b91"}, + {file = "watchdog-5.0.3-py3-none-manylinux2014_armv7l.whl", hash = "sha256:78864cc8f23dbee55be34cc1494632a7ba30263951b5b2e8fc8286b95845f82c"}, + {file = "watchdog-5.0.3-py3-none-manylinux2014_i686.whl", hash = "sha256:1e9679245e3ea6498494b3028b90c7b25dbb2abe65c7d07423ecfc2d6218ff7c"}, + {file = "watchdog-5.0.3-py3-none-manylinux2014_ppc64.whl", hash = "sha256:9413384f26b5d050b6978e6fcd0c1e7f0539be7a4f1a885061473c5deaa57221"}, + {file = "watchdog-5.0.3-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:294b7a598974b8e2c6123d19ef15de9abcd282b0fbbdbc4d23dfa812959a9e05"}, + {file = "watchdog-5.0.3-py3-none-manylinux2014_s390x.whl", hash = "sha256:26dd201857d702bdf9d78c273cafcab5871dd29343748524695cecffa44a8d97"}, + {file = "watchdog-5.0.3-py3-none-manylinux2014_x86_64.whl", hash = "sha256:0f9332243355643d567697c3e3fa07330a1d1abf981611654a1f2bf2175612b7"}, + {file = "watchdog-5.0.3-py3-none-win32.whl", hash = "sha256:c66f80ee5b602a9c7ab66e3c9f36026590a0902db3aea414d59a2f55188c1f49"}, + {file = "watchdog-5.0.3-py3-none-win_amd64.whl", hash = "sha256:f00b4cf737f568be9665563347a910f8bdc76f88c2970121c86243c8cfdf90e9"}, + {file = "watchdog-5.0.3-py3-none-win_ia64.whl", hash = "sha256:49f4d36cb315c25ea0d946e018c01bb028048023b9e103d3d3943f58e109dd45"}, + {file = "watchdog-5.0.3.tar.gz", hash = "sha256:108f42a7f0345042a854d4d0ad0834b741d421330d5f575b81cb27b883500176"}, +] + +[package.extras] +watchmedo = ["PyYAML (>=3.10)"] + [[package]] name = "webencodings" version = "0.5.1" @@ -2291,4 +2735,4 @@ sphinx = ["sphinx", "sphinx-autodoc-typehints", "sphinxcontrib-websupport"] [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "4c3b31b0ae121a5901272bbe5d032c0be8bf485ae5b423959b9b4c59cea3cd57" +content-hash = "1fd6410a2d7ef0d0c685b389e70f002b3924608a7122711cd4b84a22cfb669f4" diff --git a/pyproject.toml b/pyproject.toml index 0227754bd..7ee011bca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,9 +53,11 @@ pytest-mock = "^3.8.2" pytest-cov = "*" hypothesis = "*" fakeredis = "*" -sqlacodegen = {git = "https://github.com/agronholm/sqlacodegen.git"} - click = "*" +sqlmodel = "*" +sqlalchemy-citext = "*" +geoalchemy2 = "*" +pgvector = "*" [tool.poetry.extras] sphinx = [ "sphinx", "sphinxcontrib-websupport", "sphinx-autodoc-typehints" ] @@ -63,6 +65,15 @@ sphinx = [ "sphinx", "sphinxcontrib-websupport", "sphinx-autodoc-typehints" ] [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 From bc340088a774cd58ce2da206c85d190cdb840e5a Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Wed, 6 Nov 2024 09:55:08 -0500 Subject: [PATCH 06/32] Save the current db schema, and remove unused file. --- development/arxiv_schema_dump.sql | 3067 +++++++++++++++++++++++++++++ development/patch_db_models.py | 0 2 files changed, 3067 insertions(+) create mode 100644 development/arxiv_schema_dump.sql delete mode 100644 development/patch_db_models.py diff --git a/development/arxiv_schema_dump.sql b/development/arxiv_schema_dump.sql new file mode 100644 index 000000000..68b842f07 --- /dev/null +++ b/development/arxiv_schema_dump.sql @@ -0,0 +1,3067 @@ +-- MySQL dump 10.13 Distrib 8.0.39, for Linux (x86_64) +-- +-- Host: 127.0.0.1 Database: arXiv +-- ------------------------------------------------------ +-- Server version 5.7.44-google-log + +/*!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 */; +/*!50503 SET NAMES utf8mb4 */; +/*!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=/*!80000 '+'*/ '2d19f914-b050-11e7-95e6-005056a34791:1-563686703, +c713b996-7f87-11ef-8e22-42010a5ee117:1-12'; + +-- +-- Table structure for table `Subscription_UniversalInstitution` +-- + +DROP TABLE IF EXISTS `Subscription_UniversalInstitution`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +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=479 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=1485 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=21260 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=37722030 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=136000 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=21 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=796639 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=4 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=188641 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=6 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=5 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=28 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=114 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=16777215 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=2608822 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=287964 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=1091105 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=4126037 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=583872 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=3671365 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=61970 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=233482 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=3080 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=1980104 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=4 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=465344 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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, + 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=655595 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=112275 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=54261 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=5966693 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=309 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=1868897 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=1051 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=73019 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=23 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=289744 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=1329214 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=16 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=1029043 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=4 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=422 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=22707799 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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=1082745 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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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 */; +/*!50503 SET character_set_client = utf8mb4 */; +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-10-30 14:30:10 diff --git a/development/patch_db_models.py b/development/patch_db_models.py deleted file mode 100644 index e69de29bb..000000000 From 6444980e1a8695feb0c0e5167a5af1cbbd349e40 Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Wed, 6 Nov 2024 15:24:59 -0500 Subject: [PATCH 07/32] Cooking down the codegen override as small as possible. --- arxiv/db/arxiv-db-metadata.yaml | 32 +++++++++---------- arxiv/db/models.py | 14 +++------ arxiv/db/orig_models.py | 3 +- development/README.md | 0 development/arxiv_schema_dump.sql | 52 +++++++++++++++---------------- development/db_codegen.py | 51 +++++++++++++++++++++--------- 6 files changed, 85 insertions(+), 67 deletions(-) create mode 100644 development/README.md diff --git a/arxiv/db/arxiv-db-metadata.yaml b/arxiv/db/arxiv-db-metadata.yaml index 9b83aef49..a2ebd2a98 100644 --- a/arxiv/db/arxiv-db-metadata.yaml +++ b/arxiv/db/arxiv-db-metadata.yaml @@ -1,3 +1,16 @@ +# +# 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. +# +# Generally, sqlacodegen is driven from development/db_codegen.py +# Subscription_UniversalInstitution: class_name: MemberInstitution relationships: @@ -43,12 +56,7 @@ arXiv_bogus_countries: class_name: BogusCountries arXiv_categories: class_name: Category - relationships: - # give arXiv_demographics to use diffent back-ref name: demographic_categories - # don't forget to have this name on Demographic - arXiv_demographics: "" additional_relationships: - - "demographic_categories: Mapped['Demographic'] = relationship('Demographic', back_populates='demographic_categories') # do not ues 'arXiv_archive ='" - "arXiv_endorsement_domain = relationship('EndorsementDomain', primaryjoin='Category.endorsement_domain == EndorsementDomain.endorsement_domain', back_populates='arXiv_categories')" arXiv_questionable_categories: @@ -82,11 +90,7 @@ arXiv_documents: relationships: arXiv_dblp_document_authors: "" additional_relationships: - # This is a bit of hack - - | - @property - def owners(self): - return self.arXiv_paper_owners + - "owners = relationship('PaperOwner', back_populates='document')" arXiv_dblp: class_name: DBLP @@ -145,7 +149,7 @@ arXiv_metadata: document: "relationship('Document', primaryjoin='Metadata.document_id == Document.document_id', back_populates='arXiv_metadata')" arXiv_license: "relationship('License', primaryjoin='Metadata.license == License.name', back_populates='arXiv_metadata_licenses')" submitter: "relationship('TapirUser', primaryjoin='Metadata.submitter_id == TapirUser.user_id', back_populates='arXiv_metadata')" - sword: Mapped["Tracking"] = relationship("Tracking", primaryjoin="Submission.sword_id == Tracking.sword_id", back_populates="arXiv_submissions_sowrd") + sword: "relationship('Tracking', primaryjoin='Submission.sword_id == Tracking.sword_id', back_populates='arXiv_submissions_sowrd')" arXiv_mirror_list: class_name: MirrorList @@ -219,7 +223,6 @@ arXiv_show_email_requests: class_name: ShowEmailRequest table_args: - replace: ["Index('email_reqs_user_id', 'user_id', 'dated'),", ""] - # - replace: ["Index('ix_arXiv_show_email_requests_dated', 'dated'),", ""] - replace: ["Index('user_id', 'user_id', 'dated')", "Index('email_reqs_user_id', 'user_id', 'dated')"] arXiv_state: class_name: State @@ -383,10 +386,7 @@ arXiv_author_ids: arXiv_demographics: class_name: Demographic relationships: - # I have to drop to avoid the confusion. Instead use "demographic_categories" - arXiv_categories: "" - additional_relationships: - - "demographic_categories: Mapped['Category'] = relationship('Category', back_populates='demographic_categories')" + arXiv_categories: "relationship('Category', primaryjoin='and_(Demographic.archive == Category.archive, Demographic.subject_class == Category.subject_class)', backref='category_demographics')" arXiv_orcid_ids: class_name: OrcidIds arXiv_queue_view: diff --git a/arxiv/db/models.py b/arxiv/db/models.py index f44432e1f..9d614f703 100644 --- a/arxiv/db/models.py +++ b/arxiv/db/models.py @@ -306,9 +306,9 @@ class Category(Base): arXiv_archives: Mapped["Archive"] = relationship("Archive", back_populates="arXiv_categories") arXiv_endorsement_domains: Mapped["EndorsementDomain"] = relationship("EndorsementDomain", back_populates="arXiv_categories") arXiv_cross_control: Mapped[List["CrossControl"]] = relationship("CrossControl", back_populates="arXiv_categories") + arXiv_demographics: Mapped[List["Demographic"]] = relationship("Demographic", back_populates="arXiv_categories") arXiv_endorsement_requests: Mapped[List["EndorsementRequest"]] = relationship("EndorsementRequest", back_populates="arXiv_categories") arXiv_endorsements: Mapped[List["Endorsement"]] = relationship("Endorsement", back_populates="arXiv_categories") - demographic_categories: Mapped["Demographic"] = relationship("Demographic", back_populates="demographic_categories") # do not ues 'arXiv_archive =' arXiv_endorsement_domain = relationship("EndorsementDomain", primaryjoin="Category.endorsement_domain == EndorsementDomain.endorsement_domain", back_populates="arXiv_categories") # link to category @@ -466,10 +466,7 @@ class Document(Base): 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") - - @property - def owners(self): - return self.arXiv_paper_owners + owners = relationship("PaperOwner", back_populates="document") class DBLP(Document): @@ -2004,7 +2001,9 @@ class Demographic(Base): subject_class: Mapped[Optional[str]] = mapped_column(String(16)) flag_group_physics: Mapped[Optional[int]] = mapped_column(Integer, index=True) - demographic_categories: Mapped["Category"] = relationship("Category", back_populates="demographic_categories") + arXiv_categories: Mapped["Category"] = relationship( + "Category", primaryjoin="and_(Demographic.archive == Category.archive, Demographic.subject_class == Category.subject_class)", backref="category_demographics" + ) @property def groups(self) -> List[str]: @@ -2014,9 +2013,6 @@ def groups(self) -> List[str]: # the original user user = relationship("TapirUser", back_populates="demographics") - # associate the category - 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"), diff --git a/arxiv/db/orig_models.py b/arxiv/db/orig_models.py index 144867515..c12d576b6 100644 --- a/arxiv/db/orig_models.py +++ b/arxiv/db/orig_models.py @@ -7,7 +7,7 @@ This file was generated by using arxiv/development/db_codegen.py along with arxiv/development/sqlacodegen -If anything that you want to keep over time, add comment with the intention/reason. +If you want to keep the model definition over time, add comment with the intention/reason. Without it, it may be subjected to removal. """ @@ -1959,7 +1959,6 @@ class Demographic(Base): # the original user user = relationship('TapirUser', back_populates='demographics') - # associate the category arXiv_category = relationship('Category', primaryjoin='and_(Demographic.archive == Category.archive, Demographic.subject_class == Category.subject_class)', backref='arXiv_demographics') GROUP_FLAGS = [ diff --git a/development/README.md b/development/README.md new file mode 100644 index 000000000..e69de29bb diff --git a/development/arxiv_schema_dump.sql b/development/arxiv_schema_dump.sql index 68b842f07..e3311cdd2 100644 --- a/development/arxiv_schema_dump.sql +++ b/development/arxiv_schema_dump.sql @@ -21,7 +21,7 @@ SET @@SESSION.SQL_LOG_BIN= 0; -- GTID state at the beginning of the backup -- -SET @@GLOBAL.GTID_PURGED=/*!80000 '+'*/ '2d19f914-b050-11e7-95e6-005056a34791:1-563686703, +SET @@GLOBAL.GTID_PURGED=/*!80000 '+'*/ '2d19f914-b050-11e7-95e6-005056a34791:1-566477503, c713b996-7f87-11ef-8e22-42010a5ee117:1-12'; -- @@ -112,7 +112,7 @@ CREATE TABLE `arXiv_admin_log` ( 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=37722030 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=37855801 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -347,7 +347,7 @@ CREATE TABLE `arXiv_bib_updates` ( `journal_ref` text, `doi` text, PRIMARY KEY (`update_id`) -) ENGINE=InnoDB AUTO_INCREMENT=796639 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=796789 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -505,7 +505,7 @@ CREATE TABLE `arXiv_check_results` ( 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=188641 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=198669 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -798,7 +798,7 @@ CREATE TABLE `arXiv_documents` ( 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=2608822 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=2614028 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -857,7 +857,7 @@ CREATE TABLE `arXiv_endorsement_requests` ( 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=287964 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=289081 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -906,7 +906,7 @@ CREATE TABLE `arXiv_endorsements` ( 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=1091105 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1093533 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -1095,7 +1095,7 @@ CREATE TABLE `arXiv_metadata` ( 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=4126037 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=4134837 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -1117,7 +1117,7 @@ CREATE TABLE `arXiv_mirror_list` ( 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=583872 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=584251 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -1233,7 +1233,7 @@ CREATE TABLE `arXiv_next_mail` ( 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=3671365 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=3680904 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -1286,7 +1286,7 @@ CREATE TABLE `arXiv_ownership_requests` ( 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=61970 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=62120 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -1533,7 +1533,7 @@ CREATE TABLE `arXiv_show_email_requests` ( 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=1980104 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1982787 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -1693,7 +1693,7 @@ CREATE TABLE `arXiv_submission_category_proposal` ( 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=465344 DEFAULT CHARSET=utf8; +) ENGINE=InnoDB AUTO_INCREMENT=467577 DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -1763,7 +1763,7 @@ CREATE TABLE `arXiv_submission_flag` ( 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=655595 DEFAULT CHARSET=utf8; +) ENGINE=InnoDB AUTO_INCREMENT=662304 DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -1787,7 +1787,7 @@ CREATE TABLE `arXiv_submission_hold_reason` ( 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=112275 DEFAULT CHARSET=utf8; +) ENGINE=InnoDB AUTO_INCREMENT=114140 DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -1810,7 +1810,7 @@ CREATE TABLE `arXiv_submission_locks` ( 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=54261 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=64547 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -1952,7 +1952,7 @@ CREATE TABLE `arXiv_submissions` ( 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=5966693 DEFAULT CHARSET=utf8; +) ENGINE=InnoDB AUTO_INCREMENT=5982750 DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -2082,7 +2082,7 @@ CREATE TABLE `arXiv_trackback_pings` ( KEY `arXiv_trackback_pings__url` (`url`), KEY `arXiv_trackback_pings__posted_date` (`posted_date`), KEY `arXiv_trackback_pings__status` (`status`) -) ENGINE=InnoDB AUTO_INCREMENT=1868897 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1868954 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -2116,7 +2116,7 @@ CREATE TABLE `arXiv_tracking` ( `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`tracking_id`), UNIQUE KEY `sword_id` (`sword_id`) -) ENGINE=InnoDB AUTO_INCREMENT=73019 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=73104 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -2396,7 +2396,7 @@ CREATE TABLE `tapir_admin_audit` ( 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=289744 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=290626 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -2521,7 +2521,7 @@ CREATE TABLE `tapir_email_log` ( `template_id` int(10) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`mail_id`), KEY `mailing_id` (`mailing_id`) -) ENGINE=InnoDB AUTO_INCREMENT=1329214 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1330693 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -2686,7 +2686,7 @@ CREATE TABLE `tapir_nicknames` ( KEY `role` (`role`), KEY `policy` (`policy`), CONSTRAINT `0_570` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) -) ENGINE=InnoDB AUTO_INCREMENT=1029043 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1031816 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -2834,7 +2834,7 @@ CREATE TABLE `tapir_presessions` ( `tracking_cookie` varchar(255) NOT NULL DEFAULT '', `created_at` int(4) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`presession_id`) -) ENGINE=InnoDB AUTO_INCREMENT=422 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=442 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -2915,7 +2915,7 @@ CREATE TABLE `tapir_sessions` ( 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=22707799 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=22747905 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -3015,7 +3015,7 @@ CREATE TABLE `tapir_users` ( 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=1082745 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1085901 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -3064,4 +3064,4 @@ SET @@SESSION.SQL_LOG_BIN = @MYSQLDUMP_TEMP_LOG_BIN; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2024-10-30 14:30:10 +-- Dump completed on 2024-11-06 12:59:37 diff --git a/development/db_codegen.py b/development/db_codegen.py index 7e61f70cd..7399137e4 100644 --- a/development/db_codegen.py +++ b/development/db_codegen.py @@ -173,11 +173,14 @@ def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef updated_body.append(elem) if existing_assignments: - logging.info("#========================================================================") - logging.info(f"# {class_name}") - for remain_key, remain_value in existing_assignments.items(): - logging.info(f" {remain_key}") - logging.info("#========================================================================") + # ignore all uppers + props = [prop for prop in existing_assignments.keys() if prop.upper() != prop] + if props: + logging.info("#") + logging.info(f"# {class_name}") + for prop in props: + logging.info(f" {prop}") + logging.info("#") a_key: str for a_key, a_value in existing_assignments.items(): @@ -275,6 +278,18 @@ def leave_Assign(self, original_node: cst.Assign, updated_node: cst.Assign) -> c return updated_node +def find_classes_and_tables(tree): + 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 main() -> None: p_outfile = "arxiv/db/autogen_models.py" @@ -297,20 +312,28 @@ def main() -> None: logging.error("%s: failed to parse", p_outfile, exc_info=exc) exit(1) - latest_def = {} - latest_tables = {} - - for node in latest_tree.body: - if isinstance(node, cst.ClassDef): - latest_def[node.name.value] = node - if is_table_def(node): - latest_tables[node.body[0].targets[0].target.value] = node.body[0] + latest_classes, latest_tables = find_classes_and_tables(latest_tree) with open(os.path.expanduser('arxiv/db/orig_models.py'), encoding='utf-8') as model_fd: existing_models = model_fd.read() existing_tree = cst.parse_module(existing_models) - transformer = SchemaTransformer(latest_def, latest_tables) + existing_classes, existing_tables = find_classes_and_tables(existing_tree) + + 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.warnind(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.warnind(f"class {new_table}") + + transformer = SchemaTransformer(latest_classes, latest_tables) updated_tree = existing_tree.visit(transformer) updated_model = 'arxiv/db/models.py' From 4caf5dcbe43d40c40d514be5f382a371ff97d4b2 Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Wed, 6 Nov 2024 22:40:10 -0500 Subject: [PATCH 08/32] Preserve the class slot variable order between the original and auto-genned. --- arxiv/db/arxiv-db-metadata.yaml | 3 +- arxiv/db/models.py | 212 ++++++++++++++++---------------- arxiv/db/orig_models.py | 4 +- development/db_codegen.py | 62 ++++++---- 4 files changed, 153 insertions(+), 128 deletions(-) diff --git a/arxiv/db/arxiv-db-metadata.yaml b/arxiv/db/arxiv-db-metadata.yaml index a2ebd2a98..39e5e20b6 100644 --- a/arxiv/db/arxiv-db-metadata.yaml +++ b/arxiv/db/arxiv-db-metadata.yaml @@ -300,7 +300,8 @@ arXiv_tracking: # without this, arXiv_updates would become simple Table, not Model arXiv_updates: class_name: Updates - table_args: drop + 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'))" diff --git a/arxiv/db/models.py b/arxiv/db/models.py index 9d614f703..05ff0bbda 100644 --- a/arxiv/db/models.py +++ b/arxiv/db/models.py @@ -7,7 +7,7 @@ This file was generated by using arxiv/development/db_codegen.py along with arxiv/development/sqlacodegen -If anything that you want to keep over time, add comment with the intention/reason. +If you want to keep the model definition over time, add comment with the intention/reason. Without it, it may be subjected to removal. """ @@ -57,11 +57,11 @@ class MemberInstitution(Base): __tablename__ = "Subscription_UniversalInstitution" + resolver_URL: Mapped[Optional[str]] = mapped_column(String(255)) name: Mapped[str] = mapped_column(String(255), nullable=False, index=True) - id: Mapped[intpk] - resolver_URL: Mapped[Optional[str]] = mapped_column(String(255)) 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)) @@ -69,12 +69,12 @@ class MemberInstitution(Base): class MemberInstitutionContact(Base): __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) - id: Mapped[intpk] - email: Mapped[Optional[str]] = mapped_column(String(255)) 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)) @@ -98,8 +98,8 @@ class AdminLog(Base): __tablename__ = "arXiv_admin_log" id: Mapped[intpk] - created: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=text("CURRENT_TIMESTAMP")) logtime: Mapped[Optional[str]] = mapped_column(String(24)) + 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)) @@ -124,7 +124,6 @@ class AdminMetadata(Base): __table_args__ = (ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], ondelete="CASCADE", name="meta_doc_fk"), Index("arxiv_admin_pidv", "paper_id", "version", unique=True)) metadata_id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True) - version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) document_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) paper_id: Mapped[Optional[str]] = mapped_column(String(64)) created: Mapped[Optional[datetime]] = mapped_column(DateTime) @@ -146,6 +145,7 @@ class AdminMetadata(Base): 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()) @@ -241,10 +241,10 @@ class BibFeed(Base): 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()) - strip_journal_ref: 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)) @@ -297,19 +297,19 @@ class Category(Base): 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[str] = mapped_column(Enum("y", "n", "d"), nullable=False, server_default=text("'d'")) endorse_email: Mapped[str] = 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'")) - category_name: Mapped[Optional[str]] = mapped_column(String(255)) endorsement_domain: Mapped[Optional[str]] = mapped_column(String(32), index=True) + arXiv_endorsements: Mapped[List["Endorsement"]] = 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: Mapped[List["EndorsementRequest"]] = relationship("EndorsementRequest", back_populates="arXiv_categories") arXiv_archives: Mapped["Archive"] = relationship("Archive", back_populates="arXiv_categories") arXiv_endorsement_domains: Mapped["EndorsementDomain"] = relationship("EndorsementDomain", back_populates="arXiv_categories") arXiv_cross_control: Mapped[List["CrossControl"]] = relationship("CrossControl", back_populates="arXiv_categories") arXiv_demographics: Mapped[List["Demographic"]] = relationship("Demographic", back_populates="arXiv_categories") - arXiv_endorsement_requests: Mapped[List["EndorsementRequest"]] = relationship("EndorsementRequest", back_populates="arXiv_categories") - arXiv_endorsements: Mapped[List["Endorsement"]] = relationship("Endorsement", back_populates="arXiv_categories") - arXiv_endorsement_domain = relationship("EndorsementDomain", primaryjoin="Category.endorsement_domain == EndorsementDomain.endorsement_domain", back_populates="arXiv_categories") # link to category arXiv_archive = relationship("Archive", primaryjoin="Category.archive == Archive.archive_id", back_populates="arXiv_categories") @@ -372,17 +372,17 @@ class CrossControl(Base): desired_order: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) user_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) status: Mapped[str] = mapped_column(Enum("new", "frozen", "published", "rejected"), nullable=False, index=True, server_default=FetchedValue()) + flag_must_notify: Mapped[Optional[str]] = 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()) - flag_must_notify: Mapped[Optional[str]] = mapped_column(Enum("0", "1"), server_default=FetchedValue()) - - arXiv_categories: Mapped["Category"] = relationship("Category", back_populates="arXiv_cross_control") + arXiv_category = relationship("Category", primaryjoin="and_(CrossControl.archive == Category.archive, CrossControl.subject_class == Category.subject_class)", back_populates="arXiv_cross_control") document: Mapped["Document"] = relationship("Document", back_populates="arXiv_cross_control") user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_cross_control") - arXiv_category = relationship("Category", primaryjoin="and_(CrossControl.archive == Category.archive, CrossControl.subject_class == Category.subject_class)", back_populates="arXiv_cross_control") + + arXiv_categories: Mapped["Category"] = relationship("Category", back_populates="arXiv_cross_control") class DataciteDois(Base): @@ -390,9 +390,9 @@ class DataciteDois(Base): __table_args__ = (ForeignKeyConstraint(["metadata_id"], ["arXiv_metadata.metadata_id"], name="arXiv_datacite_dois_ibfk_1"), Index("account_paper_id", "account", "paper_id", unique=True)) doi: Mapped[str] = mapped_column(String(255), primary_key=True) + account: Mapped[Optional[str]] = mapped_column(Enum("test", "prod")) metadata_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) paper_id: Mapped[str] = mapped_column(String(64), nullable=False) - account: Mapped[Optional[str]] = mapped_column(Enum("test", "prod")) created: Mapped[Optional[datetime]] = mapped_column(DateTime, server_default=FetchedValue()) updated: Mapped[Optional[datetime]] = mapped_column(DateTime, server_default=FetchedValue()) @@ -445,15 +445,16 @@ class Document(Base): document_id: Mapped[intpk] paper_id: Mapped[str] = mapped_column(String(20), nullable=False, index=True, server_default=FetchedValue()) title: Mapped[str] = mapped_column(String(255), nullable=False, index=True, server_default=FetchedValue()) - submitter_email: Mapped[str] = mapped_column(String(64), nullable=False, index=True, server_default=FetchedValue()) - dated: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) 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(Integer, 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]] = 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_admin_metadata: Mapped[List["AdminMetadata"]] = relationship("AdminMetadata", back_populates="document") arXiv_cross_control: Mapped[List["CrossControl"]] = relationship("CrossControl", back_populates="document") arXiv_document_category: Mapped[List["DocumentCategory"]] = relationship("DocumentCategory", back_populates="document") @@ -466,7 +467,6 @@ class Document(Base): 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") class DBLP(Document): @@ -521,10 +521,10 @@ class EndorsementRequest(Base): "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) - arXiv_endorsements: Mapped[List["Endorsement"]] = relationship("Endorsement", back_populates="request") - arXiv_ownership_requests: Mapped[List["OwnershipRequest"]] = relationship("OwnershipRequest", back_populates="endorsement_request") endorsement = relationship("Endorsement", back_populates="request", uselist=False) audit = relationship("EndorsementRequestsAudit", uselist=False) + arXiv_endorsements: Mapped[List["Endorsement"]] = relationship("Endorsement", back_populates="request") + arXiv_ownership_requests: Mapped[List["OwnershipRequest"]] = relationship("OwnershipRequest", back_populates="endorsement_request") class EndorsementRequestsAudit(EndorsementRequest): @@ -549,14 +549,14 @@ class Endorsement(Base): ) endorsement_id: Mapped[intpk] + endorser_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) endorsee_id: Mapped[int] = mapped_column(Integer, 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[str]] = 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()) - endorser_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) - type: Mapped[Optional[str]] = mapped_column(Enum("user", "admin", "auto")) request_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) arXiv_categories: Mapped["Category"] = relationship("Category", back_populates="arXiv_endorsements") @@ -628,11 +628,11 @@ class JrefControl(Base): version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) user_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) status: Mapped[str] = mapped_column(Enum("new", "frozen", "published", "rejected"), nullable=False, index=True, server_default=FetchedValue()) + flag_must_notify: Mapped[Optional[str]] = 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()) - flag_must_notify: Mapped[Optional[str]] = mapped_column(Enum("0", "1"), server_default=FetchedValue()) document: Mapped["Document"] = relationship("Document", back_populates="arXiv_jref_control") user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_jref_control") @@ -671,13 +671,11 @@ class Metadata(Base): metadata_id: Mapped[intpk] document_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) paper_id: Mapped[str] = mapped_column(String(64), nullable=False) - submitter_name: Mapped[str] = mapped_column(String(64), nullable=False) - submitter_email: Mapped[str] = mapped_column(String(64), nullable=False) - version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - is_withdrawn: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) created: Mapped[Optional[datetime]] = mapped_column(DateTime) updated: Mapped[Optional[datetime]] = mapped_column(DateTime) submitter_id: Mapped[Optional[int]] = mapped_column(Integer, 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[str]] = mapped_column(String(12)) source_flags: Mapped[Optional[str]] = mapped_column(String(12)) @@ -693,12 +691,14 @@ class Metadata(Base): doi: Mapped[Optional[str]] = mapped_column(String(255)) abstract: Mapped[Optional[str]] = mapped_column(Text) license: Mapped[Optional[str]] = mapped_column(String(255), 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: Mapped["Document"] = relationship("Document", primaryjoin="Metadata.document_id == Document.document_id", back_populates="arXiv_metadata") - arXiv_licenses: Mapped["License"] = relationship("License", back_populates="arXiv_metadata") submitter: Mapped["TapirUser"] = relationship("TapirUser", primaryjoin="Metadata.submitter_id == TapirUser.user_id", back_populates="arXiv_metadata") + arXiv_licenses: Mapped["License"] = relationship("License", back_populates="arXiv_metadata") arXiv_datacite_dois: Mapped[List["DataciteDois"]] = relationship("DataciteDois", back_populates="metadata_") @@ -707,13 +707,13 @@ class MirrorList(Base): __table_args__ = (ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], name="arXiv_mirror_list_fk_document_id"),) mirror_list_id: Mapped[intpk] + created: Mapped[Optional[datetime]] = mapped_column(DateTime) + updated: Mapped[Optional[datetime]] = mapped_column(DateTime) document_id: Mapped[int] = mapped_column(Integer, 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()) - created: Mapped[Optional[datetime]] = mapped_column(DateTime) - updated: Mapped[Optional[datetime]] = mapped_column(DateTime) document: Mapped["Document"] = relationship("Document", back_populates="arXiv_mirror_list") @@ -781,12 +781,12 @@ class NextMail(Base): 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()) - is_written: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - paper_id: Mapped[Optional[str]] = mapped_column(String(20)) 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): @@ -811,14 +811,14 @@ class OwnershipRequest(Base): request_id: Mapped[intpk] user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), nullable=False, index=True, server_default=FetchedValue()) - workflow_status: Mapped[str] = mapped_column(Enum("pending", "accepted", "rejected"), nullable=False, server_default=FetchedValue()) endorsement_request_id: Mapped[Optional[int]] = mapped_column(ForeignKey("arXiv_endorsement_requests.request_id"), index=True) + workflow_status: Mapped[str] = mapped_column(Enum("pending", "accepted", "rejected"), nullable=False, server_default=FetchedValue()) + request_audit = relationship("OwnershipRequestsAudit", back_populates="ownership_request", uselist=False) 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") - request_audit = relationship("OwnershipRequestsAudit", back_populates="ownership_request", uselist=False) documents = relationship("Document", secondary=t_arXiv_ownership_requests_papers) @@ -849,11 +849,11 @@ class PaperOwner(Base): valid: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) flag_author: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) flag_auto: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + document: Mapped["Document"] = relationship("Document", back_populates="arXiv_paper_owners") + owner = relationship("TapirUser", foreign_keys="[PaperOwner.user_id]", back_populates="owned_papers") tapir_users: Mapped["TapirUser"] = relationship("TapirUser", foreign_keys=[added_by], back_populates="arXiv_paper_owners") - document: Mapped["Document"] = relationship("Document", back_populates="arXiv_paper_owners") user: Mapped["TapirUser"] = relationship("TapirUser", foreign_keys=[user_id], back_populates="arXiv_paper_owners_") - owner = relationship("TapirUser", foreign_keys="[PaperOwner.user_id]", back_populates="owned_papers") class PaperSession(Base): @@ -962,8 +962,8 @@ class SubmissionAgreement(Base): __tablename__ = "arXiv_submission_agreements" agreement_id: Mapped[int] = mapped_column(Integer, primary_key=True) - commit_ref: Mapped[str] = mapped_column(String(255), nullable=False) 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") @@ -999,8 +999,8 @@ class SubmissionCategoryProposal(Base): submission_id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, index=True) category: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False, index=True) is_primary: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, index=True, server_default=FetchedValue()) - user_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) proposal_status: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) updated: Mapped[Optional[datetime]] = mapped_column(DateTime) proposal_comment_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) response_comment_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) @@ -1026,10 +1026,10 @@ class SubmissionControl(Base): pending_paper_id: Mapped[str] = mapped_column(String(20), nullable=False, index=True, server_default=FetchedValue()) user_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) status: Mapped[str] = mapped_column(Enum("new", "frozen", "published", "rejected"), nullable=False, index=True, server_default=FetchedValue()) + flag_must_notify: Mapped[Optional[str]] = 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()) - flag_must_notify: Mapped[Optional[str]] = mapped_column(Enum("0", "1"), server_default=FetchedValue()) document: Mapped["Document"] = relationship("Document", back_populates="arXiv_submission_control") user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_submission_control") @@ -1095,9 +1095,9 @@ class SubmissionQaReport(Base): id: Mapped[intpk] submission_id: Mapped[int] = mapped_column(Integer, 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] = mapped_column(JSON, nullable=False) - created: Mapped[Optional[datetime]] = mapped_column(DateTime, server_default=FetchedValue()) report_uri: Mapped[Optional[str]] = mapped_column(String(256)) submission: Mapped["Submission"] = relationship("Submission", back_populates="arXiv_submission_qa_reports") @@ -1111,8 +1111,8 @@ class SubmissionViewFlag(Base): ) submission_id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False) - user_id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, index=True) flag: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + user_id: Mapped[int] = mapped_column(Integer, 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") @@ -1130,23 +1130,11 @@ class Submission(Base): ) submission_id: Mapped[intpk] - is_author: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) - status: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) - is_withdrawn: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) - version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) - 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()) - is_locked: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) - 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'")) document_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) doc_paper_id: Mapped[Optional[str]] = mapped_column(String(20), index=True) sword_id: Mapped[Optional[int]] = mapped_column(Integer, 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()) @@ -1155,6 +1143,7 @@ class Submission(Base): submitter_email: Mapped[Optional[str]] = mapped_column(String(64)) 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]] = mapped_column(DateTime) @@ -1163,6 +1152,7 @@ class Submission(Base): 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) @@ -1174,33 +1164,43 @@ class Submission(Base): doi: Mapped[Optional[str]] = mapped_column(String(255)) abstract: Mapped[Optional[str]] = mapped_column(Text) license: Mapped[Optional[str]] = mapped_column(String(255), 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[Optional[int]] = mapped_column(Integer, index=True) - data_queued_time: Mapped[Optional[datetime]] = mapped_column(DateTime) - metadata_queued_time: Mapped[Optional[datetime]] = mapped_column(DateTime) 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_licenses: Mapped["License"] = relationship("License", back_populates="arXiv_submissions") + arXiv_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") arXiv_check_results: Mapped[List["ArXivCheckResults"]] = relationship("ArXivCheckResults", back_populates="submission") + arXiv_submission_locks: Mapped[List["ArXivSubmissionLocks"]] = relationship("ArXivSubmissionLocks", 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_licenses: Mapped["License"] = relationship("License", back_populates="arXiv_submissions") 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_locks: Mapped[List["ArXivSubmissionLocks"]] = relationship("ArXivSubmissionLocks", 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") - arXiv_license = relationship("License", primaryjoin="Submission.license == License.name", back_populates="arXiv_submissions") class PilotDataset(Submission): @@ -1208,14 +1208,14 @@ class PilotDataset(Submission): __table_args__ = (ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], name="arXiv_pilot_datasets_cdfk3"),) submission_id: Mapped[int] = mapped_column(Integer, primary_key=True) - created: Mapped[datetime] = mapped_column(DateTime, nullable=False) - # created: Mapped[datetime] = mapped_column(DateTime, nullable=False) - # ^This column is inherited - last_checked: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) 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()) + # created: Mapped[datetime] = mapped_column(DateTime, nullable=False) + # ^This column is inherited + last_checked: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) + created: Mapped[datetime] = mapped_column(DateTime, nullable=False) class SubmissionAbsClassifierDatum(Base): @@ -1223,8 +1223,8 @@ class SubmissionAbsClassifierDatum(Base): __table_args__ = (ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], ondelete="CASCADE", name="arXiv_submission_abs_classifier_data_ibfk_1"),) submission_id: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) - last_update: Mapped[datetime] = mapped_column(DateTime, nullable=False, 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[str]] = mapped_column(Enum("processing", "success", "failed", "no connection")) message: Mapped[Optional[str]] = mapped_column(Text) is_oversize: Mapped[Optional[int]] = mapped_column(Integer, server_default=text("'0'")) @@ -1241,8 +1241,8 @@ class SubmissionClassifierDatum(Base): __table_args__ = (ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], ondelete="CASCADE", name="arXiv_submission_classifier_data_ibfk_1"),) submission_id: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) - last_update: Mapped[datetime] = mapped_column(DateTime, nullable=False, 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[str]] = mapped_column(Enum("processing", "success", "failed", "no connection")) message: Mapped[Optional[str]] = mapped_column(Text) is_oversize: Mapped[Optional[int]] = mapped_column(Integer, server_default=text("'0'")) @@ -1280,18 +1280,19 @@ class TopPaper(Base): __table_args__ = (ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], name="arXiv_top_papers_ibfk_1"),) 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=text("''")) rank: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, server_default=FetchedValue()) document_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) viewers: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) document: Mapped["Document"] = relationship("Document", primaryjoin="TopPaper.document_id == Document.document_id", back_populates="arXiv_top_papers") + _class: Mapped[str] = mapped_column("class", String(1), primary_key=True, nullable=False, server_default=text("''")) 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()) @@ -1305,7 +1306,6 @@ class TrackbackPing(Base): status: Mapped[Literal["pending", "pending2", "accepted", "rejected", "spam"]] = mapped_column( Enum("pending", "pending2", "accepted", "rejected", "spam"), nullable=False, index=True, server_default=FetchedValue() ) - document_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) site_id: Mapped[Optional[int]] = mapped_column(Integer) @property @@ -1354,22 +1354,24 @@ class Tracking(Base): tracking_id: Mapped[intpk] sword_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) paper_id: Mapped[str] = mapped_column(String(32), nullable=False) - timestamp: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) 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" - - version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) + __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"), - primary_key=True, + index=True, + server_defaults=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) @@ -1412,9 +1414,9 @@ class VersionsChecksum(Version): 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[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()) - abs_md5sum: Mapped[Optional[bytes]] = mapped_column(BINARY(16), index=True) src_md5sum: Mapped[Optional[bytes]] = mapped_column(BINARY(16), index=True) @@ -1489,9 +1491,9 @@ class TapirAddress(Base): 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()) + user: Mapped["TapirUser"] = relationship("TapirUser", primaryjoin="TapirAddress.user_id == TapirUser.user_id", back_populates="tapir_address") tapir_countries: Mapped["TapirCountry"] = relationship("TapirCountry", back_populates="tapir_address") - user: Mapped["TapirUser"] = relationship("TapirUser", primaryjoin="TapirAddress.user_id == TapirUser.user_id", back_populates="tapir_address") class TapirAdminAudit(Base): @@ -1503,16 +1505,16 @@ class TapirAdminAudit(Base): ) log_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + session_id: Mapped[Optional[int]] = mapped_column(Integer, 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(Integer, index=True) affected_user: Mapped[int] = mapped_column(Integer, 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)) comment: Mapped[str] = mapped_column(Text, nullable=False) entry_id: Mapped[intpk] - session_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) - admin_user: Mapped[Optional[int]] = mapped_column(Integer, index=True) 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_") @@ -1535,6 +1537,8 @@ class TapirEmailChangeToken(Base): __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_535"),) user_id: Mapped[int] = mapped_column(Integer, 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()) @@ -1543,8 +1547,6 @@ class TapirEmailChangeToken(Base): 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()) - old_email: Mapped[Optional[str]] = mapped_column(String(255)) - new_email: Mapped[Optional[str]] = mapped_column(String(255)) consumed_when: Mapped[Optional[int]] = mapped_column(Integer) consumed_from: Mapped[Optional[str]] = mapped_column(String(16)) @@ -1578,13 +1580,13 @@ class TapirEmailLog(Base): __tablename__ = "tapir_email_log" mail_id: Mapped[intpk] - sent_date: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - template_id: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) 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): @@ -1761,8 +1763,8 @@ class TapirPhone(Base): user_id: Mapped[int] = mapped_column(Integer, 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()) - share_phone: Mapped[int] = mapped_column(Integer, nullable=False, 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: Mapped["TapirUser"] = relationship("TapirUser", back_populates="tapir_phone") @@ -1821,9 +1823,9 @@ class TapirRecoveryTokensUsed(Base): user_id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, server_default=FetchedValue()) secret: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False, server_default=FetchedValue()) - remote_host: Mapped[str] = mapped_column(String(255), 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(Integer, index=True) session: Mapped["TapirSession"] = relationship("TapirSession", back_populates="tapir_recovery_tokens_used") @@ -1851,10 +1853,10 @@ class TapirSession(Base): end_time: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) 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") - user = relationship("TapirUser", primaryjoin="TapirSession.user_id == TapirUser.user_id", back_populates="tapir_sessions") class TapirSessionsAudit(Base): @@ -1890,6 +1892,9 @@ class TapirUser(Base): __table_args__ = (ForeignKeyConstraint(["policy_class"], ["tapir_policy_classes.class_id"], name="0_510"),) 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, index=True, server_default=text("''")) @@ -1897,6 +1902,7 @@ class TapirUser(Base): email_bouncing: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) policy_class: Mapped[int] = mapped_column(Integer, 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'")) @@ -1910,16 +1916,11 @@ class TapirUser(Base): 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'")) - 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)) - joined_ip_num: Mapped[Optional[str]] = mapped_column(String(16), index=True) 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_key: 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") @@ -1929,12 +1930,8 @@ class TapirUser(Base): 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_control: Mapped[List["CrossControl"]] = relationship("CrossControl", back_populates="user") arXiv_endorsement_requests: Mapped[List["EndorsementRequest"]] = relationship("EndorsementRequest", back_populates="endorsee") - arXiv_jref_control: Mapped[List["JrefControl"]] = relationship("JrefControl", back_populates="user") arXiv_metadata: Mapped[List["Metadata"]] = relationship("Metadata", back_populates="submitter") - arXiv_paper_owners: Mapped[List["PaperOwner"]] = relationship("PaperOwner", foreign_keys="[PaperOwner.added_by]", back_populates="tapir_users") - arXiv_paper_owners_: Mapped[List["PaperOwner"]] = relationship("PaperOwner", foreign_keys="[PaperOwner.user_id]", back_populates="user") 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") @@ -1944,20 +1941,25 @@ class TapirUser(Base): 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") - arXiv_check_results: Mapped[List["ArXivCheckResults"]] = relationship("ArXivCheckResults", back_populates="user") - arXiv_endorsements: Mapped[List["Endorsement"]] = relationship("Endorsement", foreign_keys="[Endorsement.endorsee_id]", back_populates="endorsee") - arXiv_endorsements_: Mapped[List["Endorsement"]] = relationship("Endorsement", foreign_keys="[Endorsement.endorser_id]", back_populates="endorser") + 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: 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["ArXivSubmissionLocks"]] = relationship("ArXivSubmissionLocks", back_populates="user") arXiv_submission_view_flag: Mapped[List["SubmissionViewFlag"]] = relationship("SubmissionViewFlag", back_populates="user") + arXiv_check_results: Mapped[List["ArXivCheckResults"]] = relationship("ArXivCheckResults", back_populates="user") arXiv_check_responses: Mapped[List["ArXivCheckResponses"]] = relationship("ArXivCheckResponses", 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") 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") + arXiv_moderator_api_key: Mapped[List["ModeratorApiKey"]] = relationship("ModeratorApiKey", back_populates="user") + arXiv_cross_control: Mapped[List["CrossControl"]] = relationship("CrossControl", back_populates="user") + arXiv_jref_control: Mapped[List["JrefControl"]] = relationship("JrefControl", back_populates="user") + arXiv_paper_owners: Mapped[List["PaperOwner"]] = relationship("PaperOwner", foreign_keys="[PaperOwner.added_by]", back_populates="tapir_users") + arXiv_paper_owners_: Mapped[List["PaperOwner"]] = relationship("PaperOwner", foreign_keys="[PaperOwner.user_id]", back_populates="user") + arXiv_endorsements: Mapped[List["Endorsement"]] = relationship("Endorsement", foreign_keys="[Endorsement.endorsee_id]", back_populates="endorsee") + arXiv_endorsements_: Mapped[List["Endorsement"]] = relationship("Endorsement", foreign_keys="[Endorsement.endorser_id]", back_populates="endorser") class AuthorIds(Base): @@ -1980,7 +1982,11 @@ class Demographic(Base): 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(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()) + 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'")) @@ -1996,10 +2002,6 @@ class Demographic(Base): 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[str] = mapped_column(Enum("ok", "no-endorse", "no-upload", "no-replace"), nullable=False, server_default=text("'ok'")) - 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)) - flag_group_physics: Mapped[Optional[int]] = mapped_column(Integer, index=True) arXiv_categories: Mapped["Category"] = relationship( "Category", primaryjoin="and_(Demographic.archive == Category.archive, Demographic.subject_class == Category.subject_class)", backref="category_demographics" @@ -2040,9 +2042,9 @@ class QueueView(Base): __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], ondelete="CASCADE", name="arXiv_queue_view_ibfk_1"),) user_id: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) - total_views: Mapped[int] = mapped_column(Integer, nullable=False, 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): @@ -2058,8 +2060,8 @@ class SwordLicense(Base): __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="user_id_fk"),) user_id: Mapped[int] = mapped_column(Integer, primary_key=True) - updated: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) license: Mapped[Optional[str]] = mapped_column(String(127)) + updated: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) class TapirDemographic(Base): @@ -2069,11 +2071,11 @@ class TapirDemographic(Base): user_id: Mapped[int] = mapped_column(Integer, 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[dt.date]] = mapped_column(Date, index=True) share_birthday: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) country: Mapped[str] = mapped_column(String(2), 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()) - birthday: Mapped[Optional[dt.date]] = mapped_column(Date, index=True) tapir_countries: Mapped["TapirCountry"] = relationship("TapirCountry", back_populates="tapir_demographics") tapir_countries: Mapped["TapirCountry"] = relationship("TapirCountry", back_populates="tapir_demographics") diff --git a/arxiv/db/orig_models.py b/arxiv/db/orig_models.py index c12d576b6..4e3d3a6a7 100644 --- a/arxiv/db/orig_models.py +++ b/arxiv/db/orig_models.py @@ -1305,11 +1305,13 @@ class Tracking(Base): 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"), - primary_key=True, + index=True, + server_defaults=text("'0'"), ) version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) date: Mapped[Optional[dt.date]] = mapped_column(Date, index=True) diff --git a/development/db_codegen.py b/development/db_codegen.py index 7399137e4..9919c104d 100644 --- a/development/db_codegen.py +++ b/development/db_codegen.py @@ -142,36 +142,56 @@ def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef updated_body = [] - for elem in latest_node.body.body: + # Remember the original slot order + original_slot_order = { + "__tablename__": 0, + "__table_args__": 1, + } + + for elem in original_node.body.body: if is_assign_expr(elem): 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): - 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 not processed again - del existing_assignments[target] + if target not in original_slot_order: + original_slot_order[target] = len(original_slot_order.keys()) + + 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): + 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 not processed again + 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 botom + updated_body.sort(key=lambda slot: original_slot_order[self.first_target(slot)]) + + # Append the non-assigns for elem in original_node.body.body: - if not is_assign_expr(elem): - updated_body.append(elem) + if is_assign_expr(elem): + continue + updated_body.append(elem) + # Warn the left over assigns if existing_assignments: # ignore all uppers props = [prop for prop in existing_assignments.keys() if prop.upper() != prop] From a8a48ddc591e86b0b0b0324d9add94b61db115a7 Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Thu, 7 Nov 2024 22:38:54 -0500 Subject: [PATCH 09/32] Add table's index patching. --- arxiv/db/arxiv-db-metadata.yaml | 42 ++++- arxiv/db/models.py | 283 ++++++++++++++++---------------- arxiv/db/orig_models.py | 2 + development/db_codegen.py | 66 ++++++-- 4 files changed, 230 insertions(+), 163 deletions(-) diff --git a/arxiv/db/arxiv-db-metadata.yaml b/arxiv/db/arxiv-db-metadata.yaml index 39e5e20b6..47da6b262 100644 --- a/arxiv/db/arxiv-db-metadata.yaml +++ b/arxiv/db/arxiv-db-metadata.yaml @@ -11,6 +11,15 @@ # # Generally, sqlacodegen is driven from development/db_codegen.py # + +# a hack +# globally suggests the column name to python variable name +# by default, sqlacodegen uses the suffix "_" +# +_names_map_: + class: _class + +# Subscription_UniversalInstitution: class_name: MemberInstitution relationships: @@ -56,6 +65,8 @@ arXiv_bogus_countries: class_name: BogusCountries arXiv_categories: class_name: Category + relationships: + arXiv_demographics: "relationship('Demographic', back_populates='arXiv_category')" additional_relationships: - "arXiv_endorsement_domain = relationship('EndorsementDomain', primaryjoin='Category.endorsement_domain == EndorsementDomain.endorsement_domain', back_populates='arXiv_categories')" @@ -140,14 +151,16 @@ arXiv_jref_control: status: "mapped_column(Enum('new', 'frozen', 'published', 'rejected'), nullable=False, index=True, server_default=FetchedValue())" arXiv_licenses: class_name: License + relationships: + arXiv_metadata: "" arXiv_log_positions: class_name: LogPosition arXiv_metadata: class_name: Metadata relationships: + arXiv_licenses: "" document: "relationship('Document', primaryjoin='Metadata.document_id == Document.document_id', back_populates='arXiv_metadata')" - arXiv_license: "relationship('License', primaryjoin='Metadata.license == License.name', back_populates='arXiv_metadata_licenses')" 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')" @@ -303,6 +316,7 @@ arXiv_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: @@ -321,17 +335,21 @@ tapir_address: 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_country: "relationship('TapirCountry', primaryjoin='TapirAddress.country == TapirCountry.digraph', back_populates='tapir_address')" + 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: - user: "relationship('TapirUser', primaryjoin='TapirAddress.user_id == TapirUser.user_id', back_populates='tapir_address')" + tapir_address: "relationship('TapirAddress', back_populates='tapir_country')" + tapir_demographics: "" + tapir_email_change_tokens: class_name: TapirEmailChangeToken tapir_email_headers: @@ -381,13 +399,17 @@ tapir_users: - "endorses = relationship('Endorsement', foreign_keys='[Endorsement.endorser_id]', back_populates='endorser')" - "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')" + - "arXiv_moderator_api_keys = relationship('ModeratorApiKey', back_populates='user')" + - "arXiv_cross_controls = relationship('CrossControl', back_populates='user')" + - "arXiv_jref_controls = relationship('JrefControl', back_populates='user')" arXiv_author_ids: class_name: AuthorIds arXiv_demographics: class_name: Demographic relationships: - arXiv_categories: "relationship('Category', primaryjoin='and_(Demographic.archive == Category.archive, Demographic.subject_class == Category.subject_class)', backref='category_demographics')" + arXiv_categories: + arXiv_category: "relationship('Category', primaryjoin='and_(Demographic.archive == Category.archive, Demographic.subject_class == Category.subject_class)', backref='category_demographics')" arXiv_orcid_ids: class_name: OrcidIds arXiv_queue_view: @@ -398,8 +420,9 @@ arXiv_sword_licenses: class_name: SwordLicense tapir_demographics: class_name: TapirDemographic - additional_relationships: - - "tapir_countries: Mapped['TapirCountry'] = relationship('TapirCountry', back_populates='tapir_demographics')" + relationships: + tapir_countries: + tapir_country: relationship('TapirCountry', primaryjoin='TapirDemographic.country == TapirCountry.digraph', backref='tapir_demographics') tapir_users_hot: class_name: TapirUsersHot tapir_users_password: @@ -415,3 +438,10 @@ 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())" + +arXiv_moderators: + indecies: + - replace: ["Index('user_id'", "Index('mod_user_id'"] diff --git a/arxiv/db/models.py b/arxiv/db/models.py index 05ff0bbda..0db8a2362 100644 --- a/arxiv/db/models.py +++ b/arxiv/db/models.py @@ -124,7 +124,7 @@ class AdminMetadata(Base): __table_args__ = (ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], ondelete="CASCADE", name="meta_doc_fk"), Index("arxiv_admin_pidv", "paper_id", "version", unique=True)) metadata_id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True) - document_id: Mapped[Optional[int]] = mapped_column(Integer, 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]] = mapped_column(DateTime) updated: Mapped[Optional[datetime]] = mapped_column(DateTime) @@ -191,7 +191,7 @@ class Archive(Base): __table_args__ = (ForeignKeyConstraint(["in_group"], ["arXiv_groups.group_id"], name="0_576"),) archive_id: Mapped[str] = mapped_column(String(16), primary_key=True, server_default=FetchedValue()) - in_group: Mapped[str] = mapped_column(String(16), 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()) @@ -228,11 +228,7 @@ class AwsFile(Base): num_items: Mapped[Optional[int]] = mapped_column(Integer) -t_arXiv_bad_pw = Table( - "arXiv_bad_pw", - metadata, - Column("user_id", Integer, nullable=False, 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): @@ -280,7 +276,7 @@ class BogusCountries(Base): t_arXiv_bogus_subject_class = Table( "arXiv_bogus_subject_class", metadata, - Column("document_id", Integer, nullable=False, server_default=FetchedValue()), + 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()), ) @@ -301,7 +297,7 @@ class Category(Base): endorse_all: Mapped[str] = mapped_column(Enum("y", "n", "d"), nullable=False, server_default=text("'d'")) endorse_email: Mapped[str] = 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(String(32), index=True) + 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_endorsement_domain = 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") @@ -309,7 +305,7 @@ class Category(Base): arXiv_archives: Mapped["Archive"] = relationship("Archive", back_populates="arXiv_categories") arXiv_endorsement_domains: Mapped["EndorsementDomain"] = relationship("EndorsementDomain", back_populates="arXiv_categories") arXiv_cross_control: Mapped[List["CrossControl"]] = relationship("CrossControl", back_populates="arXiv_categories") - arXiv_demographics: Mapped[List["Demographic"]] = relationship("Demographic", back_populates="arXiv_categories") + 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") @@ -350,8 +346,8 @@ class ControlHold(Base): 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[str] = mapped_column(Enum("auto", "user", "admin", "moderator"), nullable=False, index=True, server_default=FetchedValue()) - placed_by: Mapped[Optional[int]] = mapped_column(Integer, index=True) - last_changed_by: Mapped[Optional[int]] = mapped_column(Integer, index=True) + 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_") @@ -367,10 +363,10 @@ class CrossControl(Base): ) control_id: Mapped[intpk] - document_id: Mapped[int] = mapped_column(Integer, 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(Integer, 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[str] = mapped_column(Enum("new", "frozen", "published", "rejected"), nullable=False, index=True, server_default=FetchedValue()) flag_must_notify: Mapped[Optional[str]] = mapped_column(Enum("0", "1"), server_default=FetchedValue()) archive: Mapped[str] = mapped_column(String(16), nullable=False, server_default=FetchedValue()) @@ -391,7 +387,7 @@ class DataciteDois(Base): doi: Mapped[str] = mapped_column(String(255), primary_key=True) account: Mapped[Optional[str]] = mapped_column(Enum("test", "prod")) - metadata_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) + 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()) @@ -430,8 +426,8 @@ class DocumentCategory(Base): ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], ondelete="CASCADE", name="doc_cat_doc"), ) - document_id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, index=True, server_default=FetchedValue()) - category: Mapped[str] = mapped_column(String(32), 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["CategoryDef"] = relationship("CategoryDef", back_populates="arXiv_document_category") @@ -447,7 +443,7 @@ class Document(Base): 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(Integer, 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]] = mapped_column(DateTime) @@ -467,13 +463,15 @@ class Document(Base): 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") + # link the cross control + arXiv_cross_controls = relationship("CrossControl", back_populates="document") class DBLP(Document): __tablename__ = "arXiv_dblp" __table_args__ = (ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], name="arXiv_DBLP_cdfk1"),) - document_id: Mapped[int] = mapped_column(Integer, 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)) @@ -485,7 +483,13 @@ class PaperPw(Document): password_enc: Mapped[Optional[str]] = mapped_column(String(50)) -t_arXiv_duplicates = Table("arXiv_duplicates", metadata, Column("user_id", Integer, nullable=False, server_default=FetchedValue()), Column("email", String(255)), Column("username", String(255))) +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): @@ -509,7 +513,7 @@ class EndorsementRequest(Base): ) request_id: Mapped[intpk] - endorsee_id: Mapped[int] = mapped_column(Integer, 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, index=True, server_default=FetchedValue()) @@ -531,7 +535,7 @@ class EndorsementRequestsAudit(EndorsementRequest): __tablename__ = "arXiv_endorsement_requests_audit" __table_args__ = (ForeignKeyConstraint(["request_id"], ["arXiv_endorsement_requests.request_id"], name="0_725"),) - request_id: Mapped[int] = mapped_column(Integer, 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]] = mapped_column(String(255)) @@ -549,15 +553,15 @@ class Endorsement(Base): ) endorsement_id: Mapped[intpk] - endorser_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) - endorsee_id: Mapped[int] = mapped_column(Integer, 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[str]] = 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(Integer, index=True) + request_id: Mapped[Optional[int]] = mapped_column(ForeignKey("arXiv_endorsement_requests.request_id"), index=True) arXiv_categories: Mapped["Category"] = relationship("Category", back_populates="arXiv_endorsements") endorsee: Mapped["TapirUser"] = relationship("TapirUser", foreign_keys=[endorsee_id], back_populates="arXiv_endorsements") @@ -569,7 +573,7 @@ class EndorsementsAudit(Endorsement): __tablename__ = "arXiv_endorsements_audit" __table_args__ = (ForeignKeyConstraint(["endorsement_id"], ["arXiv_endorsements.endorsement_id"], name="0_732"),) - endorsement_id: Mapped[int] = mapped_column(Integer, 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()) @@ -605,13 +609,13 @@ class Group(Base): t_arXiv_in_category = Table( "arXiv_in_category", metadata, - Column("document_id", Integer, nullable=False, server_default=FetchedValue()), + 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"), + ForeignKeyConstraint(["archive", "subject_class"], ["arXiv_categories.archive", "arXiv_categories.subject_class"], name="0_583"), Index("arXiv_in_category_mp", "archive", "subject_class"), + Index("archive", "archive", "subject_class", "document_id", unique=True), ) @@ -624,9 +628,9 @@ class JrefControl(Base): ) control_id: Mapped[intpk] - document_id: Mapped[int] = mapped_column(Integer, 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(Integer, 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[str] = mapped_column(Enum("new", "frozen", "published", "rejected"), nullable=False, index=True, server_default=FetchedValue()) flag_must_notify: Mapped[Optional[str]] = mapped_column(Enum("0", "1"), server_default=FetchedValue()) jref: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) @@ -647,7 +651,6 @@ class License(Base): note: Mapped[Optional[str]] = mapped_column(String(400)) sequence: Mapped[Optional[int]] = mapped_column(Integer) - arXiv_metadata: Mapped[List["Metadata"]] = relationship("Metadata", back_populates="arXiv_licenses") arXiv_submissions: Mapped[List["Submission"]] = relationship("Submission", back_populates="arXiv_licenses") @@ -669,11 +672,11 @@ class Metadata(Base): ) metadata_id: Mapped[intpk] - document_id: Mapped[int] = mapped_column(Integer, 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]] = mapped_column(DateTime) updated: Mapped[Optional[datetime]] = mapped_column(DateTime) - submitter_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) + 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) @@ -690,7 +693,7 @@ class Metadata(Base): 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), 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()) @@ -698,8 +701,9 @@ class Metadata(Base): 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_licenses: Mapped["License"] = relationship("License", 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): @@ -709,7 +713,7 @@ class MirrorList(Base): mirror_list_id: Mapped[intpk] created: Mapped[Optional[datetime]] = mapped_column(DateTime) updated: Mapped[Optional[datetime]] = mapped_column(DateTime) - document_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + 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()) @@ -722,7 +726,7 @@ class ModeratorApiKey(Base): __tablename__ = "arXiv_moderator_api_key" __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="arXiv_moderator_api_key_ibfk_1"),) - user_id: Mapped[int] = mapped_column(Integer, 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()) @@ -735,16 +739,16 @@ class ModeratorApiKey(Base): t_arXiv_moderators = Table( "arXiv_moderators", metadata, - Column("user_id", Integer, nullable=False, server_default=FetchedValue()), - Column("archive", String(16), nullable=False, server_default=FetchedValue()), + 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, server_default=FetchedValue()), - Column("no_web_email", Integer, server_default=FetchedValue()), - Column("no_reply_to", Integer, 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"), + ForeignKeyConstraint(["archive", "subject_class"], ["arXiv_categories.archive", "arXiv_categories.subject_class"], name="0_591"), + Index("mod_user_id", "archive", "subject_class", "user_id", unique=True), ) @@ -842,7 +846,7 @@ class PaperOwner(Base): 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=FetchedValue()) - added_by: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + added_by: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), nullable=False, index=True, 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(32), nullable=False, server_default=FetchedValue()) @@ -871,7 +875,7 @@ class PilotFile(Base): __table_args__ = (ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], name="arXiv_pilot_files_cdfk3"),) file_id: Mapped[intpk] - submission_id: Mapped[int] = mapped_column(Integer, 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)) @@ -910,8 +914,8 @@ class ShowEmailRequest(Base): Index("email_reqs_user_id", "user_id", "dated"), ) - document_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) - user_id: Mapped[int] = mapped_column(Integer, 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()) @@ -976,8 +980,8 @@ class SubmissionCategory(Base): ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], ondelete="CASCADE", onupdate="CASCADE", name="arXiv_submission_category_fk_submission_id"), ) - submission_id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, index=True) - category: Mapped[str] = mapped_column(String(32), 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()) @@ -996,14 +1000,14 @@ class SubmissionCategoryProposal(Base): ) proposal_id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, index=True) - submission_id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, index=True) - category: Mapped[str] = mapped_column(String(32), 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(Integer, nullable=False, index=True) + 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(Integer, index=True) - response_comment_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) + 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", back_populates="arXiv_submission_category_proposal") proposal_comment: Mapped["AdminLog"] = relationship("AdminLog", foreign_keys=[proposal_comment_id], back_populates="arXiv_submission_category_proposal") @@ -1021,10 +1025,10 @@ class SubmissionControl(Base): ) control_id: Mapped[intpk] - document_id: Mapped[int] = mapped_column(Integer, 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(Integer, 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[str] = mapped_column(Enum("new", "frozen", "published", "rejected"), nullable=False, index=True, server_default=FetchedValue()) flag_must_notify: Mapped[Optional[str]] = mapped_column(Enum("0", "1"), server_default=FetchedValue()) request_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) @@ -1044,8 +1048,8 @@ class SubmissionFlag(Base): ) flag_id: Mapped[intpk] - user_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) - submission_id: Mapped[int] = mapped_column(Integer, 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()) @@ -1062,11 +1066,11 @@ class SubmissionHoldReason(Base): ) reason_id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False) - submission_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) - user_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"), 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(Integer, index=True) + 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") @@ -1080,7 +1084,7 @@ class SubmissionNearDuplicate(Base): Index("match", "submission_id", "matching_id", unique=True), ) - submission_id: Mapped[int] = mapped_column(Integer, 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()) @@ -1093,7 +1097,7 @@ class SubmissionQaReport(Base): __table_args__ = (ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], name="arXiv_submission_qa_reports_ibfk_1"),) id: Mapped[intpk] - submission_id: Mapped[int] = mapped_column(Integer, 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()) @@ -1110,9 +1114,9 @@ class SubmissionViewFlag(Base): ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], ondelete="CASCADE", name="arXiv_submission_view_flag_ibfk_2"), ) - submission_id: Mapped[int] = mapped_column(Integer, 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(Integer, primary_key=True, nullable=False, index=True) + 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") @@ -1130,15 +1134,15 @@ class Submission(Base): ) submission_id: Mapped[intpk] - document_id: Mapped[Optional[int]] = mapped_column(Integer, 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(Integer, 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(Integer, 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]] = mapped_column(DateTime) @@ -1163,7 +1167,7 @@ class Submission(Base): 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), 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) @@ -1176,7 +1180,7 @@ 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[Optional[int]] = mapped_column(Integer, index=True) + 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") @@ -1207,7 +1211,7 @@ class PilotDataset(Submission): __tablename__ = "arXiv_pilot_datasets" __table_args__ = (ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], name="arXiv_pilot_datasets_cdfk3"),) - submission_id: Mapped[int] = mapped_column(Integer, primary_key=True) + 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)) @@ -1222,7 +1226,7 @@ class SubmissionAbsClassifierDatum(Base): __tablename__ = "arXiv_submission_abs_classifier_data" __table_args__ = (ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], ondelete="CASCADE", name="arXiv_submission_abs_classifier_data_ibfk_1"),) - submission_id: Mapped[int] = mapped_column(Integer, 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[str]] = mapped_column(Enum("processing", "success", "failed", "no connection")) @@ -1240,7 +1244,7 @@ class SubmissionClassifierDatum(Base): __tablename__ = "arXiv_submission_classifier_data" __table_args__ = (ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], ondelete="CASCADE", name="arXiv_submission_classifier_data_ibfk_1"),) - submission_id: Mapped[int] = mapped_column(Integer, 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[str]] = mapped_column(Enum("processing", "success", "failed", "no connection")) @@ -1280,12 +1284,12 @@ class TopPaper(Base): __table_args__ = (ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], name="arXiv_top_papers_ibfk_1"),) 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(Integer, nullable=False, index=True, 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: Mapped["Document"] = relationship("Document", primaryjoin="TopPaper.document_id == Document.document_id", back_populates="arXiv_top_papers") - _class: Mapped[str] = mapped_column("class", String(1), primary_key=True, nullable=False, server_default=text("''")) class TrackbackPing(Base): @@ -1396,7 +1400,7 @@ class Version(Base): __tablename__ = "arXiv_versions" __table_args__ = (ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], name="arXiv_versions_ibfk_1"),) - document_id: Mapped[int] = mapped_column(Integer, 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()) @@ -1420,7 +1424,7 @@ class VersionsChecksum(Version): 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), index=True)) t_arXiv_xml_notifications = Table( @@ -1448,8 +1452,8 @@ class DbixClassSchemaVersion(Base): 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("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()), @@ -1491,9 +1495,9 @@ class TapirAddress(Base): 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()) - user: Mapped["TapirUser"] = relationship("TapirUser", primaryjoin="TapirAddress.user_id == TapirUser.user_id", back_populates="tapir_address") - tapir_countries: Mapped["TapirCountry"] = relationship("TapirCountry", 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): @@ -1505,11 +1509,11 @@ class TapirAdminAudit(Base): ) log_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) - session_id: Mapped[Optional[int]] = mapped_column(Integer, 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(Integer, index=True) - affected_user: Mapped[int] = mapped_column(Integer, 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(String(255)) @@ -1528,15 +1532,14 @@ class TapirCountry(Base): 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_countries") - tapir_demographics: Mapped[List["TapirDemographic"]] = relationship("TapirDemographic", back_populates="tapir_countries") + tapir_address: Mapped[List["TapirAddress"]] = relationship("TapirAddress", back_populates="tapir_country") class TapirEmailChangeToken(Base): __tablename__ = "tapir_email_change_tokens" __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_535"),) - user_id: Mapped[int] = mapped_column(Integer, 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()) 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()) @@ -1556,12 +1559,12 @@ class TapirEmailChangeToken(Base): t_tapir_email_change_tokens_used = Table( "tapir_email_change_tokens_used", metadata, - Column("user_id", Integer, nullable=False, server_default=FetchedValue()), + 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", Integer, nullable=False, server_default=FetchedValue()), + Column("session_id", ForeignKey("tapir_sessions.session_id"), nullable=False, index=True, server_default=FetchedValue()), ) @@ -1569,7 +1572,7 @@ class TapirEmailHeader(Base): __tablename__ = "tapir_email_headers" __table_args__ = (ForeignKeyConstraint(["template_id"], ["tapir_email_templates.template_id"], name="0_563"),) - template_id: Mapped[int] = mapped_column(Integer, 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()) @@ -1598,9 +1601,9 @@ class TapirEmailMailing(Base): ) mailing_id: Mapped[intpk] - template_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) - created_by: Mapped[Optional[int]] = mapped_column(Integer, index=True) - sent_by: Mapped[Optional[int]] = mapped_column(Integer, 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) @@ -1627,8 +1630,8 @@ 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(Integer, nullable=False, index=True, server_default=FetchedValue()) - updated_by: 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()) @@ -1642,7 +1645,7 @@ class TapirEmailToken(Base): __tablename__ = "tapir_email_tokens" __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_530"),) - user_id: Mapped[int] = mapped_column(Integer, 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()) @@ -1657,25 +1660,25 @@ class TapirEmailToken(Base): t_tapir_email_tokens_used = Table( "tapir_email_tokens_used", metadata, - Column("user_id", Integer, nullable=False, server_default=FetchedValue()), + 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", Integer, 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, server_default=FetchedValue()), + 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, server_default=FetchedValue()), + 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, server_default=FetchedValue()), - Column("message", String(32), 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()), ) @@ -1694,7 +1697,7 @@ class TapirNickname(Base): nick_id: Mapped[intpk] nickname: Mapped[str] = mapped_column(String(20), nullable=False, index=True, server_default=FetchedValue()) - user_id: Mapped[int] = mapped_column(Integer, nullable=False, 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'")) @@ -1726,20 +1729,20 @@ class TapirNicknamesAudit(Base): ) -t_tapir_periodic_tasks_log = Table("tapir_periodic_tasks_log", metadata, Column("t", Integer, nullable=False, 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" __table_args__ = (ForeignKeyConstraint(["session_id"], ["tapir_sessions.session_id"], name="0_541"), ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_540")) - user_id: Mapped[int] = mapped_column(Integer, 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(Integer, nullable=False, index=True, server_default=FetchedValue()) + 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") @@ -1753,7 +1756,7 @@ class TapirPermanentToken(Base): Column("used_when", Integer), Column("used_from", String(16)), Column("remote_host", String(255), nullable=False, server_default=FetchedValue()), - Column("session_id", Integer, nullable=False, server_default=FetchedValue()), + Column("session_id", ForeignKey("tapir_sessions.session_id"), nullable=False, index=True, server_default=FetchedValue()), ) @@ -1761,7 +1764,7 @@ class TapirPhone(Base): __tablename__ = "tapir_phone" __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_520"),) - user_id: Mapped[int] = mapped_column(Integer, 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()) @@ -1805,7 +1808,7 @@ class TapirRecoveryToken(Base): __tablename__ = "tapir_recovery_tokens" __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_546"),) - user_id: Mapped[int] = mapped_column(Integer, 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()) @@ -1821,12 +1824,12 @@ class TapirRecoveryTokensUsed(Base): __tablename__ = "tapir_recovery_tokens_used" __table_args__ = (ForeignKeyConstraint(["session_id"], ["tapir_sessions.session_id"], name="0_549"), ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_548")) - user_id: Mapped[int] = mapped_column(Integer, 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(Integer, index=True) + 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") @@ -1835,7 +1838,7 @@ class TapirRecoveryTokensUsed(Base): t_tapir_save_post_variables = Table( "tapir_save_post_variables", metadata, - Column("presession_id", Integer, nullable=False, server_default=FetchedValue()), + 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()), @@ -1847,7 +1850,7 @@ class TapirSession(Base): __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_525"),) session_id: Mapped[int] = mapped_column(Integer, primary_key=True) - user_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) + 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'")) @@ -1863,7 +1866,7 @@ class TapirSessionsAudit(Base): __tablename__ = "tapir_sessions_audit" __table_args__ = (ForeignKeyConstraint(["session_id"], ["tapir_sessions.session_id"], name="0_527"),) - session_id: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=text("'0'")) + 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()) @@ -1900,7 +1903,7 @@ class TapirUser(Base): email: Mapped[str] = mapped_column(String(255), nullable=False, 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(Integer, 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("''")) @@ -1921,6 +1924,7 @@ class TapirUser(Base): 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 = 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") @@ -1930,7 +1934,9 @@ class TapirUser(Base): 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 = relationship("CrossControl", back_populates="user") arXiv_endorsement_requests: Mapped[List["EndorsementRequest"]] = relationship("EndorsementRequest", back_populates="endorsee") + arXiv_jref_controls = 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") @@ -1966,7 +1972,7 @@ class AuthorIds(Base): __tablename__ = "arXiv_author_ids" __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="arXiv_author_ids_ibfk_1"),) - user_id: Mapped[int] = mapped_column(Integer, 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()) @@ -1978,7 +1984,7 @@ class Demographic(Base): ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_587"), ) - user_id: Mapped[int] = mapped_column(Integer, 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()) @@ -2003,7 +2009,7 @@ class Demographic(Base): flag_group_econ: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'0'")) veto_status: Mapped[str] = mapped_column(Enum("ok", "no-endorse", "no-upload", "no-replace"), nullable=False, server_default=text("'ok'")) - arXiv_categories: Mapped["Category"] = relationship( + arXiv_category: Mapped["Category"] = relationship( "Category", primaryjoin="and_(Demographic.archive == Category.archive, Demographic.subject_class == Category.subject_class)", backref="category_demographics" ) @@ -2031,7 +2037,7 @@ class OrcidIds(Base): __tablename__ = "arXiv_orcid_ids" __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="arXiv_orcid_ids_ibfk_1"),) - user_id: Mapped[int] = mapped_column(Integer, 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()) @@ -2041,7 +2047,7 @@ class QueueView(Base): __tablename__ = "arXiv_queue_view" __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], ondelete="CASCADE", name="arXiv_queue_view_ibfk_1"),) - user_id: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) + 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()) @@ -2051,7 +2057,7 @@ class SuspiciousName(Base): __tablename__ = "arXiv_suspicious_names" __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_606"),) - user_id: Mapped[int] = mapped_column(Integer, 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()) @@ -2059,7 +2065,7 @@ class SwordLicense(Base): __tablename__ = "arXiv_sword_licenses" __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="user_id_fk"),) - user_id: Mapped[int] = mapped_column(Integer, 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()) @@ -2068,24 +2074,23 @@ class TapirDemographic(Base): __tablename__ = "tapir_demographics" __table_args__ = (ForeignKeyConstraint(["country"], ["tapir_countries.digraph"], name="0_518"), ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_517")) - user_id: Mapped[int] = mapped_column(Integer, 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[dt.date]] = mapped_column(Date, index=True) share_birthday: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - country: Mapped[str] = mapped_column(String(2), 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_countries: Mapped["TapirCountry"] = relationship("TapirCountry", back_populates="tapir_demographics") - tapir_countries: Mapped["TapirCountry"] = relationship("TapirCountry", back_populates="tapir_demographics") + tapir_country: Mapped["TapirCountry"] = relationship("TapirCountry", primaryjoin="TapirDemographic.country == TapirCountry.digraph", backref="tapir_demographics") class TapirUsersHot(Base): __tablename__ = "tapir_users_hot" __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_514"),) - user_id: Mapped[int] = mapped_column(Integer, 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()) @@ -2110,11 +2115,11 @@ class ArXivCheckResults(Base): ) check_result_id: Mapped[int] = mapped_column(Integer, primary_key=True) - submission_id: Mapped[int] = mapped_column(Integer, nullable=False, index=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(Integer, nullable=False, index=True) - user_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) + 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=text("CURRENT_TIMESTAMP")) message: Mapped[Optional[str]] = mapped_column(String(40)) @@ -2134,8 +2139,8 @@ class ArXivCheckResponses(Base): ) check_response_id: Mapped[int] = mapped_column(Integer, primary_key=True) - check_result_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) - user_id: Mapped[int] = mapped_column(Integer, nullable=False, index=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=text("CURRENT_TIMESTAMP")) @@ -2184,9 +2189,9 @@ class ArXivChecks(Base): ) check_id: Mapped[int] = mapped_column(Integer, primary_key=True) - check_target_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) - check_role_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) - check_result_view_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'1'")) + check_target_id: Mapped[int] = mapped_column(ForeignKey("arXiv_check_targets.check_target_id"), nullable=False, index=True) + check_role_id: Mapped[int] = mapped_column(ForeignKey("arXiv_check_roles.check_role_id"), nullable=False, index=True) + 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) 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'")) @@ -2211,8 +2216,8 @@ class ArXivSubmissionLocks(Base): ) 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) + 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) diff --git a/arxiv/db/orig_models.py b/arxiv/db/orig_models.py index 4e3d3a6a7..0e35074f1 100644 --- a/arxiv/db/orig_models.py +++ b/arxiv/db/orig_models.py @@ -457,6 +457,7 @@ class Document(Base): # 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") + # link the cross control arXiv_cross_controls = relationship('CrossControl', back_populates='document') class DBLP(Document): @@ -679,6 +680,7 @@ class Metadata(Base): 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') diff --git a/development/db_codegen.py b/development/db_codegen.py index 9919c104d..cacccd52d 100644 --- a/development/db_codegen.py +++ b/development/db_codegen.py @@ -23,6 +23,7 @@ "t_arXiv_ownership_requests_papers": True, "t_arXiv_updates_tmp": True, "t_arXiv_admin_state": True, + # "t_arXiv_in_category": True, } def first_target(body): @@ -50,7 +51,6 @@ def patch_mysql_types(contents: str): (re.compile(r'= mapped_column\(TIMESTAMP'), r'= mapped_column(DateTime'), # Replace MEDIUMTEXT with Text (re.compile(r'= mapped_column\(CHAR\s*\((\d+)\)'), r'= mapped_column(String(\1)'), # Replace CHAR(size) with str (re.compile(r' CHAR\s*\((\d+)\),'), r' String(\1),'), # Replace CHAR(size) with str - (re.compile(r' class_:'), r' _class:'), # (re.compile(r'Mapped\[decimal.Decimal\]'), r'Mapped[float]'), # (re.compile(r'Mapped\[datetime.datetime\]'), r'Mapped[datetime]'), # (re.compile(r'Optional\[datetime.datetime\]'), r'Optional[datetime]'), # @@ -59,6 +59,7 @@ def patch_mysql_types(contents: str): (re.compile(r'MEDIUMINT(\(\d+\)){0,1}'), r'Integer'), (re.compile(r'SMALLINT(\(\d+\)){0,1}'), r'Integer'), (re.compile(r'MEDIUMTEXT(\(\d+\)){0,1}'), r'Text'), + (re.compile(r'Base\.metadata'), r'metadata'), (re.compile(r'text\("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"\)'), r'FetchdValue()'), (re.compile(r'datetime\.date'), r'dt.date'), @@ -191,32 +192,32 @@ def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef continue updated_body.append(elem) - # Warn the left over assigns - if existing_assignments: - # ignore all uppers - props = [prop for prop in existing_assignments.keys() if prop.upper() != prop] - if props: - logging.info("#") - logging.info(f"# {class_name}") - for prop in props: - logging.info(f" {prop}") - logging.info("#") - 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 return updated_node.with_changes(body=updated_node.body.with_changes(body=updated_body)) return updated_node @@ -263,11 +264,37 @@ def leave_Assign(self, original_node: cst.Assign, updated_node: cst.Assign) -> c 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 = latest_table_def.value - rh_old = updated_node.value - # Update the table def's RH with new's RH + rh_new = updated_node.value + rh_old = original_node.value + + # Assignments do have ards if hasattr(rh_new, 'args') and hasattr(rh_old, 'args'): + # + # 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") @@ -277,12 +304,15 @@ def leave_Assign(self, original_node: cst.Assign, updated_node: cst.Assign) -> c columns[column_name] = old_col for i_col, new_column in enumerate(rh_new.args): - # I only care the Column("foo") + # I only care the Column("") if isinstance(new_column.value, cst.Call) and new_column.value.func.value == "Column": - # column def + # 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) @@ -321,7 +351,7 @@ def main() -> None: sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "sqlacodegen", "src")) subprocess.run(['development/sqlacodegen/venv/bin/python', '-m', 'sqlacodegen', p_url, '--outfile', p_outfile, '--model-metadata', "arxiv/db/arxiv-db-metadata.yaml"], check=True) - subprocess.run(['development/sqlacodegen/venv/bin/python', '-m', 'sqlacodegen', p_url, '--outfile', "arxiv/db/raw-autogen_models.py"], check=True) + # subprocess.run(['development/sqlacodegen/venv/bin/python', '-m', 'sqlacodegen', p_url, '--outfile', "arxiv/db/raw-autogen_models.py"], check=True) with open(p_outfile, 'r') as src: source = src.read() From b37df31b7081573ccbbb453122adef9f2ac492dd Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Fri, 8 Nov 2024 11:32:43 -0500 Subject: [PATCH 10/32] Add docstring copy. Mark some of classes deprecated with it. --- arxiv/db/arxiv-db-metadata.yaml | 4 ++++ arxiv/db/models.py | 9 ++++++++- arxiv/db/orig_models.py | 5 ++++- development/db_codegen.py | 19 ++++++++++++++++--- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/arxiv/db/arxiv-db-metadata.yaml b/arxiv/db/arxiv-db-metadata.yaml index 47da6b262..7240b9482 100644 --- a/arxiv/db/arxiv-db-metadata.yaml +++ b/arxiv/db/arxiv-db-metadata.yaml @@ -281,6 +281,10 @@ arXiv_submissions: arXiv_pilot_datasets: class_name: PilotDataset + columns: + # Kill off the slot + created: drop + arXiv_submission_abs_classifier_data: class_name: SubmissionAbsClassifierDatum arXiv_submission_classifier_data: diff --git a/arxiv/db/models.py b/arxiv/db/models.py index 0db8a2362..dc58464a8 100644 --- a/arxiv/db/models.py +++ b/arxiv/db/models.py @@ -56,6 +56,8 @@ class MemberInstitution(Base): + """Deprecated - superceded by membership_institutions""" + __tablename__ = "Subscription_UniversalInstitution" resolver_URL: Mapped[Optional[str]] = mapped_column(String(255)) @@ -68,6 +70,8 @@ class MemberInstitution(Base): class MemberInstitutionContact(Base): + """Deprecated - superceded by membership_institution_users""" + __tablename__ = "Subscription_UniversalInstitutionContact" email: Mapped[Optional[str]] = mapped_column(String(255)) @@ -871,6 +875,8 @@ class PaperSession(Base): class PilotFile(Base): + """arXiv_pilot is deprecated""" + __tablename__ = "arXiv_pilot_files" __table_args__ = (ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], name="arXiv_pilot_files_cdfk3"),) @@ -1208,6 +1214,8 @@ class Submission(Base): class PilotDataset(Submission): + """arXiv_pilot is deprecated""" + __tablename__ = "arXiv_pilot_datasets" __table_args__ = (ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], name="arXiv_pilot_datasets_cdfk3"),) @@ -1219,7 +1227,6 @@ class PilotDataset(Submission): # created: Mapped[datetime] = mapped_column(DateTime, nullable=False) # ^This column is inherited last_checked: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) - created: Mapped[datetime] = mapped_column(DateTime, nullable=False) class SubmissionAbsClassifierDatum(Base): diff --git a/arxiv/db/orig_models.py b/arxiv/db/orig_models.py index 0e35074f1..6584897fa 100644 --- a/arxiv/db/orig_models.py +++ b/arxiv/db/orig_models.py @@ -61,6 +61,7 @@ class MemberInstitution(Base): + """Deprecated - superceded by membership_institutions""" __tablename__ = 'Subscription_UniversalInstitution' resolver_URL: Mapped[Optional[str]] = mapped_column(String(255)) @@ -73,6 +74,7 @@ class MemberInstitution(Base): class MemberInstitutionContact(Base): + """Deprecated - superceded by membership_institution_users""" __tablename__ = 'Subscription_UniversalInstitutionContact' email: Mapped[Optional[str]] = mapped_column(String(255)) @@ -86,7 +88,6 @@ class MemberInstitutionContact(Base): Subscription_UniversalInstitution = relationship('MemberInstitution', primaryjoin='MemberInstitutionContact.sid == MemberInstitution.id') - class MemberInstitutionIP(Base): __tablename__ = 'Subscription_UniversalInstitutionIP' __table_args__ = ( @@ -857,6 +858,7 @@ class PaperSession(Base): class PilotFile(Base): + """arXiv_pilot is deprecated""" __tablename__ = 'arXiv_pilot_files' file_id: Mapped[intpk] @@ -1160,6 +1162,7 @@ class Submission(Base): 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) diff --git a/development/db_codegen.py b/development/db_codegen.py index cacccd52d..ed752c357 100644 --- a/development/db_codegen.py +++ b/development/db_codegen.py @@ -149,12 +149,21 @@ def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef "__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 @@ -186,11 +195,14 @@ def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef # Adjust the slot order based on the existing slot while appending the new ones at the botom updated_body.sort(key=lambda slot: original_slot_order[self.first_target(slot)]) - # Append the non-assigns + # 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 - updated_body.append(elem) + if after_assign: + updated_body.append(elem) a_key: str intended = {} @@ -219,7 +231,8 @@ def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef logging.warning(f"Class with extra existing assignmet(s):\n" + "\n".join(extras)) # Rebuild the class body with updated assignments - return updated_node.with_changes(body=updated_node.body.with_changes(body=updated_body)) + 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): From 38a44eafdbdec72d65798350256ef9ea81b74976 Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Mon, 11 Nov 2024 15:43:51 -0500 Subject: [PATCH 11/32] All of sqlalchemy warnings are resolved. On to test with arxiv-browse. --- arxiv/auth/auth/tests/test_decorators.py | 1 + arxiv/db/arxiv-db-metadata.yaml | 84 ++++++++++++++---- arxiv/db/models.py | 106 ++++++++++------------- arxiv/db/orig_models.py | 25 +++--- 4 files changed, 126 insertions(+), 90 deletions(-) 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/db/arxiv-db-metadata.yaml b/arxiv/db/arxiv-db-metadata.yaml index 7240b9482..86ba66f02 100644 --- a/arxiv/db/arxiv-db-metadata.yaml +++ b/arxiv/db/arxiv-db-metadata.yaml @@ -51,8 +51,13 @@ 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: @@ -66,9 +71,13 @@ arXiv_bogus_countries: arXiv_categories: class_name: Category relationships: - arXiv_demographics: "relationship('Demographic', back_populates='arXiv_category')" - additional_relationships: - - "arXiv_endorsement_domain = relationship('EndorsementDomain', primaryjoin='Category.endorsement_domain == EndorsementDomain.endorsement_domain', back_populates='arXiv_categories')" + arXiv_demographics: "" + arXiv_archives: "" + arXiv_cross_control: + arXiv_cross_controls: "relationship('CrossControl', back_populates='arXiv_category')" + arXiv_categories: "" + arXiv_endorsement_domains: + arXiv_endorsement_domain: "relationship('EndorsementDomain', primaryjoin='Category.endorsement_domain == EndorsementDomain.endorsement_domain', back_populates='arXiv_categories')" arXiv_questionable_categories: class_name: QuestionableCategory @@ -76,14 +85,19 @@ 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())" - additional_relationships: - - "arXiv_category = relationship('Category', primaryjoin='and_(CrossControl.archive == Category.archive, CrossControl.subject_class == Category.subject_class)', back_populates='arXiv_cross_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')" + 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 @@ -100,8 +114,12 @@ arXiv_documents: class_name: Document relationships: arXiv_dblp_document_authors: "" - additional_relationships: - - "owners = relationship('PaperOwner', back_populates='document')" + arXiv_paper_owners: + owners: "relationship('PaperOwner', back_populates='document')" + arXiv_cross_control: + arXiv_cross_controls: "relationship('CrossControl', back_populates='document')" + arXiv_jref_control: + arXiv_jref_controls: "relationship('JrefControl', back_populates='document')" arXiv_dblp: class_name: DBLP @@ -116,14 +134,17 @@ arXiv_paper_pw: 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: - - "endorsement = relationship('Endorsement', back_populates='request', uselist=False)" - "audit = relationship('EndorsementRequestsAudit', uselist=False)" arXiv_endorsement_requests_audit: @@ -134,6 +155,10 @@ arXiv_endorsements: table_args: - replace: ["Index('archive', 'archive', 'subject_class'),", ""] # - replace: ["Index('endorser_id_2', 'endorser_id', 'endorsee_id', 'archive', 'subject_class', unique=True),", ""] + 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: @@ -142,6 +167,9 @@ 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: @@ -149,10 +177,16 @@ arXiv_jref_control: 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 @@ -168,6 +202,8 @@ 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: @@ -220,6 +256,11 @@ arXiv_paper_owners: 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: @@ -274,10 +315,8 @@ 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_check_results: "relationship('ArXivCheckResults', back_populates='submission')" - arXiv_submission_locks: "relationship('ArXivSubmissionLocks', back_populates='submission')" - additional_relationships: - - "arXiv_license = relationship('License', primaryjoin='Submission.license == License.name', 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 @@ -398,14 +437,23 @@ 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: - - "endorsee_of = relationship('Endorsement', foreign_keys='[Endorsement.endorsee_id]', back_populates='endorsee')" - - "endorses = relationship('Endorsement', foreign_keys='[Endorsement.endorser_id]', back_populates='endorser')" - - "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')" - - "arXiv_moderator_api_keys = relationship('ModeratorApiKey', back_populates='user')" - - "arXiv_cross_controls = relationship('CrossControl', back_populates='user')" - - "arXiv_jref_controls = relationship('JrefControl', back_populates='user')" arXiv_author_ids: class_name: AuthorIds diff --git a/arxiv/db/models.py b/arxiv/db/models.py index dc58464a8..516323ef6 100644 --- a/arxiv/db/models.py +++ b/arxiv/db/models.py @@ -201,8 +201,7 @@ class Archive(Base): 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_groups: Mapped["Group"] = relationship("Group", back_populates="arXiv_archives") - arXiv_categories: Mapped[List["Category"]] = relationship("Category", back_populates="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") @@ -303,13 +302,12 @@ class Category(Base): 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_endorsement_domain = 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_archives: Mapped["Archive"] = relationship("Archive", back_populates="arXiv_categories") - arXiv_endorsement_domains: Mapped["EndorsementDomain"] = relationship("EndorsementDomain", back_populates="arXiv_categories") - arXiv_cross_control: Mapped[List["CrossControl"]] = relationship("CrossControl", back_populates="arXiv_categories") - arXiv_demographics: Mapped[List["Demographic"]] = relationship("Demographic", back_populates="arXiv_category") + 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_cross_controls: Mapped[List["CrossControl"]] = relationship("CrossControl", back_populates="arXiv_category") # link to category arXiv_archive = relationship("Archive", primaryjoin="Category.archive == Archive.archive_id", back_populates="arXiv_categories") @@ -378,11 +376,12 @@ class CrossControl(Base): 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)", back_populates="arXiv_cross_control") - document: Mapped["Document"] = relationship("Document", back_populates="arXiv_cross_control") - user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_cross_control") - arXiv_categories: Mapped["Category"] = relationship("Category", back_populates="arXiv_cross_control") + 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): @@ -454,21 +453,18 @@ class Document(Base): # 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") + owners: Mapped[List["PaperOwner"]] = relationship("PaperOwner", back_populates="document") + arXiv_cross_controls: Mapped[List["CrossControl"]] = relationship("CrossControl", back_populates="document") arXiv_admin_metadata: Mapped[List["AdminMetadata"]] = relationship("AdminMetadata", back_populates="document") - arXiv_cross_control: Mapped[List["CrossControl"]] = relationship("CrossControl", back_populates="document") arXiv_document_category: Mapped[List["DocumentCategory"]] = relationship("DocumentCategory", back_populates="document") - arXiv_jref_control: Mapped[List["JrefControl"]] = relationship("JrefControl", 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_paper_owners: Mapped[List["PaperOwner"]] = relationship("PaperOwner", 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") - # link the cross control - arXiv_cross_controls = relationship("CrossControl", back_populates="document") class DBLP(Document): @@ -505,7 +501,7 @@ class EndorsementDomain(Base): endorse_email: Mapped[str] = 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_domains") + arXiv_categories: Mapped[List["Category"]] = relationship("Category", back_populates="arXiv_endorsement_domain") class EndorsementRequest(Base): @@ -529,9 +525,8 @@ class EndorsementRequest(Base): "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 = relationship("Endorsement", back_populates="request", uselist=False) + endorsement: Mapped["Endorsement"] = relationship("Endorsement", back_populates="request", uselist=False) audit = relationship("EndorsementRequestsAudit", uselist=False) - arXiv_endorsements: Mapped[List["Endorsement"]] = relationship("Endorsement", back_populates="request") arXiv_ownership_requests: Mapped[List["OwnershipRequest"]] = relationship("OwnershipRequest", back_populates="endorsement_request") @@ -568,9 +563,9 @@ class Endorsement(Base): request_id: Mapped[Optional[int]] = mapped_column(ForeignKey("arXiv_endorsement_requests.request_id"), index=True) arXiv_categories: Mapped["Category"] = relationship("Category", back_populates="arXiv_endorsements") - endorsee: Mapped["TapirUser"] = relationship("TapirUser", foreign_keys=[endorsee_id], back_populates="arXiv_endorsements") - endorser: Mapped["TapirUser"] = relationship("TapirUser", foreign_keys=[endorser_id], back_populates="arXiv_endorsements_") - request: Mapped["EndorsementRequest"] = relationship("EndorsementRequest", 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): @@ -607,7 +602,7 @@ class Group(Base): 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_groups") + arXiv_archives: Mapped[List["Archive"]] = relationship("Archive", back_populates="arXiv_group") t_arXiv_in_category = Table( @@ -642,8 +637,8 @@ class JrefControl(Base): 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: Mapped["Document"] = relationship("Document", back_populates="arXiv_jref_control") - user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_jref_control") + document: Mapped["Document"] = relationship("Document", back_populates="arXiv_jref_controls") + user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_jref_controls") class License(Base): @@ -655,7 +650,7 @@ class License(Base): 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_licenses") + arXiv_submissions: Mapped[List["Submission"]] = relationship("Submission", back_populates="arXiv_license") class LogPosition(Base): @@ -737,7 +732,7 @@ class ModeratorApiKey(Base): 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: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_moderator_api_key") + user: Mapped["TapirUser"] = relationship("TapirUser", primaryjoin="ModeratorApiKey.user_id == TapirUser.user_id", back_populates="arXiv_moderator_api_keys") t_arXiv_moderators = Table( @@ -849,20 +844,18 @@ class PaperOwner(Base): 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=FetchedValue()) - added_by: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), nullable=False, index=True, 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(32), nullable=False, server_default=FetchedValue()) - valid: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - flag_author: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - flag_auto: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - document: Mapped["Document"] = relationship("Document", back_populates="arXiv_paper_owners") + date: 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(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: Mapped["Document"] = relationship("Document", back_populates="owners") owner = relationship("TapirUser", foreign_keys="[PaperOwner.user_id]", back_populates="owned_papers") - tapir_users: Mapped["TapirUser"] = relationship("TapirUser", foreign_keys=[added_by], back_populates="arXiv_paper_owners") - user: Mapped["TapirUser"] = relationship("TapirUser", foreign_keys=[user_id], back_populates="arXiv_paper_owners_") - class PaperSession(Base): __tablename__ = "arXiv_paper_sessions" @@ -1190,11 +1183,9 @@ class Submission(Base): 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 = relationship("License", primaryjoin="Submission.license == License.name", 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") - arXiv_check_results: Mapped[List["ArXivCheckResults"]] = relationship("ArXivCheckResults", back_populates="submission") - arXiv_submission_locks: Mapped[List["ArXivSubmissionLocks"]] = relationship("ArXivSubmissionLocks", 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'")) @@ -1202,16 +1193,20 @@ class Submission(Base): 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_licenses: Mapped["License"] = relationship("License", back_populates="arXiv_submissions") + arXiv_check_results: Mapped[List["ArXivCheckResults"]] = relationship("ArXivCheckResults", back_populates="submission") 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_locks: Mapped[List["ArXivSubmissionLocks"]] = relationship("ArXivSubmissionLocks", 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") + # arXiv_check_results: Mapped[List["ArXivCheckResults"]] = relationship("ArXivCheckResults", back_populates="submission") + # arXiv_submission_locks: Mapped[List["ArXivSubmissionLocks"]] = relationship("ArXivSubmissionLocks", back_populates="submission") + class PilotDataset(Submission): """arXiv_pilot is deprecated""" @@ -1379,7 +1374,7 @@ class Updates(Base): document_id: Mapped[Optional[int]] = mapped_column( ForeignKey("arXiv_documents.document_id", ondelete="CASCADE", onupdate="CASCADE"), index=True, - server_defaults=text("'0'"), + server_default=text("'0'"), ) version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) @@ -1931,7 +1926,7 @@ class TapirUser(Base): 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 = relationship("ModeratorApiKey", back_populates="user") + 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") @@ -1941,9 +1936,9 @@ class TapirUser(Base): 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 = relationship("CrossControl", 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 = relationship("JrefControl", back_populates="user") + 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") @@ -1954,8 +1949,8 @@ class TapirUser(Base): 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 = relationship("Endorsement", foreign_keys="[Endorsement.endorsee_id]", back_populates="endorsee") - endorses = relationship("Endorsement", foreign_keys="[Endorsement.endorser_id]", back_populates="endorser") + 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") @@ -1964,15 +1959,8 @@ class TapirUser(Base): arXiv_submission_view_flag: Mapped[List["SubmissionViewFlag"]] = relationship("SubmissionViewFlag", back_populates="user") arXiv_check_results: Mapped[List["ArXivCheckResults"]] = relationship("ArXivCheckResults", back_populates="user") arXiv_check_responses: Mapped[List["ArXivCheckResponses"]] = relationship("ArXivCheckResponses", back_populates="user") - owned_papers = relationship("PaperOwner", foreign_keys="[PaperOwner.user_id]", back_populates="owner") + 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") - arXiv_moderator_api_key: Mapped[List["ModeratorApiKey"]] = relationship("ModeratorApiKey", back_populates="user") - arXiv_cross_control: Mapped[List["CrossControl"]] = relationship("CrossControl", back_populates="user") - arXiv_jref_control: Mapped[List["JrefControl"]] = relationship("JrefControl", back_populates="user") - arXiv_paper_owners: Mapped[List["PaperOwner"]] = relationship("PaperOwner", foreign_keys="[PaperOwner.added_by]", back_populates="tapir_users") - arXiv_paper_owners_: Mapped[List["PaperOwner"]] = relationship("PaperOwner", foreign_keys="[PaperOwner.user_id]", back_populates="user") - arXiv_endorsements: Mapped[List["Endorsement"]] = relationship("Endorsement", foreign_keys="[Endorsement.endorsee_id]", back_populates="endorsee") - arXiv_endorsements_: Mapped[List["Endorsement"]] = relationship("Endorsement", foreign_keys="[Endorsement.endorser_id]", back_populates="endorser") class AuthorIds(Base): diff --git a/arxiv/db/orig_models.py b/arxiv/db/orig_models.py index 6584897fa..85c6e664a 100644 --- a/arxiv/db/orig_models.py +++ b/arxiv/db/orig_models.py @@ -458,7 +458,6 @@ class Document(Base): # 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") - # link the cross control arXiv_cross_controls = relationship('CrossControl', back_populates='document') class DBLP(Document): @@ -833,14 +832,14 @@ class PaperOwner(Base): 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=FetchedValue()) - added_by: 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(32), nullable=False, server_default=FetchedValue()) - valid: Mapped[int] = mapped_column(SmallInteger, nullable=False, server_default=FetchedValue()) - flag_author: Mapped[int] = mapped_column(SmallInteger, nullable=False, server_default=FetchedValue()) - flag_auto: Mapped[int] = mapped_column(SmallInteger, nullable=False, server_default=FetchedValue()) + 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') @@ -1157,8 +1156,9 @@ class Submission(Base): 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') - arXiv_check_results: Mapped[List["ArXivCheckResults"]] = relationship("ArXivCheckResults", back_populates="submission") - arXiv_submission_locks: Mapped[List["ArXivSubmissionLocks"]] = relationship("ArXivSubmissionLocks", back_populates="submission") + + # arXiv_check_results: Mapped[List["ArXivCheckResults"]] = relationship("ArXivCheckResults", back_populates="submission") + # arXiv_submission_locks: Mapped[List["ArXivSubmissionLocks"]] = relationship("ArXivSubmissionLocks", back_populates="submission") class PilotDataset(Submission): @@ -1316,7 +1316,7 @@ class Updates(Base): document_id: Mapped[Optional[int]] = mapped_column( ForeignKey("arXiv_documents.document_id", ondelete="CASCADE", onupdate="CASCADE"), index=True, - server_defaults=text("'0'"), + 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) @@ -2004,7 +2004,6 @@ class QueueView(Base): total_views: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - class SuspiciousName(Base): __tablename__ = 'arXiv_suspicious_names' From 75d67ea28a3f5124a768dfd80630796c20ef59cc Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Mon, 11 Nov 2024 17:09:11 -0500 Subject: [PATCH 12/32] Ues SOURCE_FORMAT from arxiv.document.versions for Metadata.source_format. --- arxiv/db/arxiv-db-metadata.yaml | 2 ++ arxiv/db/models.py | 3 ++- arxiv/db/orig_models.py | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arxiv/db/arxiv-db-metadata.yaml b/arxiv/db/arxiv-db-metadata.yaml index 86ba66f02..2842e9fe0 100644 --- a/arxiv/db/arxiv-db-metadata.yaml +++ b/arxiv/db/arxiv-db-metadata.yaml @@ -192,6 +192,8 @@ arXiv_log_positions: 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')" diff --git a/arxiv/db/models.py b/arxiv/db/models.py index 516323ef6..1181d5d53 100644 --- a/arxiv/db/models.py +++ b/arxiv/db/models.py @@ -50,6 +50,7 @@ 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) @@ -679,7 +680,7 @@ class Metadata(Base): 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[str]] = 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) diff --git a/arxiv/db/orig_models.py b/arxiv/db/orig_models.py index 85c6e664a..06de52349 100644 --- a/arxiv/db/orig_models.py +++ b/arxiv/db/orig_models.py @@ -55,6 +55,7 @@ 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) From 2eaaa2fb5ea989593e7ea57e381d26e5834c37ab Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Mon, 11 Nov 2024 17:46:17 -0500 Subject: [PATCH 13/32] If the column is "enum", use the enum values for the slot type. --- arxiv/db/models.py | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/arxiv/db/models.py b/arxiv/db/models.py index 1181d5d53..7e138d1b9 100644 --- a/arxiv/db/models.py +++ b/arxiv/db/models.py @@ -298,8 +298,8 @@ class Category(Base): 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[str] = mapped_column(Enum("y", "n", "d"), nullable=False, server_default=text("'d'")) - endorse_email: Mapped[str] = mapped_column(Enum("y", "n", "d"), nullable=False, server_default=text("'d'")) + 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") @@ -344,11 +344,13 @@ class ControlHold(Base): hold_id: Mapped[intpk] control_id: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - hold_type: Mapped[str] = mapped_column(Enum("submission", "cross", "jref"), nullable=False, index=True, server_default=FetchedValue()) - hold_status: Mapped[str] = 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[str] = mapped_column(Enum("auto", "user", "admin", "moderator"), nullable=False, index=True, 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) @@ -370,8 +372,8 @@ class CrossControl(Base): 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[str] = mapped_column(Enum("new", "frozen", "published", "rejected"), nullable=False, index=True, server_default=FetchedValue()) - flag_must_notify: Mapped[Optional[str]] = mapped_column(Enum("0", "1"), 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()) @@ -390,7 +392,7 @@ class DataciteDois(Base): __table_args__ = (ForeignKeyConstraint(["metadata_id"], ["arXiv_metadata.metadata_id"], name="arXiv_datacite_dois_ibfk_1"), Index("account_paper_id", "account", "paper_id", unique=True)) doi: Mapped[str] = mapped_column(String(255), primary_key=True) - account: Mapped[Optional[str]] = mapped_column(Enum("test", "prod")) + 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()) @@ -497,9 +499,9 @@ class EndorsementDomain(Base): __tablename__ = "arXiv_endorsement_domains" endorsement_domain: Mapped[str] = mapped_column(String(32), primary_key=True, server_default=FetchedValue()) - endorse_all: Mapped[str] = mapped_column(Enum("y", "n"), nullable=False, server_default=FetchedValue()) - mods_endorse_all: Mapped[str] = mapped_column(Enum("y", "n"), nullable=False, server_default=FetchedValue()) - endorse_email: Mapped[str] = mapped_column(Enum("y", "n"), 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") @@ -558,7 +560,7 @@ class Endorsement(Base): 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[str]] = 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) @@ -631,8 +633,8 @@ class JrefControl(Base): 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[str] = mapped_column(Enum("new", "frozen", "published", "rejected"), nullable=False, index=True, server_default=FetchedValue()) - flag_must_notify: Mapped[Optional[str]] = mapped_column(Enum("0", "1"), 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()) @@ -816,7 +818,7 @@ class OwnershipRequest(Base): 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[str] = mapped_column(Enum("pending", "accepted", "rejected"), nullable=False, server_default=FetchedValue()) + 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: Mapped["EndorsementRequest"] = relationship( @@ -1029,8 +1031,8 @@ class SubmissionControl(Base): 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[str] = mapped_column(Enum("new", "frozen", "published", "rejected"), nullable=False, index=True, server_default=FetchedValue()) - flag_must_notify: Mapped[Optional[str]] = mapped_column(Enum("0", "1"), 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()) @@ -1232,7 +1234,7 @@ class SubmissionAbsClassifierDatum(Base): 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[str]] = 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, server_default=text("'0'")) suggested_primary: Mapped[Optional[str]] = mapped_column(Text) @@ -1250,7 +1252,7 @@ class SubmissionClassifierDatum(Base): 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[str]] = 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, server_default=text("'0'")) @@ -2003,7 +2005,7 @@ 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[str] = mapped_column(Enum("ok", "no-endorse", "no-upload", "no-replace"), nullable=False, server_default=text("'ok'")) + 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'")) arXiv_category: Mapped["Category"] = relationship( "Category", primaryjoin="and_(Demographic.archive == Category.archive, Demographic.subject_class == Category.subject_class)", backref="category_demographics" From 8c5d352b0f888d515f80c86547b4cbe4c9a2a20b Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Tue, 12 Nov 2024 15:42:45 -0500 Subject: [PATCH 14/32] More docs, comments and helpers. --- arxiv/db/models.py | 14 +- development/README.md | 97 ++++++++++ ...iv_schema_dump.sql => arxiv_db_schema.sql} | 0 development/db_codegen.py | 165 ++++++++++++++---- 4 files changed, 239 insertions(+), 37 deletions(-) rename development/{arxiv_schema_dump.sql => arxiv_db_schema.sql} (100%) diff --git a/arxiv/db/models.py b/arxiv/db/models.py index 7e138d1b9..af69114b1 100644 --- a/arxiv/db/models.py +++ b/arxiv/db/models.py @@ -1102,7 +1102,7 @@ class SubmissionQaReport(Base): 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()) + num_flags: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) report: Mapped[dict] = mapped_column(JSON, nullable=False) report_uri: Mapped[Optional[str]] = mapped_column(String(256)) @@ -1189,11 +1189,11 @@ class Submission(Base): 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") - 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_version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) + metadata_version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) + data_needed: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + data_version_queued: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) + metadata_version_queued: Mapped[int] = mapped_column(Integer, 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_check_results: Mapped[List["ArXivCheckResults"]] = relationship("ArXivCheckResults", back_populates="submission") @@ -2194,7 +2194,7 @@ class ArXivChecks(Base): 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'")) + retry_minutes: Mapped[int] = mapped_column(Integer, 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'")) description: Mapped[Optional[str]] = mapped_column(String(200)) diff --git a/development/README.md b/development/README.md index e69de29bb..e3d11f2a6 100644 --- a/development/README.md +++ b/development/README.md @@ -0,0 +1,97 @@ +# Generating arxiv/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 + +This will generate arxiv/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` + +## Anatomy of db_codegen.py + +does following steps. + +1. start mysql docker +2. load arxiv/db/arxiv_db_schema.sql to the local mysql +3. runs the modified development/sqlacodegen with the codegen metadata. This generates arxvi/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 sqlacodegn 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. + +### 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 if 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 output. You need to manually add the class +to arxiv/db/orig_models.py**. + +### Merging rules of SchemaTransformer + +CST provides a tree traversing method that takes an object of Transformer (cst.CSTTransformer). + +The tree travering 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. + diff --git a/development/arxiv_schema_dump.sql b/development/arxiv_db_schema.sql similarity index 100% rename from development/arxiv_schema_dump.sql rename to development/arxiv_db_schema.sql diff --git a/development/db_codegen.py b/development/db_codegen.py index ed752c357..6f4fcae90 100644 --- a/development/db_codegen.py +++ b/development/db_codegen.py @@ -1,17 +1,23 @@ +""" arxiv-base/development/db_codegen.py + +Generated arxiv-base/arxiv/db/models.py + +The script + +""" + from __future__ import annotations import re import sys import os -import subprocess +import time from typing import Tuple import logging - -from libcst.matchers import SimpleStatementLine -from ruamel.yaml import YAML - -# import ast import libcst as cst +import socket +import subprocess + logging.basicConfig(level=logging.INFO) @@ -26,7 +32,8 @@ # "t_arXiv_in_category": True, } -def first_target(body): +def first_target(body: cst.CSTNode): + """Get the first LHS name""" if hasattr(body, 'targets'): return body.targets[0].id if hasattr(body, 'target'): @@ -34,10 +41,13 @@ def first_target(body): return None -def is_intpk(elem): +def is_intpk(elem: cst.CSTNode): + """Figure out this is intpk""" return hasattr(elem, 'annotation') and hasattr(elem.annotation, 'slice') and hasattr(elem.annotation.slice, 'id') and elem.annotation.slice.id == "intpk" + def patch_mysql_types(contents: str): + """Mass regex replace the python code for mostly MySQL dependant types.""" # Define a mapping of MySQL dialect types to generic SQLAlchemy types type_mapping = [ (re.compile(r'= mapped_column\(BIGINT\s*\(\d+\)'), r'= mapped_column(BigInteger'), # Replace BIGINT(size) with BIGINT @@ -77,27 +87,38 @@ def mapper(line: str) -> str: return contents -def is_assign_expr(elem): +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): +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): +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""" + """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)) @@ -122,20 +143,34 @@ def copy_server_default(to_elem: cst.Call, from_elem: cst.Call) -> cst.Call: 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. + """ def __init__(self, latest_def, latest_tables): 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 + # 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) @@ -143,7 +178,8 @@ def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef updated_body = [] - # Remember the original slot order + # Remember the original slot order. __tablename__ and __table_args__ are special. it is always the + # first and 2nd. original_slot_order = { "__tablename__": 0, "__table_args__": 1, @@ -184,7 +220,7 @@ def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef ]) pass updated_body.append(elem) - # Remove this from the existing assignments so it's not processed again + # 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 @@ -192,7 +228,7 @@ def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef 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 botom + # 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" @@ -222,7 +258,7 @@ def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef intended[a_key] = a_value continue - # Warn the left over assigns + # Warn the left over assigns. if existing_assignments: # ignore all uppers props = [prop for prop in existing_assignments.keys() if prop not in intended] @@ -235,7 +271,7 @@ def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef return updated_node.with_changes(body=updated_node.body.with_changes(body=body)) return updated_node - def first_target(self, node): + def first_target(self, node: cst.CSTNode): if is_assign_expr(node): if hasattr(node.body[0], 'target'): return node.body[0].target.value @@ -243,7 +279,8 @@ def first_target(self, node): return node.body[0].targets[0].target.value return None - def is_intpk(self, elem): + def is_intpk(self, elem: cst.CSTNode): + """Find the intpk and print it as so""" if isinstance(elem, cst.SimpleStatementLine): if hasattr(elem.body[0], 'annotation'): for anno in elem.body[0].annotation.children: @@ -255,19 +292,26 @@ def is_intpk(self, elem): return True return False - def has_comment(self, elem): + def has_comment(self, elem: cst.CSTNode): + """commented?""" if isinstance(elem, cst.SimpleStatementLine): return elem.leading_lines and elem.leading_lines[-1].comment 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 @@ -341,7 +385,7 @@ def leave_Assign(self, original_node: cst.Assign, updated_node: cst.Assign) -> c return updated_node -def find_classes_and_tables(tree): +def find_classes_and_tables(tree: cst.CSTNode): classes = {} tables = {} @@ -353,18 +397,79 @@ def find_classes_and_tables(tree): return classes, tables +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 run_mysql_container(port: int): + """Start a mysql docker""" + mysql_image = "mysql:5.7" + 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 alreayd 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: - p_outfile = "arxiv/db/autogen_models.py" + 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") - #with open(os.path.expanduser('~/.arxiv/arxiv-db-prod-readonly'), encoding='utf-8') as uri_fd: - # p_url: str = uri_fd.read().strip() - #with open(os.path.expanduser('~/.arxiv/arxiv-db-dev-proxy'), encoding='utf-8') as uri_fd: - # p_url: str = uri_fd.read().strip() - p_url = "mysql://testuser:testpassword@127.0.0.1/testdb" - sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "sqlacodegen", "src")) - subprocess.run(['development/sqlacodegen/venv/bin/python', '-m', 'sqlacodegen', p_url, '--outfile', p_outfile, '--model-metadata', "arxiv/db/arxiv-db-metadata.yaml"], check=True) + 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) - # subprocess.run(['development/sqlacodegen/venv/bin/python', '-m', 'sqlacodegen', p_url, '--outfile', "arxiv/db/raw-autogen_models.py"], check=True) + 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) with open(p_outfile, 'r') as src: source = src.read() From a858b4341869bbfe871eb4db9aed01bedb9f4ab0 Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Wed, 13 Nov 2024 09:47:55 -0500 Subject: [PATCH 15/32] Modified sqlacodegen - readme and modifications --- development/sqlacodegen/ARXIV-README.md | 81 ++++++++++ development/sqlacodegen/README.rst | 17 ++- .../sqlacodegen/src/sqlacodegen/cli.py | 10 +- .../sqlacodegen/src/sqlacodegen/generators.py | 139 ++++++++++++++---- 4 files changed, 215 insertions(+), 32 deletions(-) create mode 100644 development/sqlacodegen/ARXIV-README.md diff --git a/development/sqlacodegen/ARXIV-README.md b/development/sqlacodegen/ARXIV-README.md new file mode 100644 index 000000000..5846e1bc0 --- /dev/null +++ b/development/sqlacodegen/ARXIV-README.md @@ -0,0 +1,81 @@ +# 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 sqlacoden allows the +merging of existing and re-generated Python code. + +For example, when sqlacodeden 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 + +## 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)" + + +## 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/README.rst b/development/sqlacodegen/README.rst index 8cd3941e3..efcaf4941 100644 --- a/development/sqlacodegen/README.rst +++ b/development/sqlacodegen/README.rst @@ -1,9 +1,14 @@ -.. image:: https://github.com/agronholm/sqlacodegen/actions/workflows/test.yml/badge.svg - :target: https://github.com/agronholm/sqlacodegen/actions/workflows/test.yml - :alt: Build Status -.. image:: https://coveralls.io/repos/github/agronholm/sqlacodegen/badge.svg?branch=master - :target: https://coveralls.io/github/agronholm/sqlacodegen?branch=master - :alt: Code Coverage + +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. diff --git a/development/sqlacodegen/src/sqlacodegen/cli.py b/development/sqlacodegen/src/sqlacodegen/cli.py index 3e948fc05..9f79e364c 100644 --- a/development/sqlacodegen/src/sqlacodegen/cli.py +++ b/development/sqlacodegen/src/sqlacodegen/cli.py @@ -82,8 +82,16 @@ def main() -> None: 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() + metadata = MetaData(naming_convention=naming_convention) tables = args.tables.split(",") if args.tables else None schemas = args.schemas.split(",") if args.schemas else [None] diff --git a/development/sqlacodegen/src/sqlacodegen/generators.py b/development/sqlacodegen/src/sqlacodegen/generators.py index 4824fdac6..605cc7322 100644 --- a/development/sqlacodegen/src/sqlacodegen/generators.py +++ b/development/sqlacodegen/src/sqlacodegen/generators.py @@ -107,6 +107,8 @@ def __init__( if invalid_options: raise ValueError("Unrecognized options: " + ", ".join(invalid_options)) + self.names_map: dict[str, str] = {} + @abstractmethod def generate(self) -> str: """ @@ -136,6 +138,7 @@ def __init__( 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): @@ -146,7 +149,7 @@ def get_class_name_override(self, table_name: str, suggested: str): return opt.get('class_name', suggested) return suggested - def get_override(self, table: Table, keyword: str, default: str | None) -> str | None: + 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) @@ -163,7 +166,6 @@ def get_override(self, table: Table, keyword: str, default: str | None) -> str | 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): @@ -174,6 +176,27 @@ 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")], @@ -394,10 +417,29 @@ def render_models(self, models: list[Model]) -> str: 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)) + 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): @@ -406,13 +448,14 @@ def render_table(self, table: Table) -> str: elif isinstance(constraint, (ForeignKeyConstraint, UniqueConstraint)): if len(constraint.columns) == 1: continue - - args.append(self.render_constraint(constraint)) + 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): - args.append(self.render_index(index)) + if index not in used_indecies: + args.append(self.render_index(index, table)) if table.schema: kwargs["schema"] = repr(table.schema) @@ -423,17 +466,18 @@ def render_table(self, table: Table) -> str: return render_callable("Table", *args, kwargs=kwargs, indentation=" ") - def render_index(self, index: Index) -> str: + 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 - return render_callable("Index", repr(index.name), *extra_args, kwargs=kwargs) + 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 + self, column: Column[Any], show_name: bool, is_table: bool = False, table: Table | None = None, ) -> str: args = [] kwargs: dict[str, Any] = {} @@ -444,7 +488,7 @@ def render_column( for c in column.foreign_keys if c.constraint and len(c.constraint.columns) == 1 - and uses_default_name(c.constraint) + # and uses_default_name(c.constraint) ] is_unique = any( isinstance(c, UniqueConstraint) @@ -468,7 +512,7 @@ def render_column( 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)) @@ -629,6 +673,8 @@ def find_free_name( 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": @@ -815,7 +861,7 @@ def generate_models(self) -> list[Model]: # Only form model classes for tables that have a primary key and are not # association tables - if not table.primary_key: + if not table.primary_key and (not self.is_table_class(table)): models_by_table_name[qualified_name] = Model(table) else: model = ModelClass(table) @@ -1132,13 +1178,13 @@ def render_models(self, models: list[Model]) -> str: 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) - if class_vars: - sections.append(class_vars) + 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: @@ -1147,6 +1193,14 @@ def render_class(self, model: ModelClass) -> str: 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)) @@ -1156,6 +1210,9 @@ def render_class(self, model: ModelClass) -> str: 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)) @@ -1163,6 +1220,7 @@ def render_class(self, model: ModelClass) -> str: 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: @@ -1171,22 +1229,23 @@ def render_class_declaration(self, model: ModelClass) -> str: ) return f"class {model.name}({parent_class_name}):" - def render_class_variables(self, model: ModelClass) -> str: + 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) - table_args = self.get_override(model.table, "table_args", 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) -> str: + 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): @@ -1197,12 +1256,21 @@ def render_table_args(self, table: Table) -> str: ): 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)) + args.append(self.render_index(index, table)) if table.schema: kwargs["schema"] = table.schema @@ -1229,10 +1297,12 @@ def render_table_args(self, table: Table) -> str: 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 = override if override else self.render_column(column, column_attr.name != column.name) + 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 @@ -1247,6 +1317,10 @@ def render_column_attribute(self, column_attr: ColumnAttribute, table: Table) -> 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}]" @@ -1344,6 +1418,20 @@ def render_join(terms: list[JoinType]) -> str: 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}" @@ -1521,9 +1609,10 @@ def render_relationship(self, relationship: RelationshipAttribute, table: Table) annotation = f"Optional[{annotation}]" rendered_field = render_callable("Relationship", *args, kwargs=kwargs) - relationship_override = self.get_override('relationship', table, {}) - if relationship.name in relationship_override: - rendered_field = relationship_override[relationship.name] + 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]: From 06684d4476fabe8b9c33b089c01058829e47c3cd Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Wed, 13 Nov 2024 14:44:14 -0500 Subject: [PATCH 16/32] Add warning for changed primary join between existing and latest. --- development/db_codegen.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/development/db_codegen.py b/development/db_codegen.py index 6f4fcae90..a732ff329 100644 --- a/development/db_codegen.py +++ b/development/db_codegen.py @@ -212,6 +212,15 @@ def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef 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( @@ -219,6 +228,7 @@ def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef ) ]) pass + updated_body.append(elem) # Remove this from the existing assignments so it's visited. del existing_assignments[target] @@ -382,6 +392,8 @@ def leave_Assign(self, original_node: cst.Assign, updated_node: cst.Assign) -> c ] ) ) + + return updated_node From b3963bbaf99429614d993ab1cc299c8753b2b4f0 Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Tue, 19 Nov 2024 13:45:37 -0500 Subject: [PATCH 17/32] Update readmes and better comments. Added the arxiv-check tables in the mix. Some code is copied over from modapi to db/orig_models.py. --- arxiv/db/arxiv-db-metadata.yaml | 103 +- arxiv/db/models.py | 1163 ++++++++--------- arxiv/db/orig_models.py | 245 ++-- development/Makefile | 17 + development/README.md | 48 +- development/__init__.py | 0 development/db_codegen.py | 72 +- development/dump-schema.sh | 4 + development/extract_class_n_table.py | 9 +- development/populate_arxiv_db.py | 108 ++ development/sqlacodegen/ARXIV-README.md | 35 + .../sqlacodegen/src/sqlacodegen/generators.py | 19 +- .../sqlacodegen/src/sqlacodegen/mysql_util.py | 21 + 13 files changed, 1075 insertions(+), 769 deletions(-) create mode 100644 development/Makefile create mode 100644 development/__init__.py create mode 100755 development/dump-schema.sh create mode 100644 development/populate_arxiv_db.py create mode 100644 development/sqlacodegen/src/sqlacodegen/mysql_util.py diff --git a/arxiv/db/arxiv-db-metadata.yaml b/arxiv/db/arxiv-db-metadata.yaml index 2842e9fe0..8a5cb0400 100644 --- a/arxiv/db/arxiv-db-metadata.yaml +++ b/arxiv/db/arxiv-db-metadata.yaml @@ -28,7 +28,6 @@ Subscription_UniversalInstitution: Subscription_UniversalInstitutionContact: class_name: MemberInstitutionContact - table_args: drop columns: sid: "mapped_column(ForeignKey('Subscription_UniversalInstitution.id', ondelete='CASCADE'), nullable=False, index=True)" relationships: @@ -68,21 +67,26 @@ arXiv_bib_updates: class_name: BibUpdate arXiv_bogus_countries: class_name: BogusCountries + arXiv_categories: class_name: Category relationships: arXiv_demographics: "" arXiv_archives: "" - arXiv_cross_control: - arXiv_cross_controls: "relationship('CrossControl', back_populates='arXiv_category')" + arXiv_cross_control: "" arXiv_categories: "" arXiv_endorsement_domains: arXiv_endorsement_domain: "relationship('EndorsementDomain', primaryjoin='Category.endorsement_domain == EndorsementDomain.endorsement_domain', back_populates='arXiv_categories')" - + additional_relationships: + - "arXiv_endorsements = relationship('Endorsement', back_populates='arXiv_categories')" + - "arXiv_endorsement_requests = relationship('EndorsementRequest', back_populates='arXiv_categories')" + # - "arXiv_cross_controls = relationship('CrossControl', back_populates='arXiv_category')" + arXiv_questionable_categories: class_name: QuestionableCategory arXiv_category_def: class_name: CategoryDef + arXiv_control_holds: class_name: ControlHold @@ -100,12 +104,11 @@ arXiv_cross_control: arXiv_datacite_dois: class_name: DataciteDois - + arXiv_dblp_authors: class_name: DBLPAuthor arXiv_dblp_document_authors: class_name: DBLPDocumentAuthor - table_args: drop arXiv_document_category: class_name: DocumentCategory @@ -114,19 +117,19 @@ arXiv_documents: class_name: Document relationships: arXiv_dblp_document_authors: "" - arXiv_paper_owners: - owners: "relationship('PaperOwner', back_populates='document')" - arXiv_cross_control: - arXiv_cross_controls: "relationship('CrossControl', back_populates='document')" + 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 - table_args: drop columns: document_id: "mapped_column(ForeignKey('arXiv_documents.document_id'), primary_key=True, server_default=FetchedValue())" password_storage: mapped_column(Integer) @@ -201,6 +204,7 @@ 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 @@ -455,6 +459,40 @@ tapir_users: arXiv_cross_controls: "relationship('CrossControl', back_populates='user')" additional_relationships: + - "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['ArXivSubmissionLocks']] = relationship('ArXivSubmissionLocks', 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')" arXiv_author_ids: @@ -499,3 +537,46 @@ arXiv_in_category: 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 + +arXiv_check_responses: + class_name: CheckResponses + table_args: drop + + diff --git a/arxiv/db/models.py b/arxiv/db/models.py index af69114b1..f42089ae6 100644 --- a/arxiv/db/models.py +++ b/arxiv/db/models.py @@ -27,6 +27,8 @@ Column, Date, DateTime, + Engine, + Enum, ForeignKey, ForeignKeyConstraint, Index, @@ -36,12 +38,11 @@ PrimaryKeyConstraint, SmallInteger, String, - Text, - Table, TIMESTAMP, - Enum, + Table, + Text, + func, text, - Engine, ) from sqlalchemy.schema import FetchedValue from sqlalchemy.orm import Mapped, mapped_column, relationship @@ -60,6 +61,7 @@ class MemberInstitution(Base): """Deprecated - superceded by membership_institutions""" __tablename__ = "Subscription_UniversalInstitution" + __table_args__ = {"mysql_charset": "utf8mb3"} resolver_URL: Mapped[Optional[str]] = mapped_column(String(255)) name: Mapped[str] = mapped_column(String(255), nullable=False, index=True) @@ -74,10 +76,11 @@ class MemberInstitutionContact(Base): """Deprecated - superceded by membership_institution_users""" __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()) + active: Mapped[Optional[int]] = mapped_column(Integer) contact_name: Mapped[Optional[str]] = mapped_column(String(255)) id: Mapped[intpk] phone: Mapped[Optional[str]] = mapped_column(String(255)) @@ -101,6 +104,7 @@ class MemberInstitutionIP(Base): class AdminLog(Base): __tablename__ = "arXiv_admin_log" + __table_args__ = {"mysql_charset": "latin1"} id: Mapped[intpk] logtime: Mapped[Optional[str]] = mapped_column(String(24)) @@ -113,26 +117,18 @@ class AdminLog(Base): 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()) - - 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") + notify: Mapped[Optional[int]] = mapped_column(Integer) class AdminMetadata(Base): __tablename__ = "arXiv_admin_metadata" - __table_args__ = (ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], ondelete="CASCADE", name="meta_doc_fk"), Index("arxiv_admin_pidv", "paper_id", "version", unique=True)) + __table_args__ = (Index("admin_metadata_pidv", "paper_id", "version"),) metadata_id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True) - document_id: Mapped[Optional[int]] = mapped_column(ForeignKey("arXiv_documents.document_id", ondelete="CASCADE"), 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]] = mapped_column(DateTime) - updated: Mapped[Optional[datetime]] = mapped_column(DateTime) + 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) @@ -154,7 +150,7 @@ class AdminMetadata(Base): modtime: Mapped[Optional[int]] = mapped_column(Integer) is_current: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) - document: Mapped["Document"] = relationship("Document", back_populates="arXiv_admin_metadata") + document = relationship("Document", primaryjoin="AdminMetadata.document_id == Document.document_id", backref="arXiv_admin_metadata") t_arXiv_admin_state = Table( @@ -172,35 +168,38 @@ class AdminMetadata(Base): class ArchiveCategory(Base): __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()) + archive_id: Mapped[str] = mapped_column(String(16), primary_key=True, nullable=False) category_id: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False) class ArchiveDef(Base): __tablename__ = "arXiv_archive_def" + __table_args__ = {"mysql_charset": "latin1"} - archive: Mapped[str] = mapped_column(String(16), primary_key=True, server_default=FetchedValue()) + archive: Mapped[str] = mapped_column(String(16), primary_key=True) name: Mapped[Optional[str]] = mapped_column(String(255)) class ArchiveGroup(Base): __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()) + archive_id: Mapped[str] = mapped_column(String(16), primary_key=True, nullable=False) + group_id: Mapped[str] = mapped_column(String(16), primary_key=True, nullable=False) class Archive(Base): __tablename__ = "arXiv_archives" - __table_args__ = (ForeignKeyConstraint(["in_group"], ["arXiv_groups.group_id"], name="0_576"),) + __table_args__ = {"mysql_charset": "latin1"} - archive_id: Mapped[str] = mapped_column(String(16), primary_key=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()) + archive_id: Mapped[str] = mapped_column(String(16), primary_key=True) + in_group: Mapped[str] = mapped_column(ForeignKey("arXiv_groups.group_id"), nullable=False, index=True) + archive_name: Mapped[str] = mapped_column(String(255), nullable=False) + start_date: Mapped[str] = mapped_column(String(4), nullable=False) + end_date: Mapped[str] = mapped_column(String(4), nullable=False) + subdivided: Mapped[int] = mapped_column(Integer, nullable=False) arXiv_categories: Mapped[List["Category"]] = relationship("Category", back_populates="arXiv_archive") @@ -210,6 +209,7 @@ class Archive(Base): class AwsConfig(Base): __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) @@ -218,9 +218,10 @@ class AwsConfig(Base): class AwsFile(Base): __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()) + type: Mapped[str] = mapped_column(String(10), nullable=False, index=True) + filename: Mapped[str] = mapped_column(String(100), primary_key=True) md5sum: Mapped[Optional[str]] = mapped_column(String(50)) content_md5sum: Mapped[Optional[str]] = mapped_column(String(50)) size: Mapped[Optional[int]] = mapped_column(Integer) @@ -232,34 +233,36 @@ 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)) class BibFeed(Base): __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()) + name: Mapped[str] = mapped_column(String(64), nullable=False) + priority: Mapped[int] = mapped_column(Integer, nullable=False) 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()) + strip_journal_ref: Mapped[int] = mapped_column(Integer, nullable=False) 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()) + enabled: Mapped[Optional[int]] = mapped_column(Integer) class BibUpdate(Base): __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()) - bib_id: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - updated: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) + document_id: Mapped[int] = mapped_column(Integer, nullable=False) + bib_id: Mapped[int] = mapped_column(Integer, nullable=False) + updated: Mapped[datetime] = mapped_column(DateTime, nullable=False) journal_ref: Mapped[Optional[str]] = mapped_column(Text) doi: Mapped[Optional[str]] = mapped_column(Text) @@ -272,9 +275,10 @@ class BibUpdate(Base): 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()) + user_id: Mapped[int] = mapped_column(Integer, primary_key=True) + country_name: Mapped[str] = mapped_column(String(255), nullable=False) t_arXiv_bogus_subject_class = Table( @@ -287,14 +291,11 @@ class BogusCountries(Base): class Category(Base): __tablename__ = "arXiv_categories" - __table_args__ = ( - ForeignKeyConstraint(["archive"], ["arXiv_archives.archive_id"], name="0_578"), - ForeignKeyConstraint(["endorsement_domain"], ["arXiv_endorsement_domains.endorsement_domain"], name="0_753"), - ) + __table_args__ = {"mysql_charset": "latin1"} # 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()) + subject_class: Mapped[str] = mapped_column(String(16), primary_key=True, nullable=False) 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)) @@ -302,13 +303,12 @@ class Category(Base): 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_cross_controls: Mapped[List["CrossControl"]] = relationship("CrossControl", back_populates="arXiv_category") + arXiv_endorsement_requests = relationship("EndorsementRequest", back_populates="arXiv_categories") # link to category arXiv_archive = relationship("Archive", primaryjoin="Category.archive == Archive.archive_id", back_populates="arXiv_categories") @@ -316,7 +316,7 @@ class Category(Base): class QuestionableCategory(Category): __tablename__ = "arXiv_questionable_categories" - __table_args__ = (ForeignKeyConstraint(["archive", "subject_class"], ["arXiv_categories.archive", "arXiv_categories.subject_class"], name="0_756"),) + __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()) @@ -324,33 +324,24 @@ class QuestionableCategory(Category): class CategoryDef(Base): __tablename__ = "arXiv_category_def" + __table_args__ = {"mysql_charset": "latin1"} 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()) - - 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") + active: Mapped[Optional[int]] = mapped_column(Integer) class ControlHold(Base): __tablename__ = "arXiv_control_holds" - __table_args__ = ( - ForeignKeyConstraint(["last_changed_by"], ["tapir_users.user_id"], name="arXiv_control_holds_ibfk_2"), - ForeignKeyConstraint(["placed_by"], ["tapir_users.user_id"], name="arXiv_control_holds_ibfk_1"), - Index("control_id", "control_id", "hold_type", unique=True), - ) + __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_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()) + control_id: Mapped[int] = mapped_column(Integer, nullable=False) + hold_type: Mapped[Literal["submission", "cross", "jref"]] = mapped_column(Enum("submission", "cross", "jref"), nullable=False, index=True) + hold_status: Mapped[Literal["held", "extended", "accepted", "rejected"]] = mapped_column(Enum("held", "extended", "accepted", "rejected"), nullable=False, index=True) + hold_reason: Mapped[str] = mapped_column(String(255), nullable=False, index=True) + hold_data: Mapped[str] = mapped_column(String(255), nullable=False) + origin: Mapped[Literal["auto", "user", "admin", "moderator"]] = mapped_column(Enum("auto", "user", "admin", "moderator"), nullable=False, index=True) 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) @@ -361,10 +352,9 @@ class ControlHold(Base): class CrossControl(Base): __tablename__ = "arXiv_cross_control" __table_args__ = ( - ForeignKeyConstraint(["archive", "subject_class"], ["arXiv_categories.archive", "arXiv_categories.subject_class"], name="arXiv_cross_control_ibfk_2"), - ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], name="arXiv_cross_control_ibfk_1"), - ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="arXiv_cross_control_ibfk_3"), + 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] @@ -380,16 +370,14 @@ class CrossControl(Base): 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: 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") + 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__ = (ForeignKeyConstraint(["metadata_id"], ["arXiv_metadata.metadata_id"], name="arXiv_datacite_dois_ibfk_1"), Index("account_paper_id", "account", "paper_id", unique=True)) + __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")) @@ -398,7 +386,7 @@ class DataciteDois(Base): created: Mapped[Optional[datetime]] = mapped_column(DateTime, server_default=FetchedValue()) updated: Mapped[Optional[datetime]] = mapped_column(DateTime, server_default=FetchedValue()) - metadata_: Mapped["Metadata"] = relationship("Metadata", back_populates="arXiv_datacite_dois") + metadata_ = relationship("Metadata", primaryjoin="DataciteDois.metadata_id == Metadata.metadata_id", backref="arXiv_datacite_dois") class DBLPAuthor(Base): @@ -416,6 +404,7 @@ class DBLPDocumentAuthor(Base): # 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 @@ -427,28 +416,24 @@ class DBLPDocumentAuthor(Base): class DocumentCategory(Base): __tablename__ = "arXiv_document_category" - __table_args__ = ( - ForeignKeyConstraint(["category"], ["arXiv_category_def.category"], name="doc_cat_cat"), - ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], ondelete="CASCADE", name="doc_cat_doc"), - ) 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) + 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["CategoryDef"] = relationship("CategoryDef", back_populates="arXiv_document_category") - document: Mapped["Document"] = relationship("Document", back_populates="arXiv_document_category") + 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" - __table_args__ = (ForeignKeyConstraint(["submitter_id"], ["tapir_users.user_id"], name="0_580"),) + __table_args__ = {"mysql_charset": "latin1"} document_id: Mapped[intpk] - paper_id: Mapped[str] = mapped_column(String(20), nullable=False, index=True, server_default=FetchedValue()) - title: Mapped[str] = mapped_column(String(255), nullable=False, index=True, server_default=FetchedValue()) + paper_id: Mapped[str] = mapped_column(String(20), nullable=False, unique=True, index=True) + title: Mapped[str] = mapped_column(String(255), nullable=False, index=True) authors: Mapped[Optional[str]] = mapped_column(Text) - submitter_email: Mapped[str] = mapped_column(String(64), nullable=False, index=True, server_default=FetchedValue()) + submitter_email: Mapped[str] = mapped_column(String(64), nullable=False, 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)) @@ -456,23 +441,12 @@ class Document(Base): # join it with user to get the user info submitter = relationship("TapirUser", primaryjoin="Document.submitter_id == TapirUser.user_id", back_populates="arXiv_documents") - owners: Mapped[List["PaperOwner"]] = relationship("PaperOwner", back_populates="document") - arXiv_cross_controls: Mapped[List["CrossControl"]] = 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") + arXiv_cross_controls = relationship("CrossControl", back_populates="document") class DBLP(Document): __tablename__ = "arXiv_dblp" - __table_args__ = (ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], name="arXiv_DBLP_cdfk1"),) 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)) @@ -487,22 +461,19 @@ class PaperPw(Document): 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), Column("email", String(255)), Column("username", String(255)) ) class EndorsementDomain(Base): __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(Integer, nullable=False, server_default=FetchedValue()) + endorsement_domain: Mapped[str] = mapped_column(String(32), primary_key=True) + endorse_all: Mapped[Literal["y", "n"]] = mapped_column(Enum("y", "n"), nullable=False) + mods_endorse_all: Mapped[Literal["y", "n"]] = mapped_column(Enum("y", "n"), nullable=False) + endorse_email: Mapped[Literal["y", "n"]] = mapped_column(Enum("y", "n"), nullable=False) + papers_to_endorse: Mapped[int] = mapped_column(Integer, nullable=False) arXiv_categories: Mapped[List["Category"]] = relationship("Category", back_populates="arXiv_endorsement_domain") @@ -510,32 +481,29 @@ class EndorsementDomain(Base): class EndorsementRequest(Base): __tablename__ = "arXiv_endorsement_requests" __table_args__ = ( - ForeignKeyConstraint(["archive", "subject_class"], ["arXiv_categories.archive", "arXiv_categories.subject_class"], name="0_723"), - ForeignKeyConstraint(["endorsee_id"], ["tapir_users.user_id"], name="0_722"), - Index("endorsee_id_2", "endorsee_id", "archive", "subject_class", unique=True), + 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, index=True, 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: Mapped["Category"] = relationship( + arXiv_categories = 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) + 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_ownership_requests: Mapped[List["OwnershipRequest"]] = relationship("OwnershipRequest", back_populates="endorsement_request") class EndorsementRequestsAudit(EndorsementRequest): __tablename__ = "arXiv_endorsement_requests_audit" - __table_args__ = (ForeignKeyConstraint(["request_id"], ["arXiv_endorsement_requests.request_id"], name="0_725"),) 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()) @@ -547,11 +515,9 @@ class EndorsementRequestsAudit(EndorsementRequest): class Endorsement(Base): __tablename__ = "arXiv_endorsements" __table_args__ = ( - ForeignKeyConstraint(["archive", "subject_class"], ["arXiv_categories.archive", "arXiv_categories.subject_class"], name="0_729"), - ForeignKeyConstraint(["endorsee_id"], ["tapir_users.user_id"], name="0_728"), - ForeignKeyConstraint(["endorser_id"], ["tapir_users.user_id"], name="0_727"), - ForeignKeyConstraint(["request_id"], ["arXiv_endorsement_requests.request_id"], name="0_730"), - Index("endorser_id_2", "endorser_id", "endorsee_id", "archive", "subject_class", unique=True), + 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] @@ -565,15 +531,14 @@ class Endorsement(Base): 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: 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") + 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" - __table_args__ = (ForeignKeyConstraint(["endorsement_id"], ["arXiv_endorsements.endorsement_id"], name="0_732"),) 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()) @@ -587,23 +552,26 @@ class EndorsementsAudit(Endorsement): class FreezeLog(Base): __tablename__ = "arXiv_freeze_log" + __table_args__ = {"mysql_charset": "latin1"} - date: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) + date: Mapped[int] = mapped_column(Integer, primary_key=True) class GroupDef(Base): __tablename__ = "arXiv_group_def" + __table_args__ = {"mysql_charset": "latin1"} - archive_group: Mapped[str] = mapped_column(String(16), primary_key=True, server_default=FetchedValue()) + archive_group: Mapped[str] = mapped_column(String(16), primary_key=True) name: Mapped[Optional[str]] = mapped_column(String(255)) class Group(Base): __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()) + group_id: Mapped[str] = mapped_column(String(16), primary_key=True) + group_name: Mapped[str] = mapped_column(String(255), nullable=False) + start_year: Mapped[str] = mapped_column(String(4), nullable=False) arXiv_archives: Mapped[List["Archive"]] = relationship("Archive", back_populates="arXiv_group") @@ -615,19 +583,15 @@ class Group(Base): 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"], name="0_583"), + 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"), - Index("archive", "archive", "subject_class", "document_id", unique=True), ) class JrefControl(Base): __tablename__ = "arXiv_jref_control" - __table_args__ = ( - ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], name="arXiv_jref_control_ibfk_1"), - ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="arXiv_jref_control_ibfk_2"), - Index("jref_ctrl_document_id", "document_id", "version", unique=True), - ) + __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()) @@ -640,49 +604,44 @@ class JrefControl(Base): 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: Mapped["Document"] = relationship("Document", back_populates="arXiv_jref_controls") - user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_jref_controls") + 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" + __table_args__ = {"mysql_charset": "latin1"} 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()) + active: Mapped[Optional[int]] = mapped_column(Integer) 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" + __table_args__ = {"mysql_charset": "latin1"} - id: Mapped[str] = mapped_column(String(255), primary_key=True, server_default=FetchedValue()) + id: Mapped[str] = mapped_column(String(255), primary_key=True) position: Mapped[Optional[int]] = mapped_column(Integer) date: Mapped[Optional[int]] = mapped_column(Integer) class Metadata(Base): __tablename__ = "arXiv_metadata" - __table_args__ = ( - ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], ondelete="CASCADE", onupdate="CASCADE", name="arXiv_metadata_fk_document_id"), - ForeignKeyConstraint(["license"], ["arXiv_licenses.name"], name="arXiv_metadata_fk_license"), - ForeignKeyConstraint(["submitter_id"], ["tapir_users.user_id"], name="arXiv_metadata_fk_submitter_id"), - Index("pidv", "paper_id", "version", unique=True), - ) + __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]] = mapped_column(DateTime) - updated: Mapped[Optional[datetime]] = mapped_column(DateTime) + 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[SOURCE_FORMAT]] = mapped_column(String(12)) + 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) @@ -701,39 +660,37 @@ class Metadata(Base): is_current: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) is_withdrawn: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) - 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_") + 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" - __table_args__ = (ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], name="arXiv_mirror_list_fk_document_id"),) mirror_list_id: Mapped[intpk] - created: Mapped[Optional[datetime]] = mapped_column(DateTime) - updated: Mapped[Optional[datetime]] = mapped_column(DateTime) + 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: Mapped["Document"] = relationship("Document", back_populates="arXiv_mirror_list") + document = relationship("Document", primaryjoin="MirrorList.document_id == Document.document_id", backref="arXiv_mirror_lists") class ModeratorApiKey(Base): __tablename__ = "arXiv_moderator_api_key" - __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="arXiv_moderator_api_key_ibfk_1"),) + __table_args__ = {"mysql_charset": "utf8mb3"} - 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_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), primary_key=True, nullable=False) + secret: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False) + valid: Mapped[int] = mapped_column(Integer, nullable=False) + issued_when: Mapped[int] = mapped_column(Integer, nullable=False) + issued_to: Mapped[str] = mapped_column(String(16), nullable=False) + remote_host: Mapped[str] = mapped_column(String(255), nullable=False) user: Mapped["TapirUser"] = relationship("TapirUser", primaryjoin="ModeratorApiKey.user_id == TapirUser.user_id", back_populates="arXiv_moderator_api_keys") @@ -749,54 +706,58 @@ class ModeratorApiKey(Base): 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"], name="0_591"), - Index("mod_user_id", "archive", "subject_class", "user_id", unique=True), + 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" + __table_args__ = {"mysql_charset": "latin1"} - t: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) + t: Mapped[int] = mapped_column(Integer, primary_key=True) sent: Mapped[Optional[int]] = mapped_column(Integer) class MonitorMailq(Base): __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()) - 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()) + t: Mapped[int] = mapped_column(Integer, primary_key=True) + main_q: Mapped[int] = mapped_column(Integer, nullable=False) + local_q: Mapped[int] = mapped_column(Integer, nullable=False) + local_host_map: Mapped[int] = mapped_column(Integer, nullable=False) + local_timeout: Mapped[int] = mapped_column(Integer, nullable=False) + local_refused: Mapped[int] = mapped_column(Integer, nullable=False) + local_in_flight: Mapped[int] = mapped_column(Integer, nullable=False) class MonitorMailsent(Base): __tablename__ = "arXiv_monitor_mailsent" + __table_args__ = {"mysql_charset": "latin1"} - t: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) + t: Mapped[int] = mapped_column(Integer, primary_key=True) 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"),) + __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) - document_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + document_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) 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()) + version: Mapped[int] = mapped_column(Integer, nullable=False) + type: Mapped[str] = mapped_column(String(255), nullable=False) 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()) + is_written: Mapped[int] = mapped_column(Integer, nullable=False) class OrcidConfig(Base): __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) @@ -819,12 +780,10 @@ class OwnershipRequest(Base): 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: 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") + 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) @@ -843,38 +802,45 @@ class OwnershipRequestsAudit(Base): class PaperOwner(Base): __tablename__ = "arXiv_paper_owners" - __table_args__ = (ForeignKeyConstraint(["added_by"], ["tapir_users.user_id"], name="0_595"), PrimaryKeyConstraint("document_id", "user_id")) + __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")) - user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.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(ForeignKey("tapir_users.user_id"), nullable=False, index=True, 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(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'")) + 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: Mapped["Document"] = relationship("Document", back_populates="owners") + 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" + __table_args__ = {"mysql_charset": "latin1"} 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()) + paper_id: Mapped[str] = mapped_column(String(16), nullable=False) + start_time: Mapped[int] = mapped_column(Integer, nullable=False) + end_time: Mapped[int] = mapped_column(Integer, nullable=False) + ip_name: Mapped[str] = mapped_column(String(16), nullable=False) class PilotFile(Base): """arXiv_pilot is deprecated""" __tablename__ = "arXiv_pilot_files" - __table_args__ = (ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], name="arXiv_pilot_files_cdfk3"),) file_id: Mapped[intpk] submission_id: Mapped[int] = mapped_column(ForeignKey("arXiv_submissions.submission_id"), nullable=False, index=True) @@ -883,13 +849,14 @@ class PilotFile(Base): description: Mapped[Optional[str]] = mapped_column(String(80)) byRef: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) - submission: Mapped["Submission"] = relationship("Submission", back_populates="arXiv_pilot_files") + submission = relationship("Submission", primaryjoin="PilotFile.submission_id == Submission.submission_id", backref="arXiv_pilot_files") class PublishLog(Base): __tablename__ = "arXiv_publish_log" + __table_args__ = {"mysql_charset": "latin1"} - date: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) + date: Mapped[int] = mapped_column(Integer, primary_key=True) t_arXiv_refresh_list = Table("arXiv_refresh_list", metadata, Column("filename", String(255)), Column("mtime", Integer, index=True)) @@ -897,12 +864,14 @@ class PublishLog(Base): class RejectSessionUsername(Base): __tablename__ = "arXiv_reject_session_usernames" + __table_args__ = {"mysql_charset": "latin1"} - username: Mapped[str] = mapped_column(String(64), primary_key=True, server_default=FetchedValue()) + username: Mapped[str] = mapped_column(String(64), primary_key=True) class SciencewisePing(Base): __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]] = mapped_column(DateTime) @@ -910,11 +879,7 @@ class SciencewisePing(Base): class ShowEmailRequest(Base): __tablename__ = "arXiv_show_email_requests" - __table_args__ = ( - ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], name="arXiv_show_email_requests_ibfk_1"), - ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="arXiv_show_email_requests_ibfk_2"), - Index("email_reqs_user_id", "user_id", "dated"), - ) + __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()) @@ -926,12 +891,13 @@ class ShowEmailRequest(Base): tracking_cookie: Mapped[str] = mapped_column(String(255), nullable=False, server_default=FetchedValue()) request_id: Mapped[intpk] - document: Mapped["Document"] = relationship("Document", back_populates="arXiv_show_email_requests") - user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_show_email_requests") + 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" + __table_args__ = {"mysql_charset": "latin1"} id: Mapped[intpk] name: Mapped[Optional[str]] = mapped_column(String(24)) @@ -951,6 +917,7 @@ class State(Base): class StatsMonthlyDownload(Base): __tablename__ = "arXiv_stats_monthly_downloads" + __table_args__ = {"mysql_charset": "latin1"} ym: Mapped[dt.date] = mapped_column(Date, primary_key=True) downloads: Mapped[int] = mapped_column(Integer, nullable=False) @@ -958,48 +925,37 @@ class StatsMonthlyDownload(Base): class StatsMonthlySubmission(Base): __tablename__ = "arXiv_stats_monthly_submissions" + __table_args__ = {"mysql_charset": "latin1"} - ym: Mapped[dt.date] = mapped_column(Date, primary_key=True, server_default=FetchedValue()) + ym: Mapped[dt.date] = mapped_column(Date, primary_key=True) num_submissions: Mapped[int] = mapped_column(Integer, nullable=False) - historical_delta: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) + historical_delta: Mapped[int] = mapped_column(Integer, nullable=False) class SubmissionAgreement(Base): __tablename__ = "arXiv_submission_agreements" + __table_args__ = {"mysql_charset": "latin1"} agreement_id: Mapped[int] = mapped_column(Integer, primary_key=True) - effective_date: Mapped[Optional[datetime]] = mapped_column(DateTime, server_default=FetchedValue()) + effective_date: Mapped[Optional[datetime]] = mapped_column(DateTime) 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" - __table_args__ = ( - ForeignKeyConstraint(["category"], ["arXiv_category_def.category"], name="arXiv_submission_category_fk_category"), - ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], ondelete="CASCADE", onupdate="CASCADE", name="arXiv_submission_category_fk_submission_id"), - ) 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: Mapped["CategoryDef"] = relationship("CategoryDef", back_populates="arXiv_submission_category") - submission: Mapped["Submission"] = relationship("Submission", back_populates="arXiv_submission_category") + 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" - __table_args__ = ( - ForeignKeyConstraint(["category"], ["arXiv_category_def.category"], name="arXiv_submission_category_proposal_fk_category"), - ForeignKeyConstraint(["proposal_comment_id"], ["arXiv_admin_log.id"], name="arXiv_submission_category_proposal_fk_prop_comment_id"), - ForeignKeyConstraint(["response_comment_id"], ["arXiv_admin_log.id"], name="arXiv_submission_category_proposal_fk_resp_comment_id"), - ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], ondelete="CASCADE", onupdate="CASCADE", name="arXiv_submission_category_proposal_fk_submission_id"), - ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="arXiv_submission_category_proposal_fk_user_id"), - ) 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) @@ -1007,24 +963,20 @@ class SubmissionCategoryProposal(Base): 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]] = mapped_column(DateTime) + 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: Mapped["CategoryDef"] = relationship("CategoryDef", back_populates="arXiv_submission_category_proposal") - proposal_comment: Mapped["AdminLog"] = relationship("AdminLog", foreign_keys=[proposal_comment_id], back_populates="arXiv_submission_category_proposal") - response_comment: Mapped["AdminLog"] = relationship("AdminLog", foreign_keys=[response_comment_id], back_populates="arXiv_submission_category_proposal_") - submission: Mapped["Submission"] = relationship("Submission", back_populates="arXiv_submission_category_proposal") - user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_submission_category_proposal") + 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__ = ( - ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], name="arXiv_submission_control_ibfk_1"), - ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="arXiv_submission_control_ibfk_2"), - Index("sub_ctrl_document_id", "document_id", "version", unique=True), - ) + __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()) @@ -1037,17 +989,13 @@ class SubmissionControl(Base): 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: Mapped["Document"] = relationship("Document", back_populates="arXiv_submission_control") - user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_submission_control") + 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__ = ( - ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], ondelete="CASCADE", name="arXiv_submission_flag_ibfk_2"), - ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], ondelete="CASCADE", name="arXiv_submission_flag_ibfk_1"), - Index("uniq_one_flag_per_mod", "submission_id", "user_id", unique=True), - ) + __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()) @@ -1055,17 +1003,12 @@ class SubmissionFlag(Base): flag: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) updated: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) - submission: Mapped["Submission"] = relationship("Submission", back_populates="arXiv_submission_flag") - user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_submission_flag") + 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" - __table_args__ = ( - ForeignKeyConstraint(["comment_id"], ["arXiv_admin_log.id"], name="arXiv_submission_hold_reason_ibfk_3"), - ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], ondelete="CASCADE", name="arXiv_submission_hold_reason_ibfk_1"), - ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], ondelete="CASCADE", name="arXiv_submission_hold_reason_ibfk_2"), - ) 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) @@ -1074,66 +1017,51 @@ class SubmissionHoldReason(Base): type: Mapped[Optional[str]] = mapped_column(String(30)) 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") + 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__ = ( - ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], ondelete="CASCADE", name="arXiv_submission_near_duplicates_ibfk_1"), - Index("match", "submission_id", "matching_id", unique=True), - ) + __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: Mapped["Submission"] = relationship("Submission", back_populates="arXiv_submission_near_duplicates") + submission = relationship("Submission", primaryjoin="SubmissionNearDuplicate.submission_id == Submission.submission_id", backref="arXiv_submission_near_duplicates") class SubmissionQaReport(Base): __tablename__ = "arXiv_submission_qa_reports" - __table_args__ = (ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], name="arXiv_submission_qa_reports_ibfk_1"),) 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(Integer, nullable=False, server_default=FetchedValue()) - report: Mapped[dict] = mapped_column(JSON, nullable=False) + 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: Mapped["Submission"] = relationship("Submission", back_populates="arXiv_submission_qa_reports") + submission = relationship("Submission", primaryjoin="SubmissionQaReport.submission_id == Submission.submission_id", backref="arXiv_submission_qa_reports") class SubmissionViewFlag(Base): __tablename__ = "arXiv_submission_view_flag" - __table_args__ = ( - ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], ondelete="CASCADE", name="arXiv_submission_view_flag_ibfk_1"), - ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], ondelete="CASCADE", name="arXiv_submission_view_flag_ibfk_2"), - ) 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]] = mapped_column(DateTime) + updated: Mapped[Optional[datetime]] - submission: Mapped["Submission"] = relationship("Submission", back_populates="arXiv_submission_view_flag") - user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_submission_view_flag") + 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" - __table_args__ = ( - ForeignKeyConstraint(["agreement_id"], ["arXiv_submission_agreements.agreement_id"], name="agreement_fk"), - ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], ondelete="CASCADE", onupdate="CASCADE", name="arXiv_submissions_fk_document_id"), - ForeignKeyConstraint(["license"], ["arXiv_licenses.name"], onupdate="CASCADE", name="arXiv_submissions_fk_license"), - ForeignKeyConstraint(["submitter_id"], ["tapir_users.user_id"], ondelete="CASCADE", onupdate="CASCADE", name="arXiv_submissions_fk_submitter_id"), - ForeignKeyConstraint(["sword_id"], ["arXiv_tracking.sword_id"], name="arXiv_submissions_fk_sword_id"), - ) submission_id: Mapped[intpk] document_id: Mapped[Optional[int]] = mapped_column(ForeignKey("arXiv_documents.document_id", ondelete="CASCADE", onupdate="CASCADE"), index=True) @@ -1147,13 +1075,13 @@ class Submission(Base): 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]] = mapped_column(DateTime) - updated: Mapped[Optional[datetime]] = mapped_column(DateTime) + 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]] = mapped_column(DateTime) - release_time: Mapped[Optional[datetime]] = mapped_column(DateTime) + 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)) @@ -1162,7 +1090,7 @@ 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]] = mapped_column(String(255)) + 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)) @@ -1182,43 +1110,27 @@ 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[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") - data_version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) - metadata_version: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) - data_needed: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) - data_version_queued: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'0'")) - metadata_version_queued: Mapped[int] = mapped_column(Integer, 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_check_results: Mapped[List["ArXivCheckResults"]] = relationship("ArXivCheckResults", back_populates="submission") - 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_locks: Mapped[List["ArXivSubmissionLocks"]] = relationship("ArXivSubmissionLocks", 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") + 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") - # arXiv_check_results: Mapped[List["ArXivCheckResults"]] = relationship("ArXivCheckResults", back_populates="submission") - # arXiv_submission_locks: Mapped[List["ArXivSubmissionLocks"]] = relationship("ArXivSubmissionLocks", back_populates="submission") + # to arxiv check + arXiv_check_results: Mapped[List["CheckResults"]] = relationship("CheckResults", back_populates="submission") + # to submission locks + arXiv_submission_locks: Mapped[List["ArXivSubmissionLocks"]] = relationship("ArXivSubmissionLocks", back_populates="submission") class PilotDataset(Submission): """arXiv_pilot is deprecated""" __tablename__ = "arXiv_pilot_datasets" - __table_args__ = (ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], name="arXiv_pilot_datasets_cdfk3"),) submission_id: Mapped[int] = mapped_column(ForeignKey("arXiv_submissions.submission_id"), primary_key=True) - numfiles: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) + 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()) @@ -1229,14 +1141,13 @@ class PilotDataset(Submission): class SubmissionAbsClassifierDatum(Base): __tablename__ = "arXiv_submission_abs_classifier_data" - __table_args__ = (ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], ondelete="CASCADE", name="arXiv_submission_abs_classifier_data_ibfk_1"),) 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, server_default=text("'0'")) + 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) @@ -1247,18 +1158,18 @@ class SubmissionAbsClassifierDatum(Base): class SubmissionClassifierDatum(Base): __tablename__ = "arXiv_submission_classifier_data" - __table_args__ = (ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], ondelete="CASCADE", name="arXiv_submission_classifier_data_ibfk_1"),) 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, server_default=text("'0'")) + is_oversize: Mapped[Optional[int]] = mapped_column(Integer) class SubmitterFlag(Base): __tablename__ = "arXiv_submitter_flags" + __table_args__ = {"mysql_charset": "latin1"} flag_id: Mapped[intpk] comment: Mapped[Optional[str]] = mapped_column(String(255)) @@ -1267,16 +1178,18 @@ class SubmitterFlag(Base): class SuspectEmail(Base): __tablename__ = "arXiv_suspect_emails" + __table_args__ = {"mysql_charset": "latin1"} 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()) + updated: Mapped[datetime] = mapped_column(DateTime, nullable=False) class Title(Base): __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) @@ -1286,32 +1199,32 @@ class Title(Base): class TopPaper(Base): __tablename__ = "arXiv_top_papers" - __table_args__ = (ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], name="arXiv_top_papers_ibfk_1"),) - from_week: Mapped[dt.date] = mapped_column(Date, primary_key=True, nullable=False, server_default=FetchedValue()) + 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(Integer, 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: Mapped["Document"] = relationship("Document", primaryjoin="TopPaper.document_id == Document.document_id", back_populates="arXiv_top_papers") + document = relationship("Document", primaryjoin="TopPaper.document_id == Document.document_id", backref="arXiv_top_papers") class TrackbackPing(Base): __tablename__ = "arXiv_trackback_pings" + __table_args__ = {"mysql_charset": "latin1"} 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()) + title: Mapped[str] = mapped_column(String(255), nullable=False) + excerpt: Mapped[str] = mapped_column(String(255), nullable=False) + url: Mapped[str] = mapped_column(String(255), nullable=False, index=True) + blog_name: Mapped[str] = mapped_column(String(255), nullable=False) + remote_host: Mapped[str] = mapped_column(String(255), nullable=False) + remote_addr: Mapped[str] = mapped_column(String(16), nullable=False) + posted_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True) + is_stale: Mapped[int] = mapped_column(Integer, nullable=False) + approved_by_user: Mapped[int] = mapped_column(Integer, nullable=False) + approved_time: Mapped[int] = mapped_column(Integer, nullable=False) status: Mapped[Literal["pending", "pending2", "accepted", "rejected", "spam"]] = mapped_column( Enum("pending", "pending2", "accepted", "rejected", "spam"), nullable=False, index=True, server_default=FetchedValue() ) @@ -1351,22 +1264,22 @@ def hashed_document_id(self) -> str: class TrackbackSite(Base): __tablename__ = "arXiv_trackback_sites" + __table_args__ = {"mysql_charset": "latin1"} - pattern: Mapped[str] = mapped_column(String(255), nullable=False, index=True, server_default=FetchedValue()) + pattern: Mapped[str] = mapped_column(String(255), nullable=False, index=True) 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" + __table_args__ = {"mysql_charset": "latin1"} tracking_id: Mapped[intpk] - sword_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=FetchedValue()) + sword_id: Mapped[int] = mapped_column(Integer, nullable=False, unique=True, index=True) 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") + timestamp: Mapped[datetime] = mapped_column(DateTime, nullable=False) class Updates(Base): @@ -1379,12 +1292,11 @@ class Updates(Base): 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[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})" @@ -1403,7 +1315,6 @@ def __repr__(self) -> str: class Version(Base): __tablename__ = "arXiv_versions" - __table_args__ = (ForeignKeyConstraint(["document_id"], ["arXiv_documents.document_id"], name="arXiv_versions_ibfk_1"),) 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()) @@ -1412,24 +1323,24 @@ class Version(Base): 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: Mapped["Document"] = relationship("Document", back_populates="arXiv_versions") + 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"], name="arXiv_versions_checksum_ibfk_1"),) + __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[bytes]] = mapped_column(BINARY(16), index=True) + 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[bytes]] = mapped_column(BINARY(16), index=True) + src_md5sum: Mapped[Optional[str]] = mapped_column(BINARY(16), index=True) -t_arXiv_white_email = Table("arXiv_white_email", metadata, Column("pattern", String(64), index=True)) +t_arXiv_white_email = Table("arXiv_white_email", metadata, Column("pattern", String(64), unique=True, index=True)) t_arXiv_xml_notifications = Table( @@ -1437,14 +1348,15 @@ class VersionsChecksum(Version): 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("queued_date", Integer, nullable=False), + Column("sent_date", Integer, nullable=False), Column("status", Enum("unsent", "sent", "failed"), index=True), ) class DbixClassSchemaVersion(Base): __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) @@ -1453,34 +1365,35 @@ class DbixClassSchemaVersion(Base): 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("user_id", Integer, nullable=False), + Column("country", String(2), nullable=False), + Column("affiliation", String(255), nullable=False), + Column("url", String(255), nullable=False), 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("original_subject_classes", String(255), nullable=False), 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()), + Column("flag_group_math", Integer, nullable=False), + Column("flag_group_cs", Integer, nullable=False), + Column("flag_group_nlin", Integer, nullable=False), + Column("flag_proxy", Integer, nullable=False), + Column("flag_journal", Integer, nullable=False), + Column("flag_xml", Integer, nullable=False), + Column("dirty", Integer, nullable=False), + Column("flag_group_test", Integer, nullable=False), + Column("flag_suspect", Integer, nullable=False), + Column("flag_group_q_bio", Integer, nullable=False), + Column("flag_no_upload", Integer, nullable=False), + Column("flag_no_endorse", Integer, nullable=False), + Column("veto_status", Enum("ok", "no-endorse", "no-upload")), ) class Session(Base): __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) @@ -1501,17 +1414,12 @@ class TapirAddress(Base): 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: 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") + 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" - __table_args__ = ( - ForeignKeyConstraint(["admin_user"], ["tapir_users.user_id"], name="0_554"), - ForeignKeyConstraint(["affected_user"], ["tapir_users.user_id"], name="0_555"), - ForeignKeyConstraint(["session_id"], ["tapir_sessions.session_id"], name="0_553"), - ) 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) @@ -1521,30 +1429,28 @@ class TapirAdminAudit(Base): 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)) + 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: 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") + 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" + __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") + digraph: Mapped[str] = mapped_column(String(2), primary_key=True) + country_name: Mapped[str] = mapped_column(String(255), nullable=False) + rank: Mapped[int] = mapped_column(Integer, nullable=False) class TapirEmailChangeToken(Base): __tablename__ = "tapir_email_change_tokens" - __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_535"),) - user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), primary_key=True, nullable=False, server_default=FetchedValue()) + 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()) @@ -1558,7 +1464,7 @@ class TapirEmailChangeToken(Base): consumed_when: Mapped[Optional[int]] = mapped_column(Integer) consumed_from: Mapped[Optional[str]] = mapped_column(String(16)) - user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="tapir_email_change_tokens") + user = relationship("TapirUser", primaryjoin="TapirEmailChangeToken.user_id == TapirUser.user_id", back_populates="tapir_email_change_tokens") t_tapir_email_change_tokens_used = Table( @@ -1575,35 +1481,30 @@ class TapirEmailChangeToken(Base): class TapirEmailHeader(Base): __tablename__ = "tapir_email_headers" - __table_args__ = (ForeignKeyConstraint(["template_id"], ["tapir_email_templates.template_id"], name="0_563"),) 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: Mapped["TapirEmailTemplate"] = relationship("TapirEmailTemplate", back_populates="tapir_email_headers") + template = relationship("TapirEmailTemplate", primaryjoin="TapirEmailHeader.template_id == TapirEmailTemplate.template_id", backref="tapir_email_headers") class TapirEmailLog(Base): __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()) + sent_date: Mapped[int] = mapped_column(Integer, nullable=False) 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()) + template_id: Mapped[int] = mapped_column(Integer, nullable=False) class TapirEmailMailing(Base): __tablename__ = "tapir_email_mailings" - __table_args__ = ( - ForeignKeyConstraint(["created_by"], ["tapir_users.user_id"], name="0_565"), - ForeignKeyConstraint(["sent_by"], ["tapir_users.user_id"], name="0_566"), - ForeignKeyConstraint(["template_id"], ["tapir_email_templates.template_id"], name="0_567"), - ) mailing_id: Mapped[intpk] template_id: Mapped[Optional[int]] = mapped_column(ForeignKey("tapir_email_templates.template_id"), index=True) @@ -1615,18 +1516,14 @@ class TapirEmailMailing(Base): mailing_name: Mapped[Optional[str]] = mapped_column(String(255)) comment: Mapped[Optional[str]] = mapped_column(Text) - 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") + 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__ = ( - ForeignKeyConstraint(["created_by"], ["tapir_users.user_id"], name="0_560"), - ForeignKeyConstraint(["updated_by"], ["tapir_users.user_id"], name="0_561"), - Index("short_name", "short_name", "lang", unique=True), - ) + __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()) @@ -1640,15 +1537,12 @@ class TapirEmailTemplate(Base): 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: 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") + 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" - __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_530"),) 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()) @@ -1659,7 +1553,7 @@ 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: Mapped["TapirUser"] = relationship("TapirUser", back_populates="tapir_email_tokens") + user = relationship("TapirUser", primaryjoin="TapirEmailToken.user_id == TapirUser.user_id", back_populates="tapir_email_tokens") t_tapir_email_tokens_used = Table( @@ -1677,31 +1571,32 @@ class TapirEmailToken(Base): t_tapir_error_log = Table( "tapir_error_log", metadata, - Column("error_date", Integer, nullable=False, index=True, server_default=FetchedValue()), + Column("error_date", Integer, nullable=False, index=True), 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()), + Column("ip_addr", String(16), nullable=False, index=True), + Column("remote_host", String(255), nullable=False), + Column("tracking_cookie", String(32), nullable=False, index=True), + Column("message", String(32), nullable=False, index=True), + Column("url", String(255), nullable=False), + Column("error_url", String(255), nullable=False), ) class TapirIntegerVariable(Base): __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()) + variable_id: Mapped[str] = mapped_column(String(32), primary_key=True) + value: Mapped[int] = mapped_column(Integer, nullable=False) class TapirNickname(Base): __tablename__ = "tapir_nicknames" - __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_570"), Index("user_id", "user_id", "user_seq", unique=True)) + __table_args__ = (Index("user_id", "user_id", "user_seq"),) nick_id: Mapped[intpk] - nickname: Mapped[str] = mapped_column(String(20), nullable=False, index=True, server_default=FetchedValue()) + 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'")) @@ -1709,7 +1604,7 @@ class TapirNickname(Base): 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: Mapped["TapirUser"] = relationship("TapirUser", back_populates="tapir_nicknames") + user = relationship("TapirUser", primaryjoin="TapirNickname.user_id == TapirUser.user_id", back_populates="tapir_nicknames") class TapirNicknamesAudit(Base): @@ -1725,21 +1620,20 @@ class TapirNicknamesAudit(Base): 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()), + Column("log_date", Integer, nullable=False), + Column("ip_addr", String(16), nullable=False), + Column("remote_host", String(255), nullable=False), + Column("tracking_cookie", String(255), nullable=False), + Column("session_data", String(255), nullable=False), + Column("user_agent", String(255), nullable=False), ) -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), Column("entry", Text)) class TapirPermanentToken(Base): __tablename__ = "tapir_permanent_tokens" - __table_args__ = (ForeignKeyConstraint(["session_id"], ["tapir_sessions.session_id"], name="0_541"), ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_540")) 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()) @@ -1749,8 +1643,8 @@ class TapirPermanentToken(Base): 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: Mapped["TapirSession"] = relationship("TapirSession", back_populates="tapir_permanent_tokens") - user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="tapir_permanent_tokens") + 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( @@ -1767,25 +1661,25 @@ class TapirPermanentToken(Base): class TapirPhone(Base): __tablename__ = "tapir_phone" - __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_520"),) 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: Mapped["TapirUser"] = relationship("TapirUser", back_populates="tapir_phone") + user = relationship("TapirUser", primaryjoin="TapirPhone.user_id == TapirUser.user_id", back_populates="tapir_phone") class TapirPolicyClass(Base): __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()) + name: Mapped[str] = mapped_column(String(64), nullable=False) 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()) + password_storage: Mapped[int] = mapped_column(Integer, nullable=False) + recovery_policy: Mapped[int] = mapped_column(Integer, nullable=False) + permanent_login: Mapped[int] = mapped_column(Integer, nullable=False) tapir_users: Mapped[List["TapirUser"]] = relationship("TapirUser", back_populates="tapir_policy_classes") @@ -1801,17 +1695,17 @@ class TapirPolicyClass(Base): class TapirPresession(Base): __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()) - 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()) + ip_num: Mapped[str] = mapped_column(String(16), nullable=False) + remote_host: Mapped[str] = mapped_column(String(255), nullable=False) + tracking_cookie: Mapped[str] = mapped_column(String(255), nullable=False) + created_at: Mapped[int] = mapped_column(Integer, nullable=False) class TapirRecoveryToken(Base): __tablename__ = "tapir_recovery_tokens" - __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_546"),) 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()) @@ -1822,12 +1716,11 @@ 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: Mapped["TapirUser"] = relationship("TapirUser", back_populates="tapir_recovery_tokens") + user = relationship("TapirUser", primaryjoin="TapirRecoveryToken.user_id == TapirUser.user_id", back_populates="tapir_recovery_tokens") class TapirRecoveryTokensUsed(Base): __tablename__ = "tapir_recovery_tokens_used" - __table_args__ = (ForeignKeyConstraint(["session_id"], ["tapir_sessions.session_id"], name="0_549"), ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_548")) 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()) @@ -1836,42 +1729,36 @@ class TapirRecoveryTokensUsed(Base): 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: Mapped["TapirSession"] = relationship("TapirSession", back_populates="tapir_recovery_tokens_used") - user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="tapir_recovery_tokens_used") + 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("presession_id", ForeignKey("tapir_presessions.presession_id"), nullable=False, index=True), Column("name", String(255)), Column("value", Text, nullable=False), - Column("seq", Integer, nullable=False, server_default=FetchedValue()), + Column("seq", Integer, nullable=False), ) class TapirSession(Base): __tablename__ = "tapir_sessions" - __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_525"),) - session_id: Mapped[int] = mapped_column(Integer, primary_key=True) + 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: 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" - __table_args__ = (ForeignKeyConstraint(["session_id"], ["tapir_sessions.session_id"], name="0_527"),) - session_id: Mapped[int] = mapped_column(ForeignKey("tapir_sessions.session_id"), primary_key=True, server_default=text("'0'")) + 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()) @@ -1881,23 +1768,25 @@ class TapirSessionsAudit(Base): class TapirStringVariable(Base): __tablename__ = "tapir_string_variables" + __table_args__ = {"mysql_charset": "latin1"} - variable_id: Mapped[str] = mapped_column(String(32), primary_key=True, server_default=FetchedValue()) + variable_id: Mapped[str] = mapped_column(String(32), primary_key=True) value: Mapped[str] = mapped_column(Text, nullable=False) class TapirString(Base): __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()) - language: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False, server_default=FetchedValue()) + name: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False) + module: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False) + language: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False) 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"),) + __table_args__ = {"mysql_charset": "latin1"} user_id: Mapped[intpk] first_name: Mapped[Optional[str]] = mapped_column(String(50), index=True) @@ -1905,7 +1794,7 @@ 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, index=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'")) @@ -1930,45 +1819,44 @@ class TapirUser(Base): 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") + 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["ArXivSubmissionLocks"]] = relationship("ArXivSubmissionLocks", back_populates="user") - arXiv_submission_view_flag: Mapped[List["SubmissionViewFlag"]] = relationship("SubmissionViewFlag", back_populates="user") - arXiv_check_results: Mapped[List["ArXivCheckResults"]] = relationship("ArXivCheckResults", back_populates="user") - arXiv_check_responses: Mapped[List["ArXivCheckResponses"]] = relationship("ArXivCheckResponses", back_populates="user") - owned_papers: Mapped[List["PaperOwner"]] = relationship("PaperOwner", foreign_keys="[PaperOwner.user_id]", back_populates="owner") + 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" - __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="arXiv_author_ids_ibfk_1"),) 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) @@ -1977,16 +1865,13 @@ class AuthorIds(Base): class Demographic(Base): __tablename__ = "arXiv_demographics" - __table_args__ = ( - ForeignKeyConstraint(["archive", "subject_class"], ["arXiv_categories.archive", "arXiv_categories.subject_class"], name="0_588"), - ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_587"), - ) + __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(Integer, index=True) + 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()) @@ -2007,18 +1892,11 @@ class Demographic(Base): 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'")) - arXiv_category: Mapped["Category"] = relationship( - "Category", primaryjoin="and_(Demographic.archive == Category.archive, Demographic.subject_class == Category.subject_class)", backref="category_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] - # 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"), @@ -2030,10 +1908,14 @@ def groups(self) -> List[str]: ("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" - __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="arXiv_orcid_ids_ibfk_1"),) 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) @@ -2043,17 +1925,15 @@ class OrcidIds(Base): class QueueView(Base): __tablename__ = "arXiv_queue_view" - __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], ondelete="CASCADE", name="arXiv_queue_view_ibfk_1"),) 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) + 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" - __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_606"),) 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()) @@ -2061,7 +1941,6 @@ class SuspiciousName(Base): class SwordLicense(Base): __tablename__ = "arXiv_sword_licenses" - __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="user_id_fk"),) user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), primary_key=True) license: Mapped[Optional[str]] = mapped_column(String(127)) @@ -2070,23 +1949,21 @@ class SwordLicense(Base): class TapirDemographic(Base): __tablename__ = "tapir_demographics" - __table_args__ = (ForeignKeyConstraint(["country"], ["tapir_countries.digraph"], name="0_518"), ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_517")) 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[dt.date]] = mapped_column(Date, index=True) + 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: Mapped["TapirCountry"] = relationship("TapirCountry", primaryjoin="TapirDemographic.country == TapirCountry.digraph", backref="tapir_demographics") + tapir_country = relationship("TapirCountry", primaryjoin="TapirDemographic.country == TapirCountry.digraph", backref="tapir_demographics") class TapirUsersHot(Base): __tablename__ = "tapir_users_hot" - __table_args__ = (ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="0_514"),) 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()) @@ -2104,107 +1981,6 @@ class TapirUsersPassword(Base): user = relationship("TapirUser") -class ArXivCheckResults(Base): - __tablename__ = "arXiv_check_results" - __table_args__ = ( - ForeignKeyConstraint(["check_id"], ["arXiv_checks.check_id"], name="check_results_checks_fk"), - ForeignKeyConstraint(["submission_id"], ["arXiv_submissions.submission_id"], name="check_results_sub_fk"), - ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="check_results_user_fk"), - ) - - 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=text("CURRENT_TIMESTAMP")) - message: Mapped[Optional[str]] = mapped_column(String(40)) - data: Mapped[Optional[str]] = mapped_column(String(2000)) - - check: Mapped["ArXivChecks"] = relationship("ArXivChecks", back_populates="arXiv_check_results") - submission: Mapped["Submission"] = relationship("Submission", back_populates="arXiv_check_results") - user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_check_results") - arXiv_check_responses: Mapped[List["ArXivCheckResponses"]] = relationship("ArXivCheckResponses", back_populates="check_result") - - -class ArXivCheckResponses(Base): - __tablename__ = "arXiv_check_responses" - __table_args__ = ( - ForeignKeyConstraint(["check_result_id"], ["arXiv_check_results.check_result_id"], name="check_responses_results_fk"), - ForeignKeyConstraint(["user_id"], ["tapir_users.user_id"], name="check_responses_user_fk"), - ) - - 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=text("CURRENT_TIMESTAMP")) - message: Mapped[Optional[str]] = mapped_column(String(200)) - - check_result: Mapped["ArXivCheckResults"] = relationship("ArXivCheckResults", back_populates="arXiv_check_responses") - user: Mapped["TapirUser"] = relationship("TapirUser", back_populates="arXiv_check_responses") - - -class ArXivCheckResultViews(Base): - __tablename__ = "arXiv_check_result_views" - - 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)) - - arXiv_checks: Mapped[List["ArXivChecks"]] = relationship("ArXivChecks", back_populates="check_result_view") - - -class ArXivCheckRoles(Base): - __tablename__ = "arXiv_check_roles" - - 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)) - - arXiv_checks: Mapped[List["ArXivChecks"]] = relationship("ArXivChecks", back_populates="check_role") - - -class ArXivCheckTargets(Base): - __tablename__ = "arXiv_check_targets" - - 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)) - - arXiv_checks: Mapped[List["ArXivChecks"]] = relationship("ArXivChecks", back_populates="check_target") - - -class ArXivChecks(Base): - __tablename__ = "arXiv_checks" - __table_args__ = ( - ForeignKeyConstraint(["check_result_view_id"], ["arXiv_check_result_views.check_result_view_id"], name="checks_result_views_fk"), - ForeignKeyConstraint(["check_role_id"], ["arXiv_check_roles.check_role_id"], name="checks_roles_fk"), - ForeignKeyConstraint(["check_target_id"], ["arXiv_check_targets.check_target_id"], name="checks_content_fk"), - ) - - 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) - check_role_id: Mapped[int] = mapped_column(ForeignKey("arXiv_check_roles.check_role_id"), nullable=False, index=True) - 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) - 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(Integer, 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'")) - description: Mapped[Optional[str]] = mapped_column(String(200)) - - check_result_view: Mapped["ArXivCheckResultViews"] = relationship("ArXivCheckResultViews", back_populates="arXiv_checks") - check_role: Mapped["ArXivCheckRoles"] = relationship("ArXivCheckRoles", back_populates="arXiv_checks") - check_target: Mapped["ArXivCheckTargets"] = relationship("ArXivCheckTargets", back_populates="arXiv_checks") - arXiv_check_results: Mapped[List["ArXivCheckResults"]] = relationship("ArXivCheckResults", back_populates="check") - - class ArXivSubmissionLocks(Base): __tablename__ = "arXiv_submission_locks" __table_args__ = ( @@ -2214,8 +1990,8 @@ class ArXivSubmissionLocks(Base): ) 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) + 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) @@ -2228,6 +2004,7 @@ class ArXivSubmissionLocks(Base): # Student-lead membership dashboard - supercedes "Subscription_UniversalInstitution" class MembershipInstitutions(Base): __tablename__ = "membership_institutions" + __table_args__ = {"mysql_charset": "utf8mb4"} sid: Mapped[int] = mapped_column(Integer, primary_key=True) is_active: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("'1'")) @@ -2245,6 +2022,7 @@ class MembershipInstitutions(Base): # Student-lead membership dashboard class MembershipUsers(Base): __tablename__ = "membership_users" + __table_args__ = {"mysql_charset": "utf8mb4"} id: Mapped[int] = mapped_column(Integer, primary_key=True) sid: Mapped[int] = mapped_column(Integer, nullable=False) @@ -2253,8 +2031,9 @@ class MembershipUsers(Base): class DBLaTeXMLDocuments(LaTeXMLBase): __tablename__ = "arXiv_latexml_doc" + __table_args__ = {"mysql_charset": "utf8mb4"} - paper_id: Mapped[str] = mapped_column(String(20), primary_key=True) + paper_id: Mapped[str] = mapped_column(String(20), primary_key=True, nullable=False) document_version: Mapped[intpk] # conversion_status codes: # - 0 = in progress @@ -2265,11 +2044,12 @@ class DBLaTeXMLDocuments(LaTeXMLBase): 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)) + publish_dt: Mapped[Optional[datetime]] = mapped_column(DateTime) class DBLaTeXMLSubmissions(LaTeXMLBase): __tablename__ = "arXiv_latexml_sub" + __table_args__ = {"mysql_charset": "utf8mb4"} submission_id: Mapped[intpk] # conversion_status codes: @@ -2279,12 +2059,13 @@ class DBLaTeXMLSubmissions(LaTeXMLBase): 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]] + conversion_start_time: Mapped[Optional[int]] = mapped_column(Integer) + conversion_end_time: Mapped[Optional[int]] = mapped_column(Integer) class DBLaTeXMLFeedback(LaTeXMLBase): __tablename__ = "feedback" + __table_args__ = {"mysql_charset": "utf8mb4"} id: Mapped[str] = mapped_column(String(40), primary_key=True) canonical_url: Mapped[Optional[str]] = mapped_column(String(255)) @@ -2298,6 +2079,128 @@ class DBLaTeXMLFeedback(LaTeXMLBase): 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": "utf8mb4"} + + 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": "utf8mb4"} + + 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": "utf8mb4"} + + 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": "utf8mb4"} + + 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") + + 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, primary_key=True) + submission_id = Column(ForeignKey("arXiv_submissions.submission_id"), nullable=False, index=True) + data_version = Column(Integer, nullable=False, server_default=text("'0'")) + metadata_version = Column(Integer, 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, 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, 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, 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, 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={ diff --git a/arxiv/db/orig_models.py b/arxiv/db/orig_models.py index 06de52349..395d1732c 100644 --- a/arxiv/db/orig_models.py +++ b/arxiv/db/orig_models.py @@ -5,7 +5,11 @@ These models represent the entire arXiv DB and the LaTeXML DB. -This file was generated by using arxiv/development/db_codegen.py along with arxiv/development/sqlacodegen +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. @@ -27,6 +31,8 @@ Column, Date, DateTime, + Engine, + Enum, ForeignKey, ForeignKeyConstraint, Index, @@ -36,12 +42,11 @@ PrimaryKeyConstraint, SmallInteger, String, - Text, - Table, TIMESTAMP, - Enum, + Table, + Text, + func, text, - Engine, ) from sqlalchemy.schema import FetchedValue from sqlalchemy.orm import ( @@ -1158,8 +1163,10 @@ class Submission(Base): 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') - # arXiv_check_results: Mapped[List["ArXivCheckResults"]] = relationship("ArXivCheckResults", back_populates="submission") - # arXiv_submission_locks: Mapped[List["ArXivSubmissionLocks"]] = relationship("ArXivSubmissionLocks", back_populates="submission") + # to arxiv check + arXiv_check_results: Mapped[List["CheckResults"]] = relationship("CheckResults", back_populates="submission") + # to submission locks + arXiv_submission_locks: Mapped[List["ArXivSubmissionLocks"]] = relationship("ArXivSubmissionLocks", back_populates="submission") class PilotDataset(Submission): @@ -1917,8 +1924,8 @@ class TapirUser(Base): arXiv_submission_hold_reason = relationship('SubmissionHoldReason', back_populates='user') arXiv_submission_locks: Mapped[List["ArXivSubmissionLocks"]] = relationship("ArXivSubmissionLocks", back_populates="user") arXiv_submission_view_flag = relationship('SubmissionViewFlag', back_populates='user') - arXiv_check_results: Mapped[List["ArXivCheckResults"]] = relationship("ArXivCheckResults", back_populates="user") - arXiv_check_responses: Mapped[List["ArXivCheckResponses"]] = relationship("ArXivCheckResponses", 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') @@ -2054,108 +2061,6 @@ class TapirUsersPassword(Base): user = relationship('TapirUser') -class ArXivCheckResults(Base): - __tablename__ = 'arXiv_check_results' - __table_args__ = ( - ForeignKeyConstraint(['check_id'], ['arXiv_checks.check_id'], name='check_results_checks_fk'), - ForeignKeyConstraint(['submission_id'], ['arXiv_submissions.submission_id'], name='check_results_sub_fk'), - ForeignKeyConstraint(['user_id'], ['tapir_users.user_id'], name='check_results_user_fk') - ) - - check_result_id: Mapped[int] = mapped_column(Integer, primary_key=True) - submission_id: Mapped[int] = mapped_column(Integer, 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(Integer, nullable=False, index=True) - user_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) - ok: Mapped[int] = mapped_column(Integer, nullable=False) - created: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=text('CURRENT_TIMESTAMP')) - message: Mapped[Optional[str]] = mapped_column(String(40)) - data: Mapped[Optional[str]] = mapped_column(String(2000)) - - check: Mapped['ArXivChecks'] = relationship('ArXivChecks', back_populates='arXiv_check_results') - submission: Mapped['Submission'] = relationship('Submission', back_populates='arXiv_check_results') - user: Mapped['TapirUser'] = relationship('TapirUser', back_populates='arXiv_check_results') - arXiv_check_responses: Mapped[List['ArXivCheckResponses']] = relationship('ArXivCheckResponses', back_populates='check_result') - - -class ArXivCheckResponses(Base): - __tablename__ = 'arXiv_check_responses' - __table_args__ = ( - ForeignKeyConstraint(['check_result_id'], ['arXiv_check_results.check_result_id'], name='check_responses_results_fk'), - ForeignKeyConstraint(['user_id'], ['tapir_users.user_id'], name='check_responses_user_fk') - ) - - check_response_id: Mapped[int] = mapped_column(Integer, primary_key=True) - check_result_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) - user_id: Mapped[int] = mapped_column(Integer, 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=text('CURRENT_TIMESTAMP')) - message: Mapped[Optional[str]] = mapped_column(String(200)) - - check_result: Mapped['ArXivCheckResults'] = relationship('ArXivCheckResults', back_populates='arXiv_check_responses') - user: Mapped['TapirUser'] = relationship('TapirUser', back_populates='arXiv_check_responses') - - -class ArXivCheckResultViews(Base): - __tablename__ = 'arXiv_check_result_views' - - 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)) - - arXiv_checks: Mapped[List['ArXivChecks']] = relationship('ArXivChecks', back_populates='check_result_view') - - -class ArXivCheckRoles(Base): - __tablename__ = 'arXiv_check_roles' - - 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)) - - arXiv_checks: Mapped[List['ArXivChecks']] = relationship('ArXivChecks', back_populates='check_role') - - -class ArXivCheckTargets(Base): - __tablename__ = 'arXiv_check_targets' - - 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)) - - arXiv_checks: Mapped[List['ArXivChecks']] = relationship('ArXivChecks', back_populates='check_target') - - -class ArXivChecks(Base): - __tablename__ = 'arXiv_checks' - __table_args__ = ( - ForeignKeyConstraint(['check_result_view_id'], ['arXiv_check_result_views.check_result_view_id'], name='checks_result_views_fk'), - ForeignKeyConstraint(['check_role_id'], ['arXiv_check_roles.check_role_id'], name='checks_roles_fk'), - ForeignKeyConstraint(['check_target_id'], ['arXiv_check_targets.check_target_id'], name='checks_content_fk') - ) - - check_id: Mapped[int] = mapped_column(Integer, primary_key=True) - check_target_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) - check_role_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) - check_result_view_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True, server_default=text("'1'")) - name: Mapped[str] = mapped_column(String(40), nullable=False) - 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'")) - description: Mapped[Optional[str]] = mapped_column(String(200)) - - check_result_view: Mapped['ArXivCheckResultViews'] = relationship('ArXivCheckResultViews', back_populates='arXiv_checks') - check_role: Mapped['ArXivCheckRoles'] = relationship('ArXivCheckRoles', back_populates='arXiv_checks') - check_target: Mapped['ArXivCheckTargets'] = relationship('ArXivCheckTargets', back_populates='arXiv_checks') - arXiv_check_results: Mapped[List['ArXivCheckResults']] = relationship('ArXivCheckResults', back_populates='check') - - - class ArXivSubmissionLocks(Base): __tablename__ = 'arXiv_submission_locks' __table_args__ = ( @@ -2176,6 +2081,7 @@ class ArXivSubmissionLocks(Base): user: Mapped['TapirUser'] = relationship('TapirUser', back_populates='arXiv_submission_locks') +######################################################################################################## # Student-lead membership dashboard - supercedes "Subscription_UniversalInstitution" class MembershipInstitutions(Base): __tablename__ = 'membership_institutions' @@ -2202,7 +2108,8 @@ class MembershipUsers(Base): user_id: Mapped[Optional[int]] = mapped_column(Integer) - +######################################################################################################## +# class DBLaTeXMLDocuments(LaTeXMLBase): __tablename__ = 'arXiv_latexml_doc' @@ -2248,6 +2155,120 @@ class DBLaTeXMLFeedback (LaTeXMLBase): 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, 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 index e3d11f2a6..cd2531345 100644 --- a/development/README.md +++ b/development/README.md @@ -1,14 +1,29 @@ # 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 +* 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. @@ -28,11 +43,13 @@ so once generates `arxiv/db/models.py` +**DO NOT EDIT db/models.py.** + ## Anatomy of db_codegen.py does following steps. -1. start mysql docker +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 arxvi/db/autogen_models.py 4. merges arxiv/db/autogen_models.py and arxiv/db/orig_models.py and creates arxiv/db/models.py @@ -56,6 +73,10 @@ Here is the TL;DR of changes made to it: 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](development/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 @@ -76,8 +97,11 @@ Parsing, traversing and updating the Python code uses [CST](https://github.com/I **IMPORTANT** -Because of this, if you add a new table, **it does not show up in the output. You need to manually add the class -to arxiv/db/orig_models.py**. +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 @@ -95,3 +119,19 @@ This is where the latest model object is merged to existing model. 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/db_codegen.py b/development/db_codegen.py index a732ff329..a41476689 100644 --- a/development/db_codegen.py +++ b/development/db_codegen.py @@ -86,6 +86,9 @@ def mapper(line: str) -> str: 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""" @@ -147,8 +150,13 @@ 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 @@ -159,6 +167,7 @@ def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef 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 @@ -169,7 +178,8 @@ def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef # Only updates if there is a latest. latest_node = self.latest_def[class_name] - # Collect the existing assignments from the original class body + # 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 @@ -180,6 +190,11 @@ def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef # 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, @@ -282,6 +297,7 @@ def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef 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 @@ -290,7 +306,15 @@ def first_target(self, node: cst.CSTNode): return None def is_intpk(self, elem: cst.CSTNode): - """Find the intpk and print it as so""" + """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: @@ -303,9 +327,9 @@ def is_intpk(self, elem: cst.CSTNode): return False def has_comment(self, elem: cst.CSTNode): - """commented?""" + """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].comment + return elem.leading_lines and elem.leading_lines[-1].comment[1:].strip() return False def leave_Assign(self, original_node: cst.Assign, updated_node: cst.Assign) -> cst.CSTNode: @@ -340,6 +364,8 @@ def leave_Assign(self, original_node: cst.Assign, updated_node: cst.Assign) -> c # Assignments do have ards if hasattr(rh_new, 'args') and hasattr(rh_old, 'args'): + # + # This seems not needed # # foreign_key_constaints = {} # simple_indecies = {} @@ -408,13 +434,18 @@ def find_classes_and_tables(tree: cst.CSTNode): 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" @@ -448,7 +479,7 @@ def load_sql_file(sql_file): 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 alreayd loaded so ignore the error. + it means that the sql is already loaded so ignore the error. """ with open(sql_file, encoding="utf-8") as sql: @@ -463,12 +494,17 @@ def load_sql_file(sql_file): 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): @@ -476,6 +512,7 @@ def main() -> None: 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" @@ -483,48 +520,63 @@ def main() -> None: 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) - with open(os.path.expanduser('arxiv/db/orig_models.py'), encoding='utf-8') as model_fd: + # 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.warnind(f"class {new_class}") + 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.warnind(f"class {new_table}") + logging.warning(f"class {new_table}") + # Merge the exiting and latest models transformer = SchemaTransformer(latest_classes, latest_tables) updated_tree = existing_tree.visit(transformer) - updated_model = 'arxiv/db/models.py' - with open(os.path.expanduser(updated_model), "w", encoding='utf-8') as updated_fd: + # 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]) 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 index 0d9aa6d89..536822856 100644 --- a/development/extract_class_n_table.py +++ b/development/extract_class_n_table.py @@ -1,5 +1,7 @@ import json import ast +from ruamel.yaml import YAML +import sys def extract_class_table_mapping(filename: str): with open(filename, 'r') as src: @@ -28,6 +30,11 @@ def extract_class_table_mapping(filename: str): 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) - json.dump(class_table_mapping, open('arxiv/db/model-options.json', 'w'), indent=4) + yaml = YAML() + yaml.dump(class_table_mapping, output) + diff --git a/development/populate_arxiv_db.py b/development/populate_arxiv_db.py new file mode 100644 index 000000000..0987a3ac8 --- /dev/null +++ b/development/populate_arxiv_db.py @@ -0,0 +1,108 @@ +#!/usr/bin/python3 +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 + +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" + try: + subprocess.run(["docker", "pull", mysql_image], check=True) + + subprocess.run( + [ + "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 + ], + 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 main() -> None: + mysql_port = 13306 + db_name = "arxiv" + + 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) + for _ in range(20): + if is_port_open("127.0.0.1", mysql_port): + break + time.sleep(1) + + 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", "-h", "127.0.0.1", "--port", str(mysql_port), "-u", "root", "-ptestpassword", "--no-data", db_name], + stdout=sql_file, check=True) + + +if __name__ == "__main__": + """ + """ + main() diff --git a/development/sqlacodegen/ARXIV-README.md b/development/sqlacodegen/ARXIV-README.md index 5846e1bc0..390eb7519 100644 --- a/development/sqlacodegen/ARXIV-README.md +++ b/development/sqlacodegen/ARXIV-README.md @@ -48,6 +48,41 @@ This is an example of metadata for a table. - "request_audit = relationship('OwnershipRequestsAudit', back_populates='ownership_request', uselist=False)" - "documents = relationship('Document', secondary=t_arXiv_ownership_requests_papers)" +### Definition of metadata + + TABLE_NAME: + class_name: + + table_args: + - replace: [, ] + + columns: + : | + + relationships: + : + : + + additional_relationships: + - + +#### 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. + +#### 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. + ## Class name designation diff --git a/development/sqlacodegen/src/sqlacodegen/generators.py b/development/sqlacodegen/src/sqlacodegen/generators.py index 605cc7322..7d870a06b 100644 --- a/development/sqlacodegen/src/sqlacodegen/generators.py +++ b/development/sqlacodegen/src/sqlacodegen/generators.py @@ -60,9 +60,12 @@ get_constraint_sort_key, qualified_table_name, render_callable, - uses_default_name, + #uses_default_name, ) +def uses_default_name(_constraint: Constraint | Index) -> bool: + return True + if sys.version_info < (3, 10): pass else: @@ -207,6 +210,15 @@ def generate_base(self) -> None: 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 @@ -1278,6 +1290,11 @@ def render_table_args(self, table: Table, indexed_columns: set) -> str: 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: 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 From 3a6671fd0c13f03739f2967298dd12ef26573451 Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Thu, 21 Nov 2024 10:32:59 -0500 Subject: [PATCH 18/32] Add "load_arxiv_db_schema.py" --- development/load_arxiv_db_schema.py | 105 ++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 development/load_arxiv_db_schema.py diff --git a/development/load_arxiv_db_schema.py b/development/load_arxiv_db_schema.py new file mode 100644 index 000000000..a2a6b51a3 --- /dev/null +++ b/development/load_arxiv_db_schema.py @@ -0,0 +1,105 @@ +#!/usr/bin/python3 +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 + +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" + + 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)}") + + + +def main() -> None: + mysql_port = 13306 + db_name = "arxiv" + conn_argv = [f"--port={mysql_port}", "-h", "127.0.0.1", "-u", "root", "-ptestpassword"] + + 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) + + 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) + + with open("arxiv_db_schema.sql") as schema_file: + subprocess.call(cli, stdin=schema_file) + +if __name__ == "__main__": + """ + """ + main() From c1bd8f8b96403e6047a2c7b30de982e94bf96941 Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Thu, 21 Nov 2024 10:38:24 -0500 Subject: [PATCH 19/32] Add "load_arxiv_db_schema.py" (updated without fluff) --- development/load_arxiv_db_schema.py | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/development/load_arxiv_db_schema.py b/development/load_arxiv_db_schema.py index a2a6b51a3..4771d26ed 100644 --- a/development/load_arxiv_db_schema.py +++ b/development/load_arxiv_db_schema.py @@ -1,10 +1,5 @@ #!/usr/bin/python3 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 @@ -15,15 +10,8 @@ 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) @@ -31,19 +19,6 @@ def is_port_open(host: str, port: int): 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" @@ -71,7 +46,6 @@ def run_mysql_container(port: int, container_name="mysql-test", db_name="testdb" logging.error(f"Unexpected error: {e}\n\n{shlex.join(argv)}") - def main() -> None: mysql_port = 13306 db_name = "arxiv" From 1fed9816e6c49e3a97daa632faf7b182c58df5a7 Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Thu, 21 Nov 2024 11:14:17 -0500 Subject: [PATCH 20/32] Change the mysql version to 5.7.20. It now requires --ssl-mode=DISABLED for loading schema. --- development/load_arxiv_db_schema.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/development/load_arxiv_db_schema.py b/development/load_arxiv_db_schema.py index 4771d26ed..697cc62b7 100644 --- a/development/load_arxiv_db_schema.py +++ b/development/load_arxiv_db_schema.py @@ -21,10 +21,10 @@ def is_port_open(host: str, port: int): def run_mysql_container(port: int, container_name="mysql-test", db_name="testdb"): """Start a mysql docker""" - mysql_image = "mysql:5.7" + 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 = [ @@ -49,7 +49,7 @@ def run_mysql_container(port: int, container_name="mysql-test", db_name="testdb" def main() -> None: mysql_port = 13306 db_name = "arxiv" - conn_argv = [f"--port={mysql_port}", "-h", "127.0.0.1", "-u", "root", "-ptestpassword"] + conn_argv = [f"--port={mysql_port}", "-h", "127.0.0.1", "-u", "root", "-ptestpassword", "--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) @@ -59,9 +59,7 @@ def main() -> None: 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) + stdin=subprocess.PIPE) mysql.communicate("select 1") if mysql.returncode == 0: break From b02b9a17619ccbc69232014f1dd1b612cda3ee7c Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Wed, 11 Dec 2024 10:02:28 -0500 Subject: [PATCH 21/32] First pass of tests working with MySQL. --- .gitignore | 1 + Makefile | 17 +- arxiv/auth/conftest.py | 179 +- arxiv/auth/legacy/tests/test_accounts.py | 12 +- arxiv/auth/legacy/tests/test_bootstrap.py | 43 +- .../legacy/tests/test_endorsement_auto.py | 12 +- arxiv/auth/legacy/tests/test_endorsements.py | 151 +- arxiv/auth/legacy/util.py | 32 +- arxiv/auth/tests/test_db.py | 1 + arxiv/db/arxiv-db-metadata.yaml | 89 +- arxiv/db/models.py | 866 ++++--- arxiv/db/orig_models.py | 6 +- arxiv/db/tests/test_db_schema.py | 9 +- development/README.md | 12 +- development/arxiv_db_schema.sql | 390 +-- development/create_arxiv_schema.sh | 19 + development/db_codegen.py | 9 +- development/load_arxiv_db_schema.py | 100 +- development/populate_arxiv_db.py | 139 +- development/run_mysql_container.py | 121 + development/sqlacodegen/ARXIV-README.md | 55 +- .../sqlacodegen/src/sqlacodegen/generators.py | 10 + development/test-data/arXiv_archives.json | 314 +++ development/test-data/arXiv_categories.json | 2125 +++++++++++++++++ .../test-data/arXiv_endorsement_domains.json | 436 ++++ development/test-data/arXiv_groups.json | 47 + 26 files changed, 4338 insertions(+), 857 deletions(-) create mode 100755 development/create_arxiv_schema.sh create mode 100644 development/run_mysql_container.py create mode 100644 development/test-data/arXiv_archives.json create mode 100644 development/test-data/arXiv_categories.json create mode 100644 development/test-data/arXiv_endorsement_domains.json create mode 100644 development/test-data/arXiv_groups.json diff --git a/.gitignore b/.gitignore index da454afb8..c22c7ef5a 100644 --- a/.gitignore +++ b/.gitignore @@ -134,3 +134,4 @@ test.db-journal arxiv/db/.autogen_models.py /arxiv/db/autogen_models.py +/arxiv/db/near_models.py diff --git a/Makefile b/Makefile index 19aa1ee4c..a5b182a39 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ PROD_DB_PROXY_PORT := 2021 -.PHONY: db-models prod-proxy +.PHONY: db-models prod-proxy test default: venv/bin/poetry @@ -22,16 +22,11 @@ venv: db-models: arxiv/db/autogen_models.py -arxiv/db/autogen_models.py: arxiv/db/autogen_models_patch.diff ~/.arxiv/arxiv-db-prod-readonly - @PROD_ARXIV_DB_URI=`cat ~/.arxiv/arxiv-db-prod-readonly`; . venv/bin/activate && \ - poetry run sqlacodegen "$$PROD_ARXIV_DB_URI" --outfile arxiv/db/autogen_models.py && \ - poetry run python3 development/patch_db_models.py arxiv/db/autogen_models.py arxiv/db/arxiv_db_metadata.json - patch arxiv/db/autogen_models.py arxiv/db/autogen_models_patch.diff - -arxiv/db/autogen_models_patch.diff: - @PROD_ARXIV_DB_URI=`cat ~/.arxiv/arxiv-db-prod-readonly`; . venv/bin/activate && \ - poetry run sqlacodegen "$$PROD_ARXIV_DB_URI" --outfile arxiv/db/.autogen_models.py - diff -c arxiv/db/.autogen_models.py arxiv/db/autogen_models.py > arxiv/db/autogen_models_patch.diff 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/conftest.py b/arxiv/auth/conftest.py index c49732293..8d18c6f0a 100644 --- a/arxiv/auth/conftest.py +++ b/arxiv/auth/conftest.py @@ -1,14 +1,17 @@ +import logging +import shlex import shutil +import subprocess 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 sqlalchemy import create_engine, text, CursorResult +from sqlalchemy.orm import Session +from sqlalchemy.pool import NullPool from .legacy import util from .legacy.passwords import hash_password @@ -20,26 +23,106 @@ from ..auth.auth import Auth from ..auth.auth.middleware import AuthMiddleware +logging.basicConfig(level=logging.INFO) -@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) +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}", + # "--ssl-mode=DISABLED", + DB_NAME] +def arxiv_base_dir() -> str: + """ + Returns: + "arxiv-base" directory abs path + """ + here = os.path.abspath(__file__) + root_dir = here + for _ in range(3): + root_dir = os.path.dirname(root_dir) + return root_dir + + +@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", 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 + 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 = {} + # 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: + 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) + mysql = subprocess.Popen(my_sql_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, encoding="utf-8") + try: + logger.info(debug_sql + sql) + out, err = mysql.communicate(sql, timeout=9999) + if out: + logger.info(out) + if err: + 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: + 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 ]) + logger.info(kill_conn) + mysql = subprocess.Popen(my_sql_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, encoding="utf-8") + mysql.communicate(kill_conn) + db_engine.dispose() -@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 @@ -90,7 +173,7 @@ def foouser(mocker): issued_when=n, issued_to='127.0.0.1', remote_host='foohost.foo.com', - session_id=0 + session_id=1 ) user.tapir_nicknames = nick user.tapir_passwords = password @@ -100,8 +183,17 @@ def foouser(mocker): @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: + 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, @@ -117,6 +209,15 @@ def db_with_user(classic_db_engine, foouser): 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, @@ -126,11 +227,30 @@ def db_with_user(classic_db_engine, foouser): 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, @@ -140,20 +260,14 @@ def db_with_user(classic_db_engine, foouser): 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) - + db_engine, _ = configure_db_engine(db_with_user,None) + yield None @pytest.fixture def app(db_with_user): @@ -169,3 +283,8 @@ def app(db_with_user): @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/arxiv/auth/legacy/tests/test_accounts.py b/arxiv/auth/legacy/tests/test_accounts.py index 10ffbe0e8..0dc0fb087 100644 --- a/arxiv/auth/legacy/tests/test_accounts.py +++ b/arxiv/auth/legacy/tests/test_accounts.py @@ -31,20 +31,22 @@ 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): +def test_with_nonexistant_user_wo_app(app): """There is no user with the passed username.""" - assert not accounts.does_username_exist('baruser') + with app.app_context(): + assert not accounts.does_username_exist('baruser') def test_with_existant_user_w_app(app): """There is a user with the passed username.""" with app.app_context(): assert accounts.does_username_exist('foouser') -def test_with_existant_user_wo_app(db_configed): +def test_with_existant_user_wo_app(app): """There is a user with the passed username.""" - assert accounts.does_username_exist('foouser') + with app.app_context(): + assert accounts.does_username_exist('foouser') def test_email(app): """There is no user with the passed email.""" diff --git a/arxiv/auth/legacy/tests/test_bootstrap.py b/arxiv/auth/legacy/tests/test_bootstrap.py index f457eeb6b..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 @@ -82,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 @@ -250,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 23d8d3e98..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 @@ -100,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(): @@ -147,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(): @@ -174,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(): @@ -295,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 0213344a5..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 @@ -82,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), @@ -109,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: @@ -133,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) ) @@ -232,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(): @@ -279,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'] @@ -304,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(): @@ -326,6 +336,7 @@ def test_domain_papers(self): valid=1, **self.default_tracking_data )) + session.execute( insert(models.t_arXiv_in_category) .values( @@ -335,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, @@ -367,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, @@ -409,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/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 index 8a5cb0400..ee46c21ae 100644 --- a/arxiv/db/arxiv-db-metadata.yaml +++ b/arxiv/db/arxiv-db-metadata.yaml @@ -9,16 +9,18 @@ # To preserve the code change, this file exists. When the customized sqlacodegen runs, this is used to change # and override the behavior of codegen. # -# Generally, sqlacodegen is driven from development/db_codegen.py +# sqlacodegen is driven from development/db_codegen.py # -# a hack +# 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 @@ -30,13 +32,9 @@ Subscription_UniversalInstitutionContact: class_name: MemberInstitutionContact columns: sid: "mapped_column(ForeignKey('Subscription_UniversalInstitution.id', ondelete='CASCADE'), nullable=False, index=True)" - relationships: - Subscription_UniversalInstitution: relationship('MemberInstitution', primaryjoin='MemberInstitutionContact.sid == MemberInstitution.id') Subscription_UniversalInstitutionIP: class_name: MemberInstitutionIP - relationships: - Subscription_UniversalInstitution: relationship('MemberInstitution', primaryjoin='MemberInstitutionIP.sid == MemberInstitution.id') arXiv_admin_log: class_name: AdminLog @@ -71,16 +69,15 @@ arXiv_bogus_countries: arXiv_categories: class_name: Category relationships: - arXiv_demographics: "" arXiv_archives: "" - arXiv_cross_control: "" - arXiv_categories: "" + 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_cross_controls = relationship('CrossControl', back_populates='arXiv_category')" arXiv_questionable_categories: class_name: QuestionableCategory @@ -157,11 +154,11 @@ arXiv_endorsements: class_name: Endorsement table_args: - replace: ["Index('archive', 'archive', 'subject_class'),", ""] - # - replace: ["Index('endorser_id_2', 'endorser_id', 'endorsee_id', 'archive', 'subject_class', unique=True),", ""] 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: @@ -204,8 +201,8 @@ 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: @@ -234,7 +231,7 @@ arXiv_ownership_requests: - "request_audit = relationship('OwnershipRequestsAudit', back_populates='ownership_request', uselist=False)" - "documents = relationship('Document', secondary=t_arXiv_ownership_requests_papers)" -# Have a mixed feelig about this. This is clearly hand-edited, and not really used +# I think this is hand-edited, and not really used anywhere it seems arXiv_ownership_requests_audit: class_name: OwnershipRequestsAudit table_args: drop @@ -253,7 +250,7 @@ arXiv_ownership_requests_audit: arXiv_paper_owners: class_name: PaperOwner table_args: - # This is given by the document_id column - squalch the index name that's not relevant + # 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'),", ""] @@ -297,6 +294,13 @@ arXiv_submission_category: 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: @@ -308,6 +312,8 @@ 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: @@ -327,7 +333,6 @@ arXiv_submissions: arXiv_pilot_datasets: class_name: PilotDataset columns: - # Kill off the slot created: drop arXiv_submission_abs_classifier_data: @@ -360,12 +365,12 @@ 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: @@ -397,7 +402,7 @@ tapir_countries: class_name: TapirCountry relationships: tapir_address: "relationship('TapirAddress', back_populates='tapir_country')" - tapir_demographics: "" + tapir_demographics: "relationship('TapirDemographic', back_populates='tapir_country')" tapir_email_change_tokens: class_name: TapirEmailChangeToken @@ -441,6 +446,7 @@ tapir_string_variables: class_name: TapirStringVariable tapir_strings: class_name: TapirString + tapir_users: class_name: TapirUser relationships: @@ -459,40 +465,6 @@ tapir_users: arXiv_cross_controls: "relationship('CrossControl', back_populates='user')" additional_relationships: - - "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['ArXivSubmissionLocks']] = relationship('ArXivSubmissionLocks', 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')" arXiv_author_ids: @@ -501,7 +473,8 @@ arXiv_demographics: class_name: Demographic relationships: arXiv_categories: - arXiv_category: "relationship('Category', primaryjoin='and_(Demographic.archive == Category.archive, Demographic.subject_class == Category.subject_class)', backref='category_demographics')" + 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: @@ -514,7 +487,7 @@ tapir_demographics: class_name: TapirDemographic relationships: tapir_countries: - tapir_country: relationship('TapirCountry', primaryjoin='TapirDemographic.country == TapirCountry.digraph', backref='tapir_demographics') + tapir_country: relationship('TapirCountry', primaryjoin='TapirDemographic.country == TapirCountry.digraph', back_populates='tapir_demographics') tapir_users_hot: class_name: TapirUsersHot tapir_users_password: @@ -530,9 +503,12 @@ 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: @@ -574,9 +550,12 @@ arXiv_checks: 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 f42089ae6..fce36dcd8 100644 --- a/arxiv/db/models.py +++ b/arxiv/db/models.py @@ -5,7 +5,11 @@ These models represent the entire arXiv DB and the LaTeXML DB. -This file was generated by using arxiv/development/db_codegen.py along with arxiv/development/sqlacodegen +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. @@ -80,7 +84,7 @@ class MemberInstitutionContact(Base): 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) + 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)) @@ -117,18 +121,26 @@ class AdminLog(Base): 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) + 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"),) + __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) @@ -150,7 +162,7 @@ class AdminMetadata(Base): 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( @@ -170,7 +182,7 @@ class ArchiveCategory(Base): __tablename__ = "arXiv_archive_category" __table_args__ = {"mysql_charset": "latin1"} - archive_id: Mapped[str] = mapped_column(String(16), primary_key=True, nullable=False) + 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) @@ -178,7 +190,7 @@ class ArchiveDef(Base): __tablename__ = "arXiv_archive_def" __table_args__ = {"mysql_charset": "latin1"} - archive: Mapped[str] = mapped_column(String(16), primary_key=True) + archive: Mapped[str] = mapped_column(String(16), primary_key=True, server_default=FetchedValue()) name: Mapped[Optional[str]] = mapped_column(String(255)) @@ -186,20 +198,20 @@ class ArchiveGroup(Base): __tablename__ = "arXiv_archive_group" __table_args__ = {"mysql_charset": "latin1"} - archive_id: Mapped[str] = mapped_column(String(16), primary_key=True, nullable=False) - group_id: Mapped[str] = mapped_column(String(16), primary_key=True, nullable=False) + 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" __table_args__ = {"mysql_charset": "latin1"} - archive_id: Mapped[str] = mapped_column(String(16), primary_key=True) - in_group: Mapped[str] = mapped_column(ForeignKey("arXiv_groups.group_id"), nullable=False, index=True) - archive_name: Mapped[str] = mapped_column(String(255), nullable=False) - start_date: Mapped[str] = mapped_column(String(4), nullable=False) - end_date: Mapped[str] = mapped_column(String(4), nullable=False) - subdivided: Mapped[int] = mapped_column(Integer, nullable=False) + archive_id: Mapped[str] = mapped_column(String(16), primary_key=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_categories: Mapped[List["Category"]] = relationship("Category", back_populates="arXiv_archive") @@ -220,8 +232,8 @@ class AwsFile(Base): __tablename__ = "arXiv_aws_files" __table_args__ = {"mysql_charset": "utf8mb3"} - type: Mapped[str] = mapped_column(String(10), nullable=False, index=True) - filename: Mapped[str] = mapped_column(String(100), primary_key=True) + 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) @@ -233,7 +245,7 @@ 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)) +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): @@ -241,18 +253,18 @@ class BibFeed(Base): __table_args__ = {"mysql_charset": "latin1"} bib_id: Mapped[intpk] - name: Mapped[str] = mapped_column(String(64), nullable=False) - priority: Mapped[int] = mapped_column(Integer, nullable=False) + 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) + 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) + enabled: Mapped[Optional[int]] = mapped_column(Integer, server_default=FetchedValue()) class BibUpdate(Base): @@ -260,9 +272,9 @@ class BibUpdate(Base): __table_args__ = {"mysql_charset": "latin1"} update_id: Mapped[intpk] - document_id: Mapped[int] = mapped_column(Integer, nullable=False) - bib_id: Mapped[int] = mapped_column(Integer, nullable=False) - updated: Mapped[datetime] = mapped_column(DateTime, nullable=False) + 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) @@ -277,8 +289,8 @@ class BogusCountries(Base): __tablename__ = "arXiv_bogus_countries" __table_args__ = {"mysql_charset": "latin1"} - user_id: Mapped[int] = mapped_column(Integer, primary_key=True) - country_name: Mapped[str] = mapped_column(String(255), nullable=False) + 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( @@ -295,7 +307,7 @@ class Category(Base): # 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) + 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)) @@ -303,12 +315,16 @@ class Category(Base): 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") @@ -316,7 +332,7 @@ class Category(Base): class QuestionableCategory(Category): __tablename__ = "arXiv_questionable_categories" - __table_args__ = (ForeignKeyConstraint(["archive", "subject_class"], ["arXiv_categories.archive", "arXiv_categories.subject_class"]),) + __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()) @@ -328,7 +344,11 @@ class CategoryDef(Base): 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) + 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): @@ -336,12 +356,14 @@ class ControlHold(Base): __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) - hold_type: Mapped[Literal["submission", "cross", "jref"]] = mapped_column(Enum("submission", "cross", "jref"), nullable=False, index=True) - hold_status: Mapped[Literal["held", "extended", "accepted", "rejected"]] = mapped_column(Enum("held", "extended", "accepted", "rejected"), nullable=False, index=True) - hold_reason: Mapped[str] = mapped_column(String(255), nullable=False, index=True) - hold_data: Mapped[str] = mapped_column(String(255), nullable=False) - origin: Mapped[Literal["auto", "user", "admin", "moderator"]] = mapped_column(Enum("auto", "user", "admin", "moderator"), nullable=False, index=True) + 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) @@ -351,11 +373,7 @@ class ControlHold(Base): 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"), - ) + __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()) @@ -370,14 +388,16 @@ class CrossControl(Base): 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"),) + __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")) @@ -386,7 +406,7 @@ class DataciteDois(Base): 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): @@ -398,13 +418,13 @@ class DBLPAuthor(Base): class DBLPDocumentAuthor(Base): __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) # 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 @@ -416,13 +436,14 @@ class DBLPDocumentAuthor(Base): class DocumentCategory(Base): __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) + 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): @@ -430,10 +451,10 @@ class Document(Base): __table_args__ = {"mysql_charset": "latin1"} document_id: Mapped[intpk] - paper_id: Mapped[str] = mapped_column(String(20), nullable=False, unique=True, index=True) - title: Mapped[str] = mapped_column(String(255), nullable=False, index=True) + 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) + 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)) @@ -443,10 +464,21 @@ class Document(Base): 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") class DBLP(Document): __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()) url: Mapped[Optional[str]] = mapped_column(String(80)) @@ -454,6 +486,7 @@ class DBLP(Document): class PaperPw(Document): __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()) password_storage: Mapped[Optional[int]] = mapped_column(Integer) @@ -461,7 +494,11 @@ class PaperPw(Document): t_arXiv_duplicates = Table( - "arXiv_duplicates", metadata, Column("user_id", ForeignKey("tapir_users.user_id"), nullable=False, index=True), 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)), ) @@ -469,11 +506,11 @@ class EndorsementDomain(Base): __tablename__ = "arXiv_endorsement_domains" __table_args__ = {"mysql_charset": "latin1"} - endorsement_domain: Mapped[str] = mapped_column(String(32), primary_key=True) - endorse_all: Mapped[Literal["y", "n"]] = mapped_column(Enum("y", "n"), nullable=False) - mods_endorse_all: Mapped[Literal["y", "n"]] = mapped_column(Enum("y", "n"), nullable=False) - endorse_email: Mapped[Literal["y", "n"]] = mapped_column(Enum("y", "n"), nullable=False) - papers_to_endorse: Mapped[int] = mapped_column(Integer, nullable=False) + 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(Integer, nullable=False, server_default=FetchedValue()) arXiv_categories: Mapped[List["Category"]] = relationship("Category", back_populates="arXiv_endorsement_domain") @@ -482,28 +519,31 @@ 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"), + 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()) 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( + arXiv_categories: Mapped["Category"] = 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) + 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" + __table_args__ = {"mysql_charset": "latin1"} 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()) @@ -516,8 +556,8 @@ 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"), + Index("endorser_id_2", "endorser_id", "endorsee_id", "archive", "subject_class", unique=True), + {"mysql_charset": "latin1"}, ) endorsement_id: Mapped[intpk] @@ -531,14 +571,15 @@ class Endorsement(Base): 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") + 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" + __table_args__ = {"mysql_charset": "latin1"} 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()) @@ -554,14 +595,14 @@ class FreezeLog(Base): __tablename__ = "arXiv_freeze_log" __table_args__ = {"mysql_charset": "latin1"} - date: Mapped[int] = mapped_column(Integer, primary_key=True) + date: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) class GroupDef(Base): __tablename__ = "arXiv_group_def" __table_args__ = {"mysql_charset": "latin1"} - archive_group: Mapped[str] = mapped_column(String(16), primary_key=True) + archive_group: Mapped[str] = mapped_column(String(16), primary_key=True, server_default=FetchedValue()) name: Mapped[Optional[str]] = mapped_column(String(255)) @@ -569,9 +610,9 @@ class Group(Base): __tablename__ = "arXiv_groups" __table_args__ = {"mysql_charset": "latin1"} - group_id: Mapped[str] = mapped_column(String(16), primary_key=True) - group_name: Mapped[str] = mapped_column(String(255), nullable=False) - start_year: Mapped[str] = mapped_column(String(4), nullable=False) + 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") @@ -584,14 +625,14 @@ class Group(Base): 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"), + 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"),) + __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()) @@ -604,8 +645,8 @@ class JrefControl(Base): 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): @@ -614,34 +655,36 @@ class License(Base): 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) + 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" __table_args__ = {"mysql_charset": "latin1"} - id: Mapped[str] = mapped_column(String(255), primary_key=True) + id: Mapped[str] = mapped_column(String(255), primary_key=True, server_default=FetchedValue()) 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"),) + __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()) paper_id: Mapped[str] = mapped_column(String(64), nullable=False) - created: Mapped[Optional[datetime]] - updated: Mapped[Optional[datetime]] + 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) @@ -660,37 +703,39 @@ class Metadata(Base): 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") + 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") - submitter = relationship("TapirUser", primaryjoin="Metadata.submitter_id == TapirUser.user_id", back_populates="arXiv_metadata") class MirrorList(Base): __tablename__ = "arXiv_mirror_list" + __table_args__ = {"mysql_charset": "latin1"} mirror_list_id: Mapped[intpk] - created: Mapped[Optional[datetime]] - updated: Mapped[Optional[datetime]] + 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" __table_args__ = {"mysql_charset": "utf8mb3"} - user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), primary_key=True, nullable=False) - secret: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False) - valid: Mapped[int] = mapped_column(Integer, nullable=False) - issued_when: Mapped[int] = mapped_column(Integer, nullable=False) - issued_to: Mapped[str] = mapped_column(String(16), nullable=False) - remote_host: Mapped[str] = mapped_column(String(255), nullable=False) + 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: Mapped["TapirUser"] = relationship("TapirUser", primaryjoin="ModeratorApiKey.user_id == TapirUser.user_id", back_populates="arXiv_moderator_api_keys") @@ -707,7 +752,7 @@ class ModeratorApiKey(Base): 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"), + Index("mod_user_id", "archive", "subject_class", "user_id", unique=True), ) @@ -715,7 +760,7 @@ class MonitorKlog(Base): __tablename__ = "arXiv_monitor_klog" __table_args__ = {"mysql_charset": "latin1"} - t: Mapped[int] = mapped_column(Integer, primary_key=True) + t: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) sent: Mapped[Optional[int]] = mapped_column(Integer) @@ -723,20 +768,20 @@ class MonitorMailq(Base): __tablename__ = "arXiv_monitor_mailq" __table_args__ = {"mysql_charset": "latin1"} - t: Mapped[int] = mapped_column(Integer, primary_key=True) - main_q: Mapped[int] = mapped_column(Integer, nullable=False) - local_q: Mapped[int] = mapped_column(Integer, nullable=False) - local_host_map: Mapped[int] = mapped_column(Integer, nullable=False) - local_timeout: Mapped[int] = mapped_column(Integer, nullable=False) - local_refused: Mapped[int] = mapped_column(Integer, nullable=False) - local_in_flight: Mapped[int] = mapped_column(Integer, nullable=False) + 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" __table_args__ = {"mysql_charset": "latin1"} - t: Mapped[int] = mapped_column(Integer, primary_key=True) + t: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=FetchedValue()) sent: Mapped[Optional[int]] = mapped_column(Integer) @@ -746,13 +791,13 @@ class NextMail(Base): 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) + 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) - type: Mapped[str] = mapped_column(String(255), nullable=False) + 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) + is_written: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) class OrcidConfig(Base): @@ -775,20 +820,24 @@ class OrcidConfig(Base): class OwnershipRequest(Base): __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()) - 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" + __table_args__ = {"mysql_charset": "latin1"} 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()) @@ -802,27 +851,20 @@ class OwnershipRequestsAudit(Base): 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'), - ) + __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") + document: Mapped["Document"] = relationship("Document", back_populates="owners") owner = relationship("TapirUser", foreign_keys="[PaperOwner.user_id]", back_populates="owned_papers") @@ -831,16 +873,17 @@ class PaperSession(Base): __table_args__ = {"mysql_charset": "latin1"} paper_session_id: Mapped[intpk] - paper_id: Mapped[str] = mapped_column(String(16), nullable=False) - start_time: Mapped[int] = mapped_column(Integer, nullable=False) - end_time: Mapped[int] = mapped_column(Integer, nullable=False) - ip_name: Mapped[str] = mapped_column(String(16), nullable=False) + 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" + __table_args__ = {"mysql_charset": "latin1"} file_id: Mapped[intpk] submission_id: Mapped[int] = mapped_column(ForeignKey("arXiv_submissions.submission_id"), nullable=False, index=True) @@ -849,14 +892,14 @@ class PilotFile(Base): 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" __table_args__ = {"mysql_charset": "latin1"} - date: Mapped[int] = mapped_column(Integer, primary_key=True) + 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)) @@ -866,7 +909,7 @@ class RejectSessionUsername(Base): __tablename__ = "arXiv_reject_session_usernames" __table_args__ = {"mysql_charset": "latin1"} - username: Mapped[str] = mapped_column(String(64), primary_key=True) + username: Mapped[str] = mapped_column(String(64), primary_key=True, server_default=FetchedValue()) class SciencewisePing(Base): @@ -879,7 +922,7 @@ class SciencewisePing(Base): class ShowEmailRequest(Base): __tablename__ = "arXiv_show_email_requests" - __table_args__ = (Index("email_reqs_user_id", "user_id", "dated"),) + __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()) @@ -891,8 +934,8 @@ 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): @@ -927,9 +970,9 @@ class StatsMonthlySubmission(Base): __tablename__ = "arXiv_stats_monthly_submissions" __table_args__ = {"mysql_charset": "latin1"} - ym: Mapped[dt.date] = mapped_column(Date, primary_key=True) + 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) + historical_delta: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) class SubmissionAgreement(Base): @@ -937,25 +980,29 @@ class SubmissionAgreement(Base): __table_args__ = {"mysql_charset": "latin1"} agreement_id: Mapped[int] = mapped_column(Integer, primary_key=True) - effective_date: Mapped[Optional[datetime]] = mapped_column(DateTime) + 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" + __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()) 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" + __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) @@ -963,20 +1010,24 @@ class SubmissionCategoryProposal(Base): 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]] + 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 = 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") + 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"),) + __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()) @@ -989,13 +1040,13 @@ class SubmissionControl(Base): 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"),) + __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()) @@ -1003,12 +1054,13 @@ class SubmissionFlag(Base): 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" + __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) @@ -1017,51 +1069,54 @@ class SubmissionHoldReason(Base): 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: 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"),) + __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()) 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" + __table_args__ = {"mysql_charset": "utf8mb3"} 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: 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" + __table_args__ = {"mysql_charset": "utf8mb3"} 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]] + updated: Mapped[Optional[datetime]] = mapped_column(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") + 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" + __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) @@ -1075,13 +1130,13 @@ class Submission(Base): 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)) @@ -1090,7 +1145,7 @@ 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]] = mapped_column(VARCHAR(255, charset="latin1")) + 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)) @@ -1110,27 +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_id: Mapped[Optional[int]] = 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: 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["ArXivSubmissionLocks"]] = relationship("ArXivSubmissionLocks", back_populates="submission") + 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): """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()) + 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()) @@ -1141,13 +1212,14 @@ class PilotDataset(Submission): class SubmissionAbsClassifierDatum(Base): __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()) 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) + 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) @@ -1158,13 +1230,14 @@ class SubmissionAbsClassifierDatum(Base): class SubmissionClassifierDatum(Base): __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()) 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) + is_oversize: Mapped[Optional[int]] = mapped_column(Integer, server_default=text("'0'")) class SubmitterFlag(Base): @@ -1184,7 +1257,7 @@ class SuspectEmail(Base): 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) + updated: Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=FetchedValue()) class Title(Base): @@ -1199,14 +1272,15 @@ class Title(Base): class TopPaper(Base): __tablename__ = "arXiv_top_papers" + __table_args__ = {"mysql_charset": "latin1"} - from_week: Mapped[date] = mapped_column(Date, primary_key=True, nullable=False, 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(SmallInteger, 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): @@ -1215,16 +1289,16 @@ class TrackbackPing(Base): trackback_id: Mapped[intpk] document_id: Mapped[Optional[int]] = mapped_column(Integer, index=True) - title: Mapped[str] = mapped_column(String(255), nullable=False) - excerpt: Mapped[str] = mapped_column(String(255), nullable=False) - url: Mapped[str] = mapped_column(String(255), nullable=False, index=True) - blog_name: Mapped[str] = mapped_column(String(255), nullable=False) - remote_host: Mapped[str] = mapped_column(String(255), nullable=False) - remote_addr: Mapped[str] = mapped_column(String(16), nullable=False) - posted_date: Mapped[int] = mapped_column(Integer, nullable=False, index=True) - is_stale: Mapped[int] = mapped_column(Integer, nullable=False) - approved_by_user: Mapped[int] = mapped_column(Integer, nullable=False) - approved_time: Mapped[int] = mapped_column(Integer, nullable=False) + 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() ) @@ -1266,7 +1340,7 @@ class TrackbackSite(Base): __tablename__ = "arXiv_trackback_sites" __table_args__ = {"mysql_charset": "latin1"} - pattern: Mapped[str] = mapped_column(String(255), nullable=False, index=True) + 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()) @@ -1276,15 +1350,17 @@ class Tracking(Base): __table_args__ = {"mysql_charset": "latin1"} tracking_id: Mapped[intpk] - sword_id: Mapped[int] = mapped_column(Integer, nullable=False, unique=True, index=True) + 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) + 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( @@ -1292,11 +1368,12 @@ class Updates(Base): 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) + category: Mapped[Optional[str]] = 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})" @@ -1315,6 +1392,7 @@ def __repr__(self) -> str: class Version(Base): __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()) version: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, server_default=FetchedValue()) @@ -1323,21 +1401,21 @@ class Version(Base): 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"]),) + __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, index=True)) @@ -1348,8 +1426,8 @@ class VersionsChecksum(Version): metadata, Column("control_id", Integer, index=True), Column("type", Enum("submission", "cross", "jref")), - Column("queued_date", Integer, nullable=False), - Column("sent_date", Integer, nullable=False), + 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), ) @@ -1365,29 +1443,29 @@ class DbixClassSchemaVersion(Base): t_demographics_backup = Table( "demographics_backup", metadata, - Column("user_id", Integer, nullable=False), - Column("country", String(2), nullable=False), - Column("affiliation", String(255), nullable=False), - Column("url", String(255), nullable=False), + 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), + Column("original_subject_classes", String(255), nullable=False, server_default=FetchedValue()), Column("flag_group_physics", Integer), - Column("flag_group_math", Integer, nullable=False), - Column("flag_group_cs", Integer, nullable=False), - Column("flag_group_nlin", Integer, nullable=False), - Column("flag_proxy", Integer, nullable=False), - Column("flag_journal", Integer, nullable=False), - Column("flag_xml", Integer, nullable=False), - Column("dirty", Integer, nullable=False), - Column("flag_group_test", Integer, nullable=False), - Column("flag_suspect", Integer, nullable=False), - Column("flag_group_q_bio", Integer, nullable=False), - Column("flag_no_upload", Integer, nullable=False), - Column("flag_no_endorse", Integer, nullable=False), - Column("veto_status", Enum("ok", "no-endorse", "no-upload")), + 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()), ) @@ -1402,6 +1480,7 @@ class Session(Base): class TapirAddress(Base): __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()) address_type: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, index=True, server_default=FetchedValue()) @@ -1414,12 +1493,13 @@ class TapirAddress(Base): 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" + __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) @@ -1429,28 +1509,32 @@ class TapirAdminAudit(Base): 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) + 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" __table_args__ = {"mysql_charset": "latin1"} - digraph: Mapped[str] = mapped_column(String(2), primary_key=True) - country_name: Mapped[str] = mapped_column(String(255), nullable=False) - rank: Mapped[int] = mapped_column(Integer, nullable=False) + 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" + __table_args__ = {"mysql_charset": "latin1"} - user_id = 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()) 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()) @@ -1464,7 +1548,7 @@ 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( @@ -1481,12 +1565,13 @@ class TapirEmailChangeToken(Base): class TapirEmailHeader(Base): __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()) 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): @@ -1496,15 +1581,16 @@ class TapirEmailLog(Base): 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) + 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) + template_id: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) class TapirEmailMailing(Base): __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) @@ -1516,14 +1602,14 @@ class TapirEmailMailing(Base): 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"),) + __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()) @@ -1537,12 +1623,15 @@ class TapirEmailTemplate(Base): 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" + __table_args__ = {"mysql_charset": "latin1"} 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()) @@ -1553,7 +1642,7 @@ 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( @@ -1571,15 +1660,15 @@ class TapirEmailToken(Base): t_tapir_error_log = Table( "tapir_error_log", metadata, - Column("error_date", Integer, nullable=False, index=True), + 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), - Column("remote_host", String(255), nullable=False), - Column("tracking_cookie", String(32), nullable=False, index=True), - Column("message", String(32), nullable=False, index=True), - Column("url", String(255), nullable=False), - Column("error_url", String(255), nullable=False), + 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()), ) @@ -1587,16 +1676,16 @@ class TapirIntegerVariable(Base): __tablename__ = "tapir_integer_variables" __table_args__ = {"mysql_charset": "latin1"} - variable_id: Mapped[str] = mapped_column(String(32), primary_key=True) - value: Mapped[int] = mapped_column(Integer, nullable=False) + 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"),) + __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()) + 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'")) @@ -1604,7 +1693,7 @@ class TapirNickname(Base): 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): @@ -1620,20 +1709,21 @@ class TapirNicknamesAudit(Base): t_tapir_no_cookies = Table( "tapir_no_cookies", metadata, - Column("log_date", Integer, nullable=False), - Column("ip_addr", String(16), nullable=False), - Column("remote_host", String(255), nullable=False), - Column("tracking_cookie", String(255), nullable=False), - Column("session_data", String(255), nullable=False), - Column("user_agent", String(255), nullable=False), + 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), 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" + __table_args__ = {"mysql_charset": "latin1"} 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()) @@ -1643,8 +1733,8 @@ class TapirPermanentToken(Base): 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: 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( @@ -1661,13 +1751,14 @@ class TapirPermanentToken(Base): class TapirPhone(Base): __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()) 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): @@ -1675,11 +1766,11 @@ class TapirPolicyClass(Base): __table_args__ = {"mysql_charset": "latin1"} class_id: Mapped[int] = mapped_column(Integer, primary_key=True) - name: Mapped[str] = mapped_column(String(64), nullable=False) + 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) - recovery_policy: Mapped[int] = mapped_column(Integer, nullable=False) - permanent_login: Mapped[int] = mapped_column(Integer, 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") @@ -1698,14 +1789,15 @@ class TapirPresession(Base): __table_args__ = {"mysql_charset": "latin1"} presession_id: Mapped[intpk] - ip_num: Mapped[str] = mapped_column(String(16), nullable=False) - remote_host: Mapped[str] = mapped_column(String(255), nullable=False) - tracking_cookie: Mapped[str] = mapped_column(String(255), nullable=False) - created_at: Mapped[int] = mapped_column(Integer, nullable=False) + 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" + __table_args__ = {"mysql_charset": "latin1"} 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()) @@ -1716,11 +1808,12 @@ 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" + __table_args__ = {"mysql_charset": "latin1"} 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()) @@ -1729,36 +1822,42 @@ class TapirRecoveryTokensUsed(Base): 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: 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), + 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), + Column("seq", Integer, nullable=False, server_default=FetchedValue()), ) class TapirSession(Base): __tablename__ = "tapir_sessions" + __table_args__ = {"mysql_charset": "latin1"} - session_id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + 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: 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" + __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()) @@ -1770,7 +1869,7 @@ class TapirStringVariable(Base): __tablename__ = "tapir_string_variables" __table_args__ = {"mysql_charset": "latin1"} - variable_id: Mapped[str] = mapped_column(String(32), primary_key=True) + variable_id: Mapped[str] = mapped_column(String(32), primary_key=True, server_default=FetchedValue()) value: Mapped[str] = mapped_column(Text, nullable=False) @@ -1778,9 +1877,9 @@ class TapirString(Base): __tablename__ = "tapir_strings" __table_args__ = {"mysql_charset": "latin1"} - name: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False) - module: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False) - language: Mapped[str] = mapped_column(String(32), primary_key=True, nullable=False) + 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) @@ -1819,44 +1918,45 @@ class TapirUser(Base): 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 = 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["ArXivSubmissionLocks"]] = relationship("ArXivSubmissionLocks", back_populates="user") - arXiv_submission_view_flag = relationship("SubmissionViewFlag", 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 = relationship("PaperOwner", foreign_keys="[PaperOwner.user_id]", back_populates="owner") + 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" + __table_args__ = {"mysql_charset": "latin1"} 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) @@ -1865,13 +1965,13 @@ class AuthorIds(Base): 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")) + __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()) 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()) @@ -1892,11 +1992,18 @@ class Demographic(Base): 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'")) + 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] + # 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"), @@ -1908,14 +2015,10 @@ class Demographic(Base): ("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" + __table_args__ = {"mysql_charset": "utf8mb3"} 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) @@ -1925,15 +2028,17 @@ class OrcidIds(Base): class QueueView(Base): __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]] + 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" + __table_args__ = {"mysql_charset": "latin1"} 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()) @@ -1941,6 +2046,7 @@ class SuspiciousName(Base): class SwordLicense(Base): __tablename__ = "arXiv_sword_licenses" + __table_args__ = {"mysql_charset": "latin1"} user_id: Mapped[int] = mapped_column(ForeignKey("tapir_users.user_id"), primary_key=True) license: Mapped[Optional[str]] = mapped_column(String(127)) @@ -1949,21 +2055,23 @@ class SwordLicense(Base): class TapirDemographic(Base): __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()) 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()) 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" + __table_args__ = {"mysql_charset": "latin1"} 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()) @@ -1973,6 +2081,7 @@ class TapirUsersHot(Base): class TapirUsersPassword(Base): __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()) password_storage: Mapped[int] = mapped_column(Integer, nullable=False, server_default=FetchedValue()) @@ -1981,17 +2090,13 @@ class TapirUsersPassword(Base): user = relationship("TapirUser") -class ArXivSubmissionLocks(Base): +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), - ) + __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(Integer, nullable=False) - user_id: Mapped[int] = mapped_column(Integer, nullable=False, index=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) @@ -2001,10 +2106,11 @@ class ArXivSubmissionLocks(Base): 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": "utf8mb4"} + __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'")) @@ -2022,18 +2128,19 @@ class MembershipInstitutions(Base): # Student-lead membership dashboard class MembershipUsers(Base): __tablename__ = "membership_users" - __table_args__ = {"mysql_charset": "utf8mb4"} + __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" - __table_args__ = {"mysql_charset": "utf8mb4"} - paper_id: Mapped[str] = mapped_column(String(20), primary_key=True, nullable=False) + paper_id: Mapped[str] = mapped_column(String(20), primary_key=True) document_version: Mapped[intpk] # conversion_status codes: # - 0 = in progress @@ -2044,12 +2151,11 @@ class DBLaTeXMLDocuments(LaTeXMLBase): 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) + publish_dt: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True)) class DBLaTeXMLSubmissions(LaTeXMLBase): __tablename__ = "arXiv_latexml_sub" - __table_args__ = {"mysql_charset": "utf8mb4"} submission_id: Mapped[intpk] # conversion_status codes: @@ -2059,13 +2165,12 @@ class DBLaTeXMLSubmissions(LaTeXMLBase): 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) + conversion_start_time: Mapped[Optional[int]] + conversion_end_time: Mapped[Optional[int]] class DBLaTeXMLFeedback(LaTeXMLBase): __tablename__ = "feedback" - __table_args__ = {"mysql_charset": "utf8mb4"} id: Mapped[str] = mapped_column(String(40), primary_key=True) canonical_url: Mapped[Optional[str]] = mapped_column(String(255)) @@ -2086,7 +2191,7 @@ class CheckRoles(Base): """swimlanes: editor, student, moderator, qa""" __tablename__ = "arXiv_check_roles" - __table_args__ = {"mysql_charset": "utf8mb4"} + __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) @@ -2100,7 +2205,7 @@ 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": "utf8mb4"} + __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) @@ -2115,7 +2220,7 @@ class CheckTargets(Base): database metadata.""" __tablename__ = "arXiv_check_targets" - __table_args__ = {"mysql_charset": "utf8mb4"} + __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) @@ -2127,7 +2232,7 @@ def __repr__(self): class Checks(Base): __tablename__ = "arXiv_checks" - __table_args__ = {"mysql_charset": "utf8mb4"} + __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) @@ -2146,6 +2251,7 @@ class Checks(Base): 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 ''}" @@ -2153,50 +2259,50 @@ def __repr__(self): class CheckResults(Base): __tablename__ = "arXiv_check_results" + __table_args__ = {"mysql_charset": "latin1"} - check_result_id = Column(Integer, primary_key=True) - submission_id = Column(ForeignKey("arXiv_submissions.submission_id"), nullable=False, index=True) - data_version = Column(Integer, nullable=False, server_default=text("'0'")) - metadata_version = Column(Integer, 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, nullable=False) - created = Column(DateTime, nullable=False, server_default=func.now()) - message = Column(VARCHAR(40), nullable=True) - data = Column(VARCHAR(4000), nullable=True) + 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 """ - 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" + __table_args__ = {"mysql_charset": "latin1"} - check_response_id = Column(Integer, 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, nullable=False) - """If the related CheckResults ok==0, admin/mods respond with decision on whether that qa hold should stand or be dismissed.""" + 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") - persist_response = Column(Integer, nullable=False, server_default=text("'0'")) + 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. """ - 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}" diff --git a/arxiv/db/orig_models.py b/arxiv/db/orig_models.py index 395d1732c..4e216d2c6 100644 --- a/arxiv/db/orig_models.py +++ b/arxiv/db/orig_models.py @@ -1166,7 +1166,7 @@ class Submission(Base): # to arxiv check arXiv_check_results: Mapped[List["CheckResults"]] = relationship("CheckResults", back_populates="submission") # to submission locks - arXiv_submission_locks: Mapped[List["ArXivSubmissionLocks"]] = relationship("ArXivSubmissionLocks", back_populates="submission") + arXiv_submission_locks: Mapped[List["SubmissionLocks"]] = relationship("SubmissionLocks", back_populates="submission") class PilotDataset(Submission): @@ -1922,7 +1922,7 @@ class TapirUser(Base): 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["ArXivSubmissionLocks"]] = relationship("ArXivSubmissionLocks", 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") @@ -2061,7 +2061,7 @@ class TapirUsersPassword(Base): user = relationship('TapirUser') -class ArXivSubmissionLocks(Base): +class SubmissionLocks(Base): __tablename__ = 'arXiv_submission_locks' __table_args__ = ( ForeignKeyConstraint(['submission_id'], ['arXiv_submissions.submission_id'], name='arxiv_submission_locks_sub_fk'), diff --git a/arxiv/db/tests/test_db_schema.py b/arxiv/db/tests/test_db_schema.py index 63da365fb..252d68dd6 100644 --- a/arxiv/db/tests/test_db_schema.py +++ b/arxiv/db/tests/test_db_schema.py @@ -26,9 +26,16 @@ def _make_schemas(db_uri: str): 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") + print("db_uri is not defined. Bypassing the test") return _make_schemas(db_uri) diff --git a/development/README.md b/development/README.md index cd2531345..5c678d605 100644 --- a/development/README.md +++ b/development/README.md @@ -51,14 +51,14 @@ 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 arxvi/db/autogen_models.py +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 sqlacodegn modification is in development/sqlacodegen/ARXIV-README.md. +The details of sqlacodegen modification is in development/sqlacodegen/ARXIV-README.md. Here is the TL;DR of changes made to it: @@ -70,11 +70,11 @@ Here is the TL;DR of changes made to it: 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 +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](development/sqlacodegen/ARXIV-README.md). +[development/sqlacodegen/ARXIV-README.md](sqlacodegen/ARXIV-README.md). ### Merge autogen_models.py and orig_models.py @@ -88,7 +88,7 @@ This is how merge works: 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 if finds the matching class in latest, replace the assignments in the class. +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 @@ -107,7 +107,7 @@ the db_codegen.py again. It will show up. CST provides a tree traversing method that takes an object of Transformer (cst.CSTTransformer). -The tree travering invokes the member functions prefixed by "enter" and "leave". Using this, the transformer +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. diff --git a/development/arxiv_db_schema.sql b/development/arxiv_db_schema.sql index e3311cdd2..893d0a261 100644 --- a/development/arxiv_db_schema.sql +++ b/development/arxiv_db_schema.sql @@ -1,13 +1,13 @@ --- MySQL dump 10.13 Distrib 8.0.39, for Linux (x86_64) +-- MySQL dump 10.13 Distrib 5.7.20, for Linux (x86_64) -- --- Host: 127.0.0.1 Database: arXiv +-- Host: localhost Database: arXiv -- ------------------------------------------------------ --- Server version 5.7.44-google-log +-- 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 */; -/*!50503 SET NAMES utf8mb4 */; +/*!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 */; @@ -21,8 +21,7 @@ SET @@SESSION.SQL_LOG_BIN= 0; -- GTID state at the beginning of the backup -- -SET @@GLOBAL.GTID_PURGED=/*!80000 '+'*/ '2d19f914-b050-11e7-95e6-005056a34791:1-566477503, -c713b996-7f87-11ef-8e22-42010a5ee117:1-12'; +-- SET @@GLOBAL.GTID_PURGED='2d19f914-b050-11e7-95e6-005056a34791:1-572482257'; -- -- Table structure for table `Subscription_UniversalInstitution` @@ -30,7 +29,7 @@ c713b996-7f87-11ef-8e22-42010a5ee117:1-12'; DROP TABLE IF EXISTS `Subscription_UniversalInstitution`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `Subscription_UniversalInstitution` ( `resolver_URL` varchar(255) DEFAULT NULL, `name` varchar(255) NOT NULL, @@ -41,7 +40,7 @@ CREATE TABLE `Subscription_UniversalInstitution` ( `note` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`), KEY `name` (`name`) -) ENGINE=InnoDB AUTO_INCREMENT=479 DEFAULT CHARSET=utf8; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -50,7 +49,7 @@ CREATE TABLE `Subscription_UniversalInstitution` ( DROP TABLE IF EXISTS `Subscription_UniversalInstitutionContact`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `Subscription_UniversalInstitutionContact` ( `email` varchar(255) DEFAULT NULL, `sid` int(11) NOT NULL, @@ -62,7 +61,7 @@ CREATE TABLE `Subscription_UniversalInstitutionContact` ( 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=1485 DEFAULT CHARSET=utf8; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -71,7 +70,7 @@ CREATE TABLE `Subscription_UniversalInstitutionContact` ( DROP TABLE IF EXISTS `Subscription_UniversalInstitutionIP`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `Subscription_UniversalInstitutionIP` ( `sid` int(11) NOT NULL, `id` int(11) NOT NULL AUTO_INCREMENT, @@ -84,7 +83,7 @@ CREATE TABLE `Subscription_UniversalInstitutionIP` ( 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=21260 DEFAULT CHARSET=utf8; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -93,7 +92,7 @@ CREATE TABLE `Subscription_UniversalInstitutionIP` ( DROP TABLE IF EXISTS `arXiv_admin_log`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_admin_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, `logtime` varchar(24) DEFAULT NULL, @@ -112,7 +111,7 @@ CREATE TABLE `arXiv_admin_log` ( 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=37855801 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -121,7 +120,7 @@ CREATE TABLE `arXiv_admin_log` ( DROP TABLE IF EXISTS `arXiv_admin_metadata`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -153,7 +152,7 @@ CREATE TABLE `arXiv_admin_metadata` ( 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=136000 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -162,7 +161,7 @@ CREATE TABLE `arXiv_admin_metadata` ( DROP TABLE IF EXISTS `arXiv_admin_state`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -181,7 +180,7 @@ CREATE TABLE `arXiv_admin_state` ( DROP TABLE IF EXISTS `arXiv_archive_category`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_archive_category` ( `archive_id` varchar(16) NOT NULL DEFAULT '', `category_id` varchar(32) NOT NULL, @@ -195,7 +194,7 @@ CREATE TABLE `arXiv_archive_category` ( DROP TABLE IF EXISTS `arXiv_archive_def`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_archive_def` ( `archive` varchar(16) NOT NULL DEFAULT '', `name` varchar(255) DEFAULT NULL, @@ -209,7 +208,7 @@ CREATE TABLE `arXiv_archive_def` ( DROP TABLE IF EXISTS `arXiv_archive_group`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -223,7 +222,7 @@ CREATE TABLE `arXiv_archive_group` ( DROP TABLE IF EXISTS `arXiv_archives`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_archives` ( `archive_id` varchar(16) NOT NULL DEFAULT '', `in_group` varchar(16) NOT NULL DEFAULT '', @@ -243,7 +242,7 @@ CREATE TABLE `arXiv_archives` ( DROP TABLE IF EXISTS `arXiv_author_ids`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_author_ids` ( `user_id` int(4) unsigned NOT NULL, `author_id` varchar(50) NOT NULL, @@ -260,7 +259,7 @@ CREATE TABLE `arXiv_author_ids` ( DROP TABLE IF EXISTS `arXiv_aws_config`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_aws_config` ( `domain` varchar(75) NOT NULL, `keyname` varchar(60) NOT NULL, @@ -275,7 +274,7 @@ CREATE TABLE `arXiv_aws_config` ( DROP TABLE IF EXISTS `arXiv_aws_files`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_aws_files` ( `type` varchar(10) NOT NULL DEFAULT '', `filename` varchar(100) NOT NULL DEFAULT '', @@ -299,7 +298,7 @@ CREATE TABLE `arXiv_aws_files` ( DROP TABLE IF EXISTS `arXiv_bad_pw`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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`), @@ -313,7 +312,7 @@ CREATE TABLE `arXiv_bad_pw` ( DROP TABLE IF EXISTS `arXiv_bib_feeds`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -329,7 +328,7 @@ CREATE TABLE `arXiv_bib_feeds` ( `prune_regex` text, `enabled` tinyint(1) DEFAULT '0', PRIMARY KEY (`bib_id`) -) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -338,7 +337,7 @@ CREATE TABLE `arXiv_bib_feeds` ( DROP TABLE IF EXISTS `arXiv_bib_updates`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -347,7 +346,7 @@ CREATE TABLE `arXiv_bib_updates` ( `journal_ref` text, `doi` text, PRIMARY KEY (`update_id`) -) ENGINE=InnoDB AUTO_INCREMENT=796789 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -356,7 +355,7 @@ CREATE TABLE `arXiv_bib_updates` ( DROP TABLE IF EXISTS `arXiv_black_email`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_black_email` ( `pattern` varchar(64) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; @@ -368,7 +367,7 @@ CREATE TABLE `arXiv_black_email` ( DROP TABLE IF EXISTS `arXiv_block_email`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_block_email` ( `pattern` varchar(64) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; @@ -380,7 +379,7 @@ CREATE TABLE `arXiv_block_email` ( DROP TABLE IF EXISTS `arXiv_bogus_countries`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -394,7 +393,7 @@ CREATE TABLE `arXiv_bogus_countries` ( DROP TABLE IF EXISTS `arXiv_bogus_subject_class`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -409,7 +408,7 @@ CREATE TABLE `arXiv_bogus_subject_class` ( DROP TABLE IF EXISTS `arXiv_categories`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_categories` ( `archive` varchar(16) NOT NULL DEFAULT '', `subject_class` varchar(16) NOT NULL DEFAULT '', @@ -433,7 +432,7 @@ CREATE TABLE `arXiv_categories` ( DROP TABLE IF EXISTS `arXiv_category_def`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_category_def` ( `category` varchar(32) NOT NULL, `name` varchar(255) DEFAULT NULL, @@ -448,7 +447,7 @@ CREATE TABLE `arXiv_category_def` ( DROP TABLE IF EXISTS `arXiv_check_responses`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -471,13 +470,13 @@ CREATE TABLE `arXiv_check_responses` ( DROP TABLE IF EXISTS `arXiv_check_result_views`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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=4 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -486,7 +485,7 @@ CREATE TABLE `arXiv_check_result_views` ( DROP TABLE IF EXISTS `arXiv_check_results`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -505,7 +504,7 @@ CREATE TABLE `arXiv_check_results` ( 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=198669 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -514,13 +513,13 @@ CREATE TABLE `arXiv_check_results` ( DROP TABLE IF EXISTS `arXiv_check_roles`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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=6 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -529,13 +528,13 @@ CREATE TABLE `arXiv_check_roles` ( DROP TABLE IF EXISTS `arXiv_check_targets`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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=5 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -544,7 +543,7 @@ CREATE TABLE `arXiv_check_targets` ( DROP TABLE IF EXISTS `arXiv_checks`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -565,7 +564,7 @@ CREATE TABLE `arXiv_checks` ( 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=28 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -574,7 +573,7 @@ CREATE TABLE `arXiv_checks` ( DROP TABLE IF EXISTS `arXiv_control_holds`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -595,7 +594,7 @@ CREATE TABLE `arXiv_control_holds` ( 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=114 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -604,7 +603,7 @@ CREATE TABLE `arXiv_control_holds` ( DROP TABLE IF EXISTS `arXiv_cross_control`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -636,7 +635,7 @@ CREATE TABLE `arXiv_cross_control` ( DROP TABLE IF EXISTS `arXiv_datacite_dois`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_datacite_dois` ( `doi` varchar(255) NOT NULL, `account` enum('test','prod') DEFAULT NULL, @@ -657,7 +656,7 @@ CREATE TABLE `arXiv_datacite_dois` ( DROP TABLE IF EXISTS `arXiv_dblp`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_dblp` ( `document_id` mediumint(8) unsigned NOT NULL DEFAULT '0', `url` varchar(80) DEFAULT NULL, @@ -672,14 +671,14 @@ CREATE TABLE `arXiv_dblp` ( DROP TABLE IF EXISTS `arXiv_dblp_authors`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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=16777215 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -688,7 +687,7 @@ CREATE TABLE `arXiv_dblp_authors` ( DROP TABLE IF EXISTS `arXiv_dblp_document_authors`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -707,7 +706,7 @@ CREATE TABLE `arXiv_dblp_document_authors` ( DROP TABLE IF EXISTS `arXiv_demographics`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -761,7 +760,7 @@ CREATE TABLE `arXiv_demographics` ( DROP TABLE IF EXISTS `arXiv_document_category`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -780,7 +779,7 @@ CREATE TABLE `arXiv_document_category` ( DROP TABLE IF EXISTS `arXiv_documents`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -798,7 +797,7 @@ CREATE TABLE `arXiv_documents` ( 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=2614028 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -807,7 +806,7 @@ CREATE TABLE `arXiv_documents` ( DROP TABLE IF EXISTS `arXiv_duplicates`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_duplicates` ( `user_id` int(10) unsigned NOT NULL DEFAULT '0', `email` varchar(255) DEFAULT NULL, @@ -823,7 +822,7 @@ CREATE TABLE `arXiv_duplicates` ( DROP TABLE IF EXISTS `arXiv_endorsement_domains`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -840,7 +839,7 @@ CREATE TABLE `arXiv_endorsement_domains` ( DROP TABLE IF EXISTS `arXiv_endorsement_requests`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -857,7 +856,7 @@ CREATE TABLE `arXiv_endorsement_requests` ( 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=289081 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -866,7 +865,7 @@ CREATE TABLE `arXiv_endorsement_requests` ( DROP TABLE IF EXISTS `arXiv_endorsement_requests_audit`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -884,7 +883,7 @@ CREATE TABLE `arXiv_endorsement_requests_audit` ( DROP TABLE IF EXISTS `arXiv_endorsements`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -906,7 +905,7 @@ CREATE TABLE `arXiv_endorsements` ( 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=1093533 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -915,7 +914,7 @@ CREATE TABLE `arXiv_endorsements` ( DROP TABLE IF EXISTS `arXiv_endorsements_audit`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -936,7 +935,7 @@ CREATE TABLE `arXiv_endorsements_audit` ( DROP TABLE IF EXISTS `arXiv_freeze_log`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_freeze_log` ( `date` int(10) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`date`) @@ -949,7 +948,7 @@ CREATE TABLE `arXiv_freeze_log` ( DROP TABLE IF EXISTS `arXiv_group_def`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_group_def` ( `archive_group` varchar(16) NOT NULL DEFAULT '', `name` varchar(255) DEFAULT NULL, @@ -963,7 +962,7 @@ CREATE TABLE `arXiv_group_def` ( DROP TABLE IF EXISTS `arXiv_groups`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_groups` ( `group_id` varchar(16) NOT NULL DEFAULT '', `group_name` varchar(255) NOT NULL DEFAULT '', @@ -978,7 +977,7 @@ CREATE TABLE `arXiv_groups` ( DROP TABLE IF EXISTS `arXiv_in_category`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -998,7 +997,7 @@ CREATE TABLE `arXiv_in_category` ( DROP TABLE IF EXISTS `arXiv_jref_control`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -1026,7 +1025,7 @@ CREATE TABLE `arXiv_jref_control` ( DROP TABLE IF EXISTS `arXiv_licenses`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_licenses` ( `name` varchar(255) NOT NULL, `label` varchar(255) DEFAULT NULL, @@ -1043,7 +1042,7 @@ CREATE TABLE `arXiv_licenses` ( DROP TABLE IF EXISTS `arXiv_log_positions`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_log_positions` ( `id` varchar(255) NOT NULL DEFAULT '', `position` int(10) unsigned DEFAULT NULL, @@ -1058,7 +1057,7 @@ CREATE TABLE `arXiv_log_positions` ( DROP TABLE IF EXISTS `arXiv_metadata`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -1095,7 +1094,7 @@ CREATE TABLE `arXiv_metadata` ( 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=4134837 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -1104,7 +1103,7 @@ CREATE TABLE `arXiv_metadata` ( DROP TABLE IF EXISTS `arXiv_mirror_list`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_mirror_list` ( `mirror_list_id` int(11) NOT NULL AUTO_INCREMENT, `created` datetime DEFAULT NULL, @@ -1117,7 +1116,7 @@ CREATE TABLE `arXiv_mirror_list` ( 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=584251 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -1126,7 +1125,7 @@ CREATE TABLE `arXiv_mirror_list` ( DROP TABLE IF EXISTS `arXiv_moderator_api_key`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -1145,7 +1144,7 @@ CREATE TABLE `arXiv_moderator_api_key` ( DROP TABLE IF EXISTS `arXiv_moderators`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -1172,7 +1171,7 @@ CREATE TABLE `arXiv_moderators` ( DROP TABLE IF EXISTS `arXiv_monitor_klog`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -1186,7 +1185,7 @@ CREATE TABLE `arXiv_monitor_klog` ( DROP TABLE IF EXISTS `arXiv_monitor_mailq`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -1205,7 +1204,7 @@ CREATE TABLE `arXiv_monitor_mailq` ( DROP TABLE IF EXISTS `arXiv_monitor_mailsent`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -1219,7 +1218,7 @@ CREATE TABLE `arXiv_monitor_mailsent` ( DROP TABLE IF EXISTS `arXiv_next_mail`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -1233,7 +1232,7 @@ CREATE TABLE `arXiv_next_mail` ( 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=3680904 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -1242,7 +1241,7 @@ CREATE TABLE `arXiv_next_mail` ( DROP TABLE IF EXISTS `arXiv_orcid_config`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_orcid_config` ( `domain` varchar(75) NOT NULL, `keyname` varchar(60) NOT NULL, @@ -1257,7 +1256,7 @@ CREATE TABLE `arXiv_orcid_config` ( DROP TABLE IF EXISTS `arXiv_orcid_ids`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_orcid_ids` ( `user_id` int(4) unsigned NOT NULL, `orcid` varchar(19) NOT NULL, @@ -1275,7 +1274,7 @@ CREATE TABLE `arXiv_orcid_ids` ( DROP TABLE IF EXISTS `arXiv_ownership_requests`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -1286,7 +1285,7 @@ CREATE TABLE `arXiv_ownership_requests` ( 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=62120 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -1295,7 +1294,7 @@ CREATE TABLE `arXiv_ownership_requests` ( DROP TABLE IF EXISTS `arXiv_ownership_requests_audit`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -1314,7 +1313,7 @@ CREATE TABLE `arXiv_ownership_requests_audit` ( DROP TABLE IF EXISTS `arXiv_ownership_requests_papers`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -1329,7 +1328,7 @@ CREATE TABLE `arXiv_ownership_requests_papers` ( DROP TABLE IF EXISTS `arXiv_paper_owners`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -1356,7 +1355,7 @@ CREATE TABLE `arXiv_paper_owners` ( DROP TABLE IF EXISTS `arXiv_paper_pw`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -1372,7 +1371,7 @@ CREATE TABLE `arXiv_paper_pw` ( DROP TABLE IF EXISTS `arXiv_paper_sessions`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -1380,7 +1379,7 @@ CREATE TABLE `arXiv_paper_sessions` ( `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=233482 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -1389,7 +1388,7 @@ CREATE TABLE `arXiv_paper_sessions` ( DROP TABLE IF EXISTS `arXiv_pilot_datasets`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_pilot_datasets` ( `submission_id` int(11) NOT NULL, `numfiles` smallint(4) unsigned DEFAULT '0', @@ -1409,7 +1408,7 @@ CREATE TABLE `arXiv_pilot_datasets` ( DROP TABLE IF EXISTS `arXiv_pilot_files`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -1420,7 +1419,7 @@ CREATE TABLE `arXiv_pilot_files` ( 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=3080 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -1429,7 +1428,7 @@ CREATE TABLE `arXiv_pilot_files` ( DROP TABLE IF EXISTS `arXiv_publish_log`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_publish_log` ( `date` int(10) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`date`) @@ -1442,7 +1441,7 @@ CREATE TABLE `arXiv_publish_log` ( DROP TABLE IF EXISTS `arXiv_questionable_categories`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_questionable_categories` ( `archive` varchar(16) NOT NULL DEFAULT '', `subject_class` varchar(16) NOT NULL DEFAULT '', @@ -1457,7 +1456,7 @@ CREATE TABLE `arXiv_questionable_categories` ( DROP TABLE IF EXISTS `arXiv_queue_view`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -1474,7 +1473,7 @@ CREATE TABLE `arXiv_queue_view` ( DROP TABLE IF EXISTS `arXiv_refresh_list`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_refresh_list` ( `filename` varchar(255) DEFAULT NULL, `mtime` int(10) unsigned DEFAULT NULL, @@ -1488,7 +1487,7 @@ CREATE TABLE `arXiv_refresh_list` ( DROP TABLE IF EXISTS `arXiv_reject_session_usernames`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_reject_session_usernames` ( `username` varchar(64) NOT NULL DEFAULT '', PRIMARY KEY (`username`) @@ -1501,7 +1500,7 @@ CREATE TABLE `arXiv_reject_session_usernames` ( DROP TABLE IF EXISTS `arXiv_sciencewise_pings`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_sciencewise_pings` ( `paper_id_v` varchar(32) NOT NULL, `updated` datetime DEFAULT NULL, @@ -1515,7 +1514,7 @@ CREATE TABLE `arXiv_sciencewise_pings` ( DROP TABLE IF EXISTS `arXiv_show_email_requests`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -1533,7 +1532,7 @@ CREATE TABLE `arXiv_show_email_requests` ( 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=1982787 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -1542,7 +1541,7 @@ CREATE TABLE `arXiv_show_email_requests` ( DROP TABLE IF EXISTS `arXiv_state`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_state` ( `id` int(11) NOT NULL, `name` varchar(24) DEFAULT NULL, @@ -1557,7 +1556,7 @@ CREATE TABLE `arXiv_state` ( DROP TABLE IF EXISTS `arXiv_stats_hourly`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_stats_hourly` ( `ymd` date NOT NULL, `hour` tinyint(3) unsigned NOT NULL, @@ -1577,7 +1576,7 @@ CREATE TABLE `arXiv_stats_hourly` ( DROP TABLE IF EXISTS `arXiv_stats_monthly_downloads`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_stats_monthly_downloads` ( `ym` date NOT NULL, `downloads` int(10) unsigned NOT NULL, @@ -1591,7 +1590,7 @@ CREATE TABLE `arXiv_stats_monthly_downloads` ( DROP TABLE IF EXISTS `arXiv_stats_monthly_submissions`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -1606,7 +1605,7 @@ CREATE TABLE `arXiv_stats_monthly_submissions` ( DROP TABLE IF EXISTS `arXiv_submission_abs_classifier_data`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_submission_abs_classifier_data` ( `submission_id` int(11) NOT NULL DEFAULT '0', `json` text, @@ -1631,14 +1630,14 @@ CREATE TABLE `arXiv_submission_abs_classifier_data` ( DROP TABLE IF EXISTS `arXiv_submission_agreements`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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=4 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -1647,7 +1646,7 @@ CREATE TABLE `arXiv_submission_agreements` ( DROP TABLE IF EXISTS `arXiv_submission_category`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_submission_category` ( `submission_id` int(11) NOT NULL, `category` varchar(32) NOT NULL DEFAULT '', @@ -1669,7 +1668,7 @@ CREATE TABLE `arXiv_submission_category` ( DROP TABLE IF EXISTS `arXiv_submission_category_proposal`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -1693,7 +1692,7 @@ CREATE TABLE `arXiv_submission_category_proposal` ( 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=467577 DEFAULT CHARSET=utf8; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -1702,7 +1701,7 @@ CREATE TABLE `arXiv_submission_category_proposal` ( DROP TABLE IF EXISTS `arXiv_submission_classifier_data`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_submission_classifier_data` ( `submission_id` int(11) NOT NULL DEFAULT '0', `json` text, @@ -1721,7 +1720,7 @@ CREATE TABLE `arXiv_submission_classifier_data` ( DROP TABLE IF EXISTS `arXiv_submission_control`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -1751,19 +1750,20 @@ CREATE TABLE `arXiv_submission_control` ( DROP TABLE IF EXISTS `arXiv_submission_flag`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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=662304 DEFAULT CHARSET=utf8; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -1772,7 +1772,7 @@ CREATE TABLE `arXiv_submission_flag` ( DROP TABLE IF EXISTS `arXiv_submission_hold_reason`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -1787,7 +1787,7 @@ CREATE TABLE `arXiv_submission_hold_reason` ( 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=114140 DEFAULT CHARSET=utf8; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -1796,7 +1796,7 @@ CREATE TABLE `arXiv_submission_hold_reason` ( DROP TABLE IF EXISTS `arXiv_submission_locks`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -1810,7 +1810,7 @@ CREATE TABLE `arXiv_submission_locks` ( 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=64547 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -1819,7 +1819,7 @@ CREATE TABLE `arXiv_submission_locks` ( DROP TABLE IF EXISTS `arXiv_submission_near_duplicates`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -1837,7 +1837,7 @@ CREATE TABLE `arXiv_submission_near_duplicates` ( DROP TABLE IF EXISTS `arXiv_submission_qa_reports`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -1859,7 +1859,7 @@ CREATE TABLE `arXiv_submission_qa_reports` ( DROP TABLE IF EXISTS `arXiv_submission_view_flag`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_submission_view_flag` ( `submission_id` int(11) NOT NULL, `flag` tinyint(1) DEFAULT '0', @@ -1878,7 +1878,7 @@ CREATE TABLE `arXiv_submission_view_flag` ( DROP TABLE IF EXISTS `arXiv_submissions`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -1952,7 +1952,7 @@ CREATE TABLE `arXiv_submissions` ( 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=5982750 DEFAULT CHARSET=utf8; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -1961,7 +1961,7 @@ CREATE TABLE `arXiv_submissions` ( DROP TABLE IF EXISTS `arXiv_submitter_flags`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_submitter_flags` ( `flag_id` int(11) NOT NULL, `comment` varchar(255) DEFAULT NULL, @@ -1976,7 +1976,7 @@ CREATE TABLE `arXiv_submitter_flags` ( DROP TABLE IF EXISTS `arXiv_suspect_emails`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_suspect_emails` ( `id` int(11) NOT NULL AUTO_INCREMENT, `type` varchar(10) NOT NULL, @@ -1984,7 +1984,7 @@ CREATE TABLE `arXiv_suspect_emails` ( `comment` text NOT NULL, `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=309 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -1993,7 +1993,7 @@ CREATE TABLE `arXiv_suspect_emails` ( DROP TABLE IF EXISTS `arXiv_suspicious_names`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -2008,7 +2008,7 @@ CREATE TABLE `arXiv_suspicious_names` ( DROP TABLE IF EXISTS `arXiv_sword_licenses`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_sword_licenses` ( `user_id` int(4) unsigned NOT NULL, `license` varchar(127) DEFAULT NULL, @@ -2024,7 +2024,7 @@ CREATE TABLE `arXiv_sword_licenses` ( DROP TABLE IF EXISTS `arXiv_titles`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_titles` ( `paper_id` varchar(64) NOT NULL, `title` varchar(255) DEFAULT NULL, @@ -2042,7 +2042,7 @@ CREATE TABLE `arXiv_titles` ( DROP TABLE IF EXISTS `arXiv_top_papers`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -2061,7 +2061,7 @@ CREATE TABLE `arXiv_top_papers` ( DROP TABLE IF EXISTS `arXiv_trackback_pings`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -2082,7 +2082,7 @@ CREATE TABLE `arXiv_trackback_pings` ( KEY `arXiv_trackback_pings__url` (`url`), KEY `arXiv_trackback_pings__posted_date` (`posted_date`), KEY `arXiv_trackback_pings__status` (`status`) -) ENGINE=InnoDB AUTO_INCREMENT=1868954 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -2091,14 +2091,14 @@ CREATE TABLE `arXiv_trackback_pings` ( DROP TABLE IF EXISTS `arXiv_trackback_sites`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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=1051 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -2107,7 +2107,7 @@ CREATE TABLE `arXiv_trackback_sites` ( DROP TABLE IF EXISTS `arXiv_tracking`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -2116,7 +2116,7 @@ CREATE TABLE `arXiv_tracking` ( `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`tracking_id`), UNIQUE KEY `sword_id` (`sword_id`) -) ENGINE=InnoDB AUTO_INCREMENT=73104 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -2125,7 +2125,7 @@ CREATE TABLE `arXiv_tracking` ( DROP TABLE IF EXISTS `arXiv_updates`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_updates` ( `document_id` int(11) DEFAULT NULL, `version` int(4) NOT NULL DEFAULT '1', @@ -2147,7 +2147,7 @@ CREATE TABLE `arXiv_updates` ( DROP TABLE IF EXISTS `arXiv_updates_tmp`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_updates_tmp` ( `document_id` int(11) DEFAULT NULL, `date` date DEFAULT NULL, @@ -2163,7 +2163,7 @@ CREATE TABLE `arXiv_updates_tmp` ( DROP TABLE IF EXISTS `arXiv_versions`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -2185,7 +2185,7 @@ CREATE TABLE `arXiv_versions` ( DROP TABLE IF EXISTS `arXiv_versions_checksum`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -2210,7 +2210,7 @@ CREATE TABLE `arXiv_versions_checksum` ( DROP TABLE IF EXISTS `arXiv_white_email`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `arXiv_white_email` ( `pattern` varchar(64) DEFAULT NULL, UNIQUE KEY `uc_pattern` (`pattern`) @@ -2223,7 +2223,7 @@ CREATE TABLE `arXiv_white_email` ( DROP TABLE IF EXISTS `arXiv_xml_notifications`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -2241,7 +2241,7 @@ CREATE TABLE `arXiv_xml_notifications` ( DROP TABLE IF EXISTS `dbix_class_schema_versions`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `dbix_class_schema_versions` ( `version` varchar(10) NOT NULL, `installed` varchar(20) NOT NULL, @@ -2255,7 +2255,7 @@ CREATE TABLE `dbix_class_schema_versions` ( DROP TABLE IF EXISTS `demographics_backup`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -2289,7 +2289,7 @@ CREATE TABLE `demographics_backup` ( DROP TABLE IF EXISTS `membership_institutions`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `membership_institutions` ( `sid` int(11) NOT NULL, `name` varchar(256) DEFAULT NULL, @@ -2313,13 +2313,13 @@ CREATE TABLE `membership_institutions` ( DROP TABLE IF EXISTS `membership_users`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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=23 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -2328,7 +2328,7 @@ CREATE TABLE `membership_users` ( DROP TABLE IF EXISTS `sessions`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `sessions` ( `id` char(72) NOT NULL, `session_data` text, @@ -2343,7 +2343,7 @@ CREATE TABLE `sessions` ( DROP TABLE IF EXISTS `tapir_address`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -2371,7 +2371,7 @@ CREATE TABLE `tapir_address` ( DROP TABLE IF EXISTS `tapir_admin_audit`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -2396,7 +2396,7 @@ CREATE TABLE `tapir_admin_audit` ( 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=290626 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -2405,7 +2405,7 @@ CREATE TABLE `tapir_admin_audit` ( DROP TABLE IF EXISTS `tapir_countries`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `tapir_countries` ( `digraph` char(2) NOT NULL DEFAULT '', `country_name` varchar(255) NOT NULL DEFAULT '', @@ -2420,7 +2420,7 @@ CREATE TABLE `tapir_countries` ( DROP TABLE IF EXISTS `tapir_demographics`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -2445,7 +2445,7 @@ CREATE TABLE `tapir_demographics` ( DROP TABLE IF EXISTS `tapir_email_change_tokens`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -2472,7 +2472,7 @@ CREATE TABLE `tapir_email_change_tokens` ( DROP TABLE IF EXISTS `tapir_email_change_tokens_used`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -2493,7 +2493,7 @@ CREATE TABLE `tapir_email_change_tokens_used` ( DROP TABLE IF EXISTS `tapir_email_headers`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -2509,7 +2509,7 @@ CREATE TABLE `tapir_email_headers` ( DROP TABLE IF EXISTS `tapir_email_log`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -2521,7 +2521,7 @@ CREATE TABLE `tapir_email_log` ( `template_id` int(10) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`mail_id`), KEY `mailing_id` (`mailing_id`) -) ENGINE=InnoDB AUTO_INCREMENT=1330693 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -2530,7 +2530,7 @@ CREATE TABLE `tapir_email_log` ( DROP TABLE IF EXISTS `tapir_email_mailings`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -2557,7 +2557,7 @@ CREATE TABLE `tapir_email_mailings` ( DROP TABLE IF EXISTS `tapir_email_templates`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -2577,7 +2577,7 @@ CREATE TABLE `tapir_email_templates` ( 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=16 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -2586,7 +2586,7 @@ CREATE TABLE `tapir_email_templates` ( DROP TABLE IF EXISTS `tapir_email_tokens`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -2608,7 +2608,7 @@ CREATE TABLE `tapir_email_tokens` ( DROP TABLE IF EXISTS `tapir_email_tokens_used`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -2629,7 +2629,7 @@ CREATE TABLE `tapir_email_tokens_used` ( DROP TABLE IF EXISTS `tapir_error_log`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -2655,7 +2655,7 @@ CREATE TABLE `tapir_error_log` ( DROP TABLE IF EXISTS `tapir_integer_variables`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -2669,7 +2669,7 @@ CREATE TABLE `tapir_integer_variables` ( DROP TABLE IF EXISTS `tapir_nicknames`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -2686,7 +2686,7 @@ CREATE TABLE `tapir_nicknames` ( KEY `role` (`role`), KEY `policy` (`policy`), CONSTRAINT `0_570` FOREIGN KEY (`user_id`) REFERENCES `tapir_users` (`user_id`) -) ENGINE=InnoDB AUTO_INCREMENT=1031816 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -2695,7 +2695,7 @@ CREATE TABLE `tapir_nicknames` ( DROP TABLE IF EXISTS `tapir_nicknames_audit`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -2715,7 +2715,7 @@ CREATE TABLE `tapir_nicknames_audit` ( DROP TABLE IF EXISTS `tapir_no_cookies`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -2732,7 +2732,7 @@ CREATE TABLE `tapir_no_cookies` ( DROP TABLE IF EXISTS `tapir_periodic_tasks_log`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `tapir_periodic_tasks_log` ( `t` int(4) unsigned NOT NULL DEFAULT '0', `entry` text, @@ -2746,7 +2746,7 @@ CREATE TABLE `tapir_periodic_tasks_log` ( DROP TABLE IF EXISTS `tapir_permanent_tokens`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -2768,7 +2768,7 @@ CREATE TABLE `tapir_permanent_tokens` ( DROP TABLE IF EXISTS `tapir_permanent_tokens_used`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -2789,7 +2789,7 @@ CREATE TABLE `tapir_permanent_tokens_used` ( DROP TABLE IF EXISTS `tapir_phone`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -2808,7 +2808,7 @@ CREATE TABLE `tapir_phone` ( DROP TABLE IF EXISTS `tapir_policy_classes`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -2817,7 +2817,7 @@ CREATE TABLE `tapir_policy_classes` ( `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=4 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -2826,7 +2826,7 @@ CREATE TABLE `tapir_policy_classes` ( DROP TABLE IF EXISTS `tapir_presessions`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -2834,7 +2834,7 @@ CREATE TABLE `tapir_presessions` ( `tracking_cookie` varchar(255) NOT NULL DEFAULT '', `created_at` int(4) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`presession_id`) -) ENGINE=InnoDB AUTO_INCREMENT=442 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -2843,7 +2843,7 @@ CREATE TABLE `tapir_presessions` ( DROP TABLE IF EXISTS `tapir_recovery_tokens`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -2865,7 +2865,7 @@ CREATE TABLE `tapir_recovery_tokens` ( DROP TABLE IF EXISTS `tapir_recovery_tokens_used`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -2886,7 +2886,7 @@ CREATE TABLE `tapir_recovery_tokens_used` ( DROP TABLE IF EXISTS `tapir_save_post_variables`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -2903,7 +2903,7 @@ CREATE TABLE `tapir_save_post_variables` ( DROP TABLE IF EXISTS `tapir_sessions`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -2915,7 +2915,7 @@ CREATE TABLE `tapir_sessions` ( 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=22747905 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -2924,7 +2924,7 @@ CREATE TABLE `tapir_sessions` ( DROP TABLE IF EXISTS `tapir_sessions_audit`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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 '', @@ -2943,7 +2943,7 @@ CREATE TABLE `tapir_sessions_audit` ( DROP TABLE IF EXISTS `tapir_string_variables`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `tapir_string_variables` ( `variable_id` varchar(32) NOT NULL DEFAULT '', `value` text NOT NULL, @@ -2957,7 +2957,7 @@ CREATE TABLE `tapir_string_variables` ( DROP TABLE IF EXISTS `tapir_strings`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!40101 SET character_set_client = utf8 */; CREATE TABLE `tapir_strings` ( `name` varchar(32) NOT NULL DEFAULT '', `module` varchar(32) NOT NULL DEFAULT '', @@ -2973,7 +2973,7 @@ CREATE TABLE `tapir_strings` ( DROP TABLE IF EXISTS `tapir_users`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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, @@ -3015,7 +3015,7 @@ CREATE TABLE `tapir_users` ( 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=1085901 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -3024,7 +3024,7 @@ CREATE TABLE `tapir_users` ( DROP TABLE IF EXISTS `tapir_users_hot`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -3044,7 +3044,7 @@ CREATE TABLE `tapir_users_hot` ( DROP TABLE IF EXISTS `tapir_users_password`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!50503 SET character_set_client = utf8mb4 */; +/*!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', @@ -3064,4 +3064,4 @@ SET @@SESSION.SQL_LOG_BIN = @MYSQLDUMP_TEMP_LOG_BIN; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2024-11-06 12:59:37 +-- 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 < cst.CSTNode: @@ -448,7 +453,7 @@ def is_port_open(host: str, port: int): def run_mysql_container(port: int): """Start a mysql docker""" - mysql_image = "mysql:5.7" + mysql_image = "mysql:5.7.20" try: subprocess.run(["docker", "pull", mysql_image], check=True) diff --git a/development/load_arxiv_db_schema.py b/development/load_arxiv_db_schema.py index 697cc62b7..6de63eb7c 100644 --- a/development/load_arxiv_db_schema.py +++ b/development/load_arxiv_db_schema.py @@ -1,65 +1,32 @@ #!/usr/bin/python3 import os import sys -import socket 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 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 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", "kill", container_name], check=False) - 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)}") - -def main() -> None: - mysql_port = 13306 - db_name = "arxiv" - conn_argv = [f"--port={mysql_port}", "-h", "127.0.0.1", "-u", "root", "-ptestpassword", "--ssl-mode=DISABLED"] +def main(mysql_port: int, db_name: str, root_password: str="rootpassword", schema_sql: str="arxiv_db_schema.sql") -> None: + conn_argv = [f"--port={mysql_port}", "-h", "127.0.0.1", "-u", "root", f"--password={root_password}"] 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) + 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) + stdin=subprocess.PIPE, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) mysql.communicate("select 1") if mysql.returncode == 0: break @@ -68,10 +35,57 @@ def main() -> None: pass time.sleep(1) - with open("arxiv_db_schema.sql") as schema_file: - subprocess.call(cli, stdin=schema_file) + 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__": """ """ - 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", + ) + + 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) diff --git a/development/populate_arxiv_db.py b/development/populate_arxiv_db.py index 0987a3ac8..24da30ba0 100644 --- a/development/populate_arxiv_db.py +++ b/development/populate_arxiv_db.py @@ -1,4 +1,15 @@ #!/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 @@ -9,6 +20,9 @@ import socket import subprocess import logging +import time +import shlex +import argparse logging.basicConfig(level=logging.INFO) @@ -44,41 +58,76 @@ def _make_schemas(db_engine: Engine): def run_mysql_container(port: int, container_name="mysql-test", db_name="testdb"): """Start a mysql docker""" - mysql_image = "mysql:5.7" + 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(["docker", "pull", mysql_image], check=True) - - subprocess.run( - [ - "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 - ], - check=True - ) + subprocess.run(argv, check=True) logging.info("MySQL Docker container started successfully.") except subprocess.CalledProcessError as e: - logging.error(f"Error: {e}") + logging.error(f"Error: {e}\n\n{shlex.join(argv)}") except Exception as e: - logging.error(f"Unexpected error: {e}") + logging.error(f"Unexpected error: {e}\n\n{shlex.join(argv)}") -def main() -> None: - mysql_port = 13306 - db_name = "arxiv" + 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) - 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) - for _ in range(20): - if is_port_open("127.0.0.1", mysql_port): + +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 - time.sleep(1) - + 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) @@ -98,11 +147,41 @@ def main() -> None: _make_schemas(db_engine) with open("schema-from-arxiv-db-model.sql", "w", encoding="utf-8") as sql_file: - subprocess.run(["mysqldump", "-h", "127.0.0.1", "--port", str(mysql_port), "-u", "root", "-ptestpassword", "--no-data", db_name], + subprocess.run(["mysqldump"] + conn_argv + ["--no-data", db_name], stdout=sql_file, check=True) if __name__ == "__main__": - """ - """ - 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..0db3fa40c --- /dev/null +++ b/development/run_mysql_container.py @@ -0,0 +1,121 @@ +#!/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" + + 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 + ] + + 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) -> None: + conn_argv = [f"--port={mysql_port}", "-h", "127.0.0.1", "-u", "root", f"--password={root_password}"] + + 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", + ) + + 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) diff --git a/development/sqlacodegen/ARXIV-README.md b/development/sqlacodegen/ARXIV-README.md index 390eb7519..b99b1f9d8 100644 --- a/development/sqlacodegen/ARXIV-README.md +++ b/development/sqlacodegen/ARXIV-README.md @@ -3,10 +3,10 @@ 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 sqlacoden allows the +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 sqlacodeden runs, the model's class names are derived from the table name. This is not true +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 @@ -27,6 +27,10 @@ There are 7 features added to sqlacodegen. 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. @@ -50,6 +54,8 @@ This is an example of metadata for a table. ### Definition of metadata +For table model class: + TABLE_NAME: class_name: @@ -66,11 +72,26 @@ This is an example of metadata for a table. 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: @@ -83,6 +104,36 @@ 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 diff --git a/development/sqlacodegen/src/sqlacodegen/generators.py b/development/sqlacodegen/src/sqlacodegen/generators.py index 7d870a06b..23808b334 100644 --- a/development/sqlacodegen/src/sqlacodegen/generators.py +++ b/development/sqlacodegen/src/sqlacodegen/generators.py @@ -159,6 +159,15 @@ def get_arg_override(self, table: Table, keyword: str, default: str | None) -> s 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: @@ -1247,6 +1256,7 @@ def render_class_variables(self, model: ModelClass, indexed_columns: set) -> str # 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}") 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 From 4f2fdb6896cb834449df449c3855ccdb6902da26 Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Wed, 11 Dec 2024 10:57:19 -0500 Subject: [PATCH 22/32] Remove the noisy logging. --- arxiv/auth/conftest.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arxiv/auth/conftest.py b/arxiv/auth/conftest.py index 8d18c6f0a..8f3fa7bd3 100644 --- a/arxiv/auth/conftest.py +++ b/arxiv/auth/conftest.py @@ -92,11 +92,11 @@ def classic_db_engine(db_uri): if targets: 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" + # debug_sql = "SHOW PROCESSLIST;\nSELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;\n" sql = "\n".join(statements) mysql = subprocess.Popen(my_sql_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, encoding="utf-8") try: - logger.info(debug_sql + sql) + logger.info(sql) out, err = mysql.communicate(sql, timeout=9999) if out: logger.info(out) @@ -112,13 +112,14 @@ def classic_db_engine(db_uri): 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 ]) - logger.info(kill_conn) mysql = subprocess.Popen(my_sql_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, encoding="utf-8") mysql.communicate(kill_conn) db_engine.dispose() From f9c877924c1efa16b28f53a391539bd1f2dee8c0 Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Wed, 11 Dec 2024 14:55:11 -0500 Subject: [PATCH 23/32] Tests run without bruteforce connection killing. Pup back MySQL 5.7.20 for testing and not use SSL. --- .github/workflows/pullreqeust_tests.yaml | 32 +++++++-------- arxiv/auth/conftest.py | 51 +++++++++++++++--------- arxiv/auth/legacy/tests/test_accounts.py | 10 ++--- development/load_arxiv_db_schema.py | 14 ++++++- development/run_mysql_container.py | 19 +++++++-- 5 files changed, 79 insertions(+), 47 deletions(-) diff --git a/.github/workflows/pullreqeust_tests.yaml b/.github/workflows/pullreqeust_tests.yaml index b445722a5..e5c810f8c 100644 --- a/.github/workflows/pullreqeust_tests.yaml +++ b/.github/workflows/pullreqeust_tests.yaml @@ -7,11 +7,11 @@ jobs: runs-on: ubuntu-latest services: mysql: - image: mysql:8.0 + image: mysql:5.7.20 ports: - - 3306:3306 + - 23306:3306 env: - MYSQL_ROOT_PASSWORD: password + MYSQL_ROOT_PASSWORD: rootpassword MYSQL_DATABASE: testdb MYSQL_USER: testuser MYSQL_PASSWORD: testpassword @@ -29,34 +29,34 @@ jobs: poetry --version # Check if poetry lock file is current with pyproject.toml poetry check --lock - poetry install --with=dev + poetry install --quiet --with=dev + + - name: Load db schema + run: | + sudo apt update + sudo apt install -y mysql-client + poetry run python development/load_arxiv_db_schema.py --db_name=testdb --db_port=23306 --root_password=rootpassword --schema=development/arxiv_db_schema.sql + - name: Run arxiv-base tests with coverage run: poetry run pytest --cov=arxiv.base fourohfour --cov-fail-under=67 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 + # It needs to be non-Snap binary and thus it's from Mozilla PPA. - name: Install Firefox ESR, test driver, mysqladmin run: | sudo add-apt-repository -y ppa:mozillateam/ppa sudo apt update sudo apt install -y firefox-esr mysql-client-core-8.0 - 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: Wait for MySQL to be ready - run: | - until mysqladmin ping --host=127.0.0.1 --user=testuser --password=testpassword --silent; do - echo "Waiting for MySQL to be ready..." - sleep 2 - done - name: Run other tests - # These tests are split out because their coverage is low - env: - TEST_ARXIV_DB_URI: mysql://testuser:testpassword@127.0.0.1/testdb run: poetry run pytest --cov=arxiv --cov-fail-under=25 arxiv + #- name: Check Doc Style # run: poetry run pydocstyle --convention=numpy --add-ignore=D401 arxiv diff --git a/arxiv/auth/conftest.py b/arxiv/auth/conftest.py index 8f3fa7bd3..c736402f5 100644 --- a/arxiv/auth/conftest.py +++ b/arxiv/auth/conftest.py @@ -17,7 +17,7 @@ from .legacy.passwords import hash_password from arxiv.base import Base from ..base.middleware import wrap -from ..db import models +from ..db import models, Session as arXiv_session from ..db.models import configure_db_engine from ..auth.auth import Auth @@ -29,9 +29,7 @@ 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}", - # "--ssl-mode=DISABLED", - DB_NAME] +my_sql_cmd = ["mysql", f"--port={DB_PORT}", "-h", "127.0.0.1", "-u", "root", f"--password={ROOT_PASSWORD}"] def arxiv_base_dir() -> str: """ @@ -69,6 +67,7 @@ def db_uri(request): 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' @@ -76,7 +75,8 @@ def classic_db_engine(db_uri): util.create_arxiv_db_schema(db_engine) else: conn_args = {} - # conn_args["ssl"] = None + 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 @@ -91,16 +91,24 @@ def classic_db_engine(db_uri): 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) - mysql = subprocess.Popen(my_sql_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, encoding="utf-8") + 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) + # logger.info(sql) out, err = mysql.communicate(sql, timeout=9999) if out: logger.info(out) - if err: + 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) @@ -111,17 +119,20 @@ def classic_db_engine(db_uri): 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 ]) - mysql = subprocess.Popen(my_sql_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, encoding="utf-8") - mysql.communicate(kill_conn) + # 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() @@ -269,6 +280,8 @@ def _load_test_user(db_engine, foouser): 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): diff --git a/arxiv/auth/legacy/tests/test_accounts.py b/arxiv/auth/legacy/tests/test_accounts.py index 0dc0fb087..4731f41f9 100644 --- a/arxiv/auth/legacy/tests/test_accounts.py +++ b/arxiv/auth/legacy/tests/test_accounts.py @@ -33,20 +33,18 @@ def test_with_nonexistant_user_w_app(app): with app.app_context(): assert not accounts.does_username_exist('baruser') -def test_with_nonexistant_user_wo_app(app): +def test_with_nonexistant_user_wo_app(db_configed): """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_existant_user_w_app(app): """There is a user with the passed username.""" with app.app_context(): assert accounts.does_username_exist('foouser') -def test_with_existant_user_wo_app(app): +def test_with_existant_user_wo_app(db_configed): """There is a user with the passed username.""" - with app.app_context(): - assert accounts.does_username_exist('foouser') + assert accounts.does_username_exist('foouser') def test_email(app): """There is no user with the passed email.""" diff --git a/development/load_arxiv_db_schema.py b/development/load_arxiv_db_schema.py index 6de63eb7c..e133f8603 100644 --- a/development/load_arxiv_db_schema.py +++ b/development/load_arxiv_db_schema.py @@ -15,8 +15,12 @@ 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") -> None: +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) @@ -83,9 +87,15 @@ def main(mysql_port: int, db_name: str, root_password: str="rootpassword", schem 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) + main(db_port, db_name, root_password=args.root_password, schema_sql=args.schema, use_ssl=args.use_ssl) diff --git a/development/run_mysql_container.py b/development/run_mysql_container.py index 0db3fa40c..c987320b8 100644 --- a/development/run_mysql_container.py +++ b/development/run_mysql_container.py @@ -23,7 +23,8 @@ def is_port_open(host: str, port: int) -> bool: 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: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) @@ -36,7 +37,9 @@ def run_mysql_container(port: int, container_name: str ="mysql-test", db_name: s "-e", "MYSQL_PASSWORD=testpassword", "-e", "MYSQL_DATABASE=" + db_name, "-p", f"{port}:3306", - mysql_image + mysql_image, + # Add this for mysql 8 and up to turn off SSL connection + # "--require_secure_transport=OFF" ] try: @@ -57,8 +60,10 @@ def stop_mysql_container(port: int, container_name: str = "mysql-test") -> None: break -def main(mysql_port: int, db_name: str, root_password: str = "rootpassword", restart: bool = False) -> None: +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") @@ -113,9 +118,15 @@ def main(mysql_port: int, db_name: str, root_password: str = "rootpassword", res 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) + main(db_port, db_name, root_password=args.root_password, restart=args.restart, use_ssl=args.use_ssl) From 7535bd1f1423fd8fd9f88300e3619be5a148c19d Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Wed, 11 Dec 2024 16:38:19 -0500 Subject: [PATCH 24/32] Add mysql test in github action --- .github/workflows/pullreqeust_tests.yaml | 35 +++++++----------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/.github/workflows/pullreqeust_tests.yaml b/.github/workflows/pullreqeust_tests.yaml index e5c810f8c..39303a200 100644 --- a/.github/workflows/pullreqeust_tests.yaml +++ b/.github/workflows/pullreqeust_tests.yaml @@ -5,16 +5,6 @@ on: jobs: build: runs-on: ubuntu-latest - services: - mysql: - image: mysql:5.7.20 - ports: - - 23306:3306 - env: - MYSQL_ROOT_PASSWORD: rootpassword - MYSQL_DATABASE: testdb - MYSQL_USER: testuser - MYSQL_PASSWORD: testpassword steps: - uses: actions/checkout@v2 - name: Install Python 3 @@ -29,36 +19,31 @@ jobs: poetry --version # Check if poetry lock file is current with pyproject.toml poetry check --lock - poetry install --quiet --with=dev - - - name: Load db schema - run: | - sudo apt update - sudo apt install -y mysql-client - poetry run python development/load_arxiv_db_schema.py --db_name=testdb --db_port=23306 --root_password=rootpassword --schema=development/arxiv_db_schema.sql - + poetry install --with=dev - name: Run arxiv-base tests with coverage run: poetry run pytest --cov=arxiv.base fourohfour --cov-fail-under=67 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 - # It needs to be non-Snap binary and thus it's from Mozilla PPA. - - name: Install Firefox ESR, test driver, mysqladmin + - name: Install Firefox ESR and test driver run: | sudo add-apt-repository -y ppa:mozillateam/ppa sudo apt update - sudo apt install -y firefox-esr mysql-client-core-8.0 - 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 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/ 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 - #- 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 + + - name: Run db/test with MySQL docker + run: cd arxiv && poetry run pytest auth/legacy/tests --db=mysql From ff3cf964c648d8f80d3fedb94e409272d3a0f8dc Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Thu, 12 Dec 2024 15:17:41 -0500 Subject: [PATCH 25/32] Run mysql test first! --- .github/workflows/pullreqeust_tests.yaml | 11 ++++++++--- arxiv/auth/conftest.py | 4 +++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pullreqeust_tests.yaml b/.github/workflows/pullreqeust_tests.yaml index 39303a200..76728b949 100644 --- a/.github/workflows/pullreqeust_tests.yaml +++ b/.github/workflows/pullreqeust_tests.yaml @@ -19,7 +19,14 @@ 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 # - name: Check Types @@ -45,5 +52,3 @@ jobs: - name: Run App Tests run: poetry run python tests/run_app_tests.py - - name: Run db/test with MySQL docker - run: cd arxiv && poetry run pytest auth/legacy/tests --db=mysql diff --git a/arxiv/auth/conftest.py b/arxiv/auth/conftest.py index c736402f5..cc8c5053b 100644 --- a/arxiv/auth/conftest.py +++ b/arxiv/auth/conftest.py @@ -25,6 +25,8 @@ logging.basicConfig(level=logging.INFO) +PYTHON_EXE = "python" + DB_PORT = 25336 DB_NAME = "testdb" ROOT_PASSWORD = "rootpassword" @@ -54,7 +56,7 @@ def db_uri(request): 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", loader_py, f"--db_name={DB_NAME}", f"--db_port={DB_PORT}", + 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: From 1ea2cd1114b840ccbfcd482d6dee6ba44510f9a5 Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Thu, 12 Dec 2024 15:42:14 -0500 Subject: [PATCH 26/32] Update poetry.lock file --- poetry.lock | 2520 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 1652 insertions(+), 868 deletions(-) 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" From 9cd745e10ec5fa0da074d86fde4b468194e25547 Mon Sep 17 00:00:00 2001 From: "Brian D. Caruso" Date: Thu, 12 Dec 2024 16:14:28 -0500 Subject: [PATCH 27/32] Fixes failing test in test_fastly.py --- .github/workflows/pullreqeust_tests.yaml | 4 ++-- arxiv/integration/tests/test_fastly.py | 2 +- arxiv/auth/conftest.py => conftest.py | 30 ++++++++++-------------- 3 files changed, 15 insertions(+), 21 deletions(-) rename arxiv/auth/conftest.py => conftest.py (95%) diff --git a/.github/workflows/pullreqeust_tests.yaml b/.github/workflows/pullreqeust_tests.yaml index 76728b949..8dfd5c26f 100644 --- a/.github/workflows/pullreqeust_tests.yaml +++ b/.github/workflows/pullreqeust_tests.yaml @@ -28,7 +28,7 @@ jobs: 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 @@ -45,7 +45,7 @@ jobs: - 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 #- name: Check Doc Style # run: poetry run pydocstyle --convention=numpy --add-ignore=D401 arxiv 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/arxiv/auth/conftest.py b/conftest.py similarity index 95% rename from arxiv/auth/conftest.py rename to conftest.py index cc8c5053b..123a2bde8 100644 --- a/arxiv/auth/conftest.py +++ b/conftest.py @@ -1,38 +1,32 @@ import logging -import shlex +import os import shutil import subprocess import tempfile from datetime import datetime, UTC import pytest -import os - from flask import Flask -from sqlalchemy import create_engine, text, CursorResult +from sqlalchemy import create_engine, NullPool, text, CursorResult from sqlalchemy.orm import Session -from sqlalchemy.pool import NullPool -from .legacy import util -from .legacy.passwords import hash_password -from arxiv.base import Base -from ..base.middleware import wrap -from ..db import models, Session as arXiv_session -from ..db.models import configure_db_engine - -from ..auth.auth import Auth -from ..auth.auth.middleware import AuthMiddleware +from arxiv.auth.auth import Auth +from arxiv.auth.auth.middleware import AuthMiddleware -logging.basicConfig(level=logging.INFO) +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: @@ -138,7 +132,6 @@ def classic_db_engine(db_uri): db_engine.dispose() - @pytest.fixture def foouser(mocker): user_id = '15830' @@ -195,6 +188,7 @@ def foouser(mocker): return user + @pytest.fixture def db_with_user(classic_db_engine, foouser): try: From 10409982290651e2776650d2e9df5bb33e0ae6ac Mon Sep 17 00:00:00 2001 From: "Brian D. Caruso" Date: Thu, 12 Dec 2024 16:21:54 -0500 Subject: [PATCH 28/32] Attempt two to fix broken db related to test_fastly.py --- .github/workflows/pullreqeust_tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pullreqeust_tests.yaml b/.github/workflows/pullreqeust_tests.yaml index 8dfd5c26f..90e433ae2 100644 --- a/.github/workflows/pullreqeust_tests.yaml +++ b/.github/workflows/pullreqeust_tests.yaml @@ -45,7 +45,7 @@ jobs: - name: Run other tests # These tests are split out because their coverage is low - run: poetry run pytest --cov=arxiv --cov-fail-under=40 arxiv --ignore=arxiv/base --ignore=arxiv/auth/legacy + 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 From b5db5508366eb147db3c878266aff8dba4a00897 Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Fri, 13 Dec 2024 10:51:29 -0500 Subject: [PATCH 29/32] Set up venv. Set up firefox-esr + gecko driver. --- .github/workflows/pullreqeust_tests.yaml | 6 +++--- Makefile | 19 ++++++++++++++----- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/.github/workflows/pullreqeust_tests.yaml b/.github/workflows/pullreqeust_tests.yaml index 76728b949..c86dca9f2 100644 --- a/.github/workflows/pullreqeust_tests.yaml +++ b/.github/workflows/pullreqeust_tests.yaml @@ -38,9 +38,9 @@ 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 diff --git a/Makefile b/Makefile index a5b182a39..2f27cebf5 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,8 @@ PROD_DB_PROXY_PORT := 2021 +.PHONY: prod-proxy test -.PHONY: db-models prod-proxy test - -default: venv/bin/poetry +default: venv/bin/poetry /usr/bin/firefox-esr /usr/local/bin/geckodriver venv/bin/poetry: venv/bin/pip . venv/bin/activate && pip install poetry @@ -14,14 +13,23 @@ venv/bin/pip: venv 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='*')))" > $@ -db-models: arxiv/db/autogen_models.py - 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 & @@ -30,3 +38,4 @@ 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 + From c6be5f7c480a099ad64ed23b9ccbeda40f7fee39 Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Fri, 13 Dec 2024 13:39:47 -0500 Subject: [PATCH 30/32] Skip the oauth2 log in test if there is no web browser + driver is not present. --- arxiv/auth/openid/tests/test_keycloak.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arxiv/auth/openid/tests/test_keycloak.py b/arxiv/auth/openid/tests/test_keycloak.py index f9031e08e..7355956c9 100644 --- a/arxiv/auth/openid/tests/test_keycloak.py +++ b/arxiv/auth/openid/tests/test_keycloak.py @@ -5,15 +5,20 @@ from selenium.webdriver.firefox.service import Service from selenium.webdriver.firefox.options import Options import time +from shutil import which + +WEB_BROWSER = "/usr/bin/firefox-esr" +WEB_DRIVER = "/usr/local/bin/geckodriver" @pytest.fixture(scope="module") +@pytest.mark.skipif(which(WEB_BROWSER) is None or which(WEB_DRIVER) is None, reason="Web browser/driver not found") def web_driver() -> webdriver.Chrome: options = Options() options.headless = True - options.binary_location = "/usr/bin/firefox-esr" + options.binary_location = WEB_BROWSER options.add_argument('--headless') - service = Service(executable_path="/usr/local/bin/geckodriver") + service = Service(executable_path=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 +34,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 From 9cd5a5ebe1c0e02d3418461bf8784e1e71cc39df Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Fri, 13 Dec 2024 13:43:27 -0500 Subject: [PATCH 31/32] Find the firefox-esr and geckodriver. --- arxiv/auth/openid/tests/test_keycloak.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/arxiv/auth/openid/tests/test_keycloak.py b/arxiv/auth/openid/tests/test_keycloak.py index 7355956c9..195ff710c 100644 --- a/arxiv/auth/openid/tests/test_keycloak.py +++ b/arxiv/auth/openid/tests/test_keycloak.py @@ -7,18 +7,17 @@ import time from shutil import which -WEB_BROWSER = "/usr/bin/firefox-esr" -WEB_DRIVER = "/usr/local/bin/geckodriver" +WEB_BROWSER = "firefox-esr" +WEB_DRIVER = "geckodriver" @pytest.fixture(scope="module") -@pytest.mark.skipif(which(WEB_BROWSER) is None or which(WEB_DRIVER) is None, reason="Web browser/driver not found") def web_driver() -> webdriver.Chrome: options = Options() options.headless = True - options.binary_location = WEB_BROWSER + options.binary_location = which(WEB_BROWSER) options.add_argument('--headless') - service = Service(executable_path=WEB_DRIVER) + 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 From 42d4fbf1cedc6acb00bfaefa78099fe13e9a8999 Mon Sep 17 00:00:00 2001 From: Naoyuki Tai Date: Mon, 16 Dec 2024 14:48:21 -0500 Subject: [PATCH 32/32] Fix the test fixture after the file moved the location. --- conftest.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/conftest.py b/conftest.py index 123a2bde8..4465ae7dd 100644 --- a/conftest.py +++ b/conftest.py @@ -32,11 +32,7 @@ def arxiv_base_dir() -> str: Returns: "arxiv-base" directory abs path """ - here = os.path.abspath(__file__) - root_dir = here - for _ in range(3): - root_dir = os.path.dirname(root_dir) - return root_dir + return os.path.dirname(os.path.abspath(__file__)) @pytest.fixture(scope="session")