diff --git a/Dockerfile b/Dockerfile index 96ee7e7..0ad2359 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,6 +11,7 @@ WORKDIR /app # Install dependencies COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt +RUN pip install gunicorn # Copy project files COPY . . @@ -22,5 +23,5 @@ EXPOSE 5000 ENV FLASK_APP=app.py ENV FLASK_ENV=production -# Run the application -CMD ["flask", "run", "--host=0.0.0.0"] \ No newline at end of file +# Run the application with gunicorn +CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"] \ No newline at end of file diff --git a/app.py b/app.py index 426dc7e..7d2517e 100644 --- a/app.py +++ b/app.py @@ -1,5 +1,6 @@ from flask import Flask, render_template, request, redirect, url_for, flash, session from flask_sqlalchemy import SQLAlchemy +from flask_migrate import Migrate from datetime import datetime from werkzeug.security import generate_password_hash, check_password_hash from werkzeug.utils import secure_filename @@ -16,6 +17,7 @@ app.config['MAX_CONTENT_LENGTH'] = 2 * 1024 * 1024 # 2MB max file size os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) db = SQLAlchemy(app) +migrate = Migrate(app, db) # Database Models class User(db.Model): @@ -1142,4 +1144,7 @@ def seed_db(): description=plant['description'], care_guide=plant['care_guide'] )) - db.session.commit() \ No newline at end of file + db.session.commit() + +if __name__ == "__main__": + app.run(debug=True) \ No newline at end of file diff --git a/instance/site.db b/instance/site.db index 8f44f57..6af8978 100644 Binary files a/instance/site.db and b/instance/site.db differ diff --git a/migrations/README b/migrations/README new file mode 100644 index 0000000..0e04844 --- /dev/null +++ b/migrations/README @@ -0,0 +1 @@ +Single-database configuration for Flask. diff --git a/migrations/alembic.ini b/migrations/alembic.ini new file mode 100644 index 0000000..ec9d45c --- /dev/null +++ b/migrations/alembic.ini @@ -0,0 +1,50 @@ +# A generic, single database configuration. + +[alembic] +# template used to generate migration files +# file_template = %%(rev)s_%%(slug)s + +# set to 'true' to run the environment during +# the 'revision' command, regardless of autogenerate +# revision_environment = false + + +# Logging configuration +[loggers] +keys = root,sqlalchemy,alembic,flask_migrate + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console +qualname = + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[logger_flask_migrate] +level = INFO +handlers = +qualname = flask_migrate + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S diff --git a/migrations/env.py b/migrations/env.py new file mode 100644 index 0000000..4c97092 --- /dev/null +++ b/migrations/env.py @@ -0,0 +1,113 @@ +import logging +from logging.config import fileConfig + +from flask import current_app + +from alembic import context + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +fileConfig(config.config_file_name) +logger = logging.getLogger('alembic.env') + + +def get_engine(): + try: + # this works with Flask-SQLAlchemy<3 and Alchemical + return current_app.extensions['migrate'].db.get_engine() + except (TypeError, AttributeError): + # this works with Flask-SQLAlchemy>=3 + return current_app.extensions['migrate'].db.engine + + +def get_engine_url(): + try: + return get_engine().url.render_as_string(hide_password=False).replace( + '%', '%%') + except AttributeError: + return str(get_engine().url).replace('%', '%%') + + +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata +config.set_main_option('sqlalchemy.url', get_engine_url()) +target_db = current_app.extensions['migrate'].db + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + + +def get_metadata(): + if hasattr(target_db, 'metadatas'): + return target_db.metadatas[None] + return target_db.metadata + + +def run_migrations_offline(): + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure( + url=url, target_metadata=get_metadata(), literal_binds=True + ) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online(): + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + + # this callback is used to prevent an auto-migration from being generated + # when there are no changes to the schema + # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html + def process_revision_directives(context, revision, directives): + if getattr(config.cmd_opts, 'autogenerate', False): + script = directives[0] + if script.upgrade_ops.is_empty(): + directives[:] = [] + logger.info('No changes in schema detected.') + + conf_args = current_app.extensions['migrate'].configure_args + if conf_args.get("process_revision_directives") is None: + conf_args["process_revision_directives"] = process_revision_directives + + connectable = get_engine() + + with connectable.connect() as connection: + context.configure( + connection=connection, + target_metadata=get_metadata(), + **conf_args + ) + + with context.begin_transaction(): + context.run_migrations() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/migrations/script.py.mako b/migrations/script.py.mako new file mode 100644 index 0000000..2c01563 --- /dev/null +++ b/migrations/script.py.mako @@ -0,0 +1,24 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision = ${repr(up_revision)} +down_revision = ${repr(down_revision)} +branch_labels = ${repr(branch_labels)} +depends_on = ${repr(depends_on)} + + +def upgrade(): + ${upgrades if upgrades else "pass"} + + +def downgrade(): + ${downgrades if downgrades else "pass"} diff --git a/requirements.txt b/requirements.txt index f368d53..f2c7974 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,4 +5,6 @@ Flask-WTF==1.2.1 SQLAlchemy==2.0.23 Werkzeug==2.3.7 WTForms==3.1.1 -python-dotenv==1.0.0 \ No newline at end of file +python-dotenv==1.0.0 +psycopg2-binary==2.9.9 +gunicorn==21.2.0 \ No newline at end of file diff --git a/venv/Lib/site-packages/Flask_WTF-1.1.1.dist-info/INSTALLER b/venv/Lib/site-packages/Flask_WTF-1.1.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/Lib/site-packages/Flask_WTF-1.1.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/Lib/site-packages/Flask_WTF-1.1.1.dist-info/LICENSE.rst b/venv/Lib/site-packages/Flask_WTF-1.1.1.dist-info/LICENSE.rst deleted file mode 100644 index 63c3617..0000000 --- a/venv/Lib/site-packages/Flask_WTF-1.1.1.dist-info/LICENSE.rst +++ /dev/null @@ -1,28 +0,0 @@ -Copyright 2010 WTForms - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/Lib/site-packages/Flask_WTF-1.1.1.dist-info/METADATA b/venv/Lib/site-packages/Flask_WTF-1.1.1.dist-info/METADATA deleted file mode 100644 index 1cf1363..0000000 --- a/venv/Lib/site-packages/Flask_WTF-1.1.1.dist-info/METADATA +++ /dev/null @@ -1,50 +0,0 @@ -Metadata-Version: 2.1 -Name: Flask-WTF -Version: 1.1.1 -Summary: Form rendering, validation, and CSRF protection for Flask with WTForms. -Home-page: https://github.com/wtforms/flask-wtf/ -Author: Dan Jacob -Author-email: danjac354@gmail.com -Maintainer: Hsiaoming Yang -Maintainer-email: me@lepture.com -License: BSD-3-Clause -Project-URL: Documentation, https://flask-wtf.readthedocs.io/ -Project-URL: Changes, https://flask-wtf.readthedocs.io/changes/ -Project-URL: Source Code, https://github.com/wtforms/flask-wtf/ -Project-URL: Issue Tracker, https://github.com/wtforms/flask-wtf/issues/ -Project-URL: Chat, https://discord.gg/pallets -Classifier: Development Status :: 5 - Production/Stable -Classifier: Environment :: Web Environment -Classifier: Framework :: Flask -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: BSD License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content -Classifier: Topic :: Internet :: WWW/HTTP :: WSGI -Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application -Classifier: Topic :: Software Development :: Libraries :: Application Frameworks -Requires-Python: >=3.7 -Description-Content-Type: text/x-rst -License-File: LICENSE.rst -Requires-Dist: Flask -Requires-Dist: WTForms -Requires-Dist: itsdangerous -Provides-Extra: email -Requires-Dist: email-validator ; extra == 'email' - -Flask-WTF -========= - -Simple integration of Flask and WTForms, including CSRF, file upload, -and reCAPTCHA. - -Links ------ - -- Documentation: https://flask-wtf.readthedocs.io/ -- Changes: https://flask-wtf.readthedocs.io/changes/ -- PyPI Releases: https://pypi.org/project/Flask-WTF/ -- Source Code: https://github.com/wtforms/flask-wtf/ -- Issue Tracker: https://github.com/wtforms/flask-wtf/issues/ -- Chat: https://discord.gg/pallets diff --git a/venv/Lib/site-packages/Flask_WTF-1.1.1.dist-info/RECORD b/venv/Lib/site-packages/Flask_WTF-1.1.1.dist-info/RECORD deleted file mode 100644 index 3653ab8..0000000 --- a/venv/Lib/site-packages/Flask_WTF-1.1.1.dist-info/RECORD +++ /dev/null @@ -1,27 +0,0 @@ -Flask_WTF-1.1.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -Flask_WTF-1.1.1.dist-info/LICENSE.rst,sha256=1fGQNkUVeMs27u8EyZ6_fXyi5w3PBDY2UZvEIOFafGI,1475 -Flask_WTF-1.1.1.dist-info/METADATA,sha256=YR-t2rpU1ZnLGjB4H_LEm3ns3EPcs8VbAxASuoaWrgE,1868 -Flask_WTF-1.1.1.dist-info/RECORD,, -Flask_WTF-1.1.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -Flask_WTF-1.1.1.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92 -Flask_WTF-1.1.1.dist-info/top_level.txt,sha256=zK3flQPSjYTkAMjB0V6Jhu3jyotC0biL1mMhzitYoog,10 -flask_wtf/__init__.py,sha256=9N5z_8Nkzsla9cgqGKxlLmkgdHGuU3UI49_O2M1odr8,214 -flask_wtf/__pycache__/__init__.cpython-310.pyc,, -flask_wtf/__pycache__/_compat.cpython-310.pyc,, -flask_wtf/__pycache__/csrf.cpython-310.pyc,, -flask_wtf/__pycache__/file.cpython-310.pyc,, -flask_wtf/__pycache__/form.cpython-310.pyc,, -flask_wtf/__pycache__/i18n.cpython-310.pyc,, -flask_wtf/_compat.py,sha256=N3sqC9yzFWY-3MZ7QazX1sidvkO3d5yy4NR6lkp0s94,248 -flask_wtf/csrf.py,sha256=Z407bCLwNpqjmdh6vK162hG1dHxdrZ2kly4n-Hrbyhs,10156 -flask_wtf/file.py,sha256=SKm-Tjk9mYrP94cMnIdEOab1vvQEjfKZ1PwPzXNhH6o,3644 -flask_wtf/form.py,sha256=TmR7xCrxin2LHp6thn7fq1OeU8aLB7xsZzvv52nH7Ss,4049 -flask_wtf/i18n.py,sha256=TyO8gqt9DocHMSaNhj0KKgxoUrPYs-G1nVW-jns0SOw,1166 -flask_wtf/recaptcha/__init__.py,sha256=m4eNGoU3Q0Wnt_wP8VvOlA0mwWuoMtAcK9pYT7sPFp8,106 -flask_wtf/recaptcha/__pycache__/__init__.cpython-310.pyc,, -flask_wtf/recaptcha/__pycache__/fields.cpython-310.pyc,, -flask_wtf/recaptcha/__pycache__/validators.cpython-310.pyc,, -flask_wtf/recaptcha/__pycache__/widgets.cpython-310.pyc,, -flask_wtf/recaptcha/fields.py,sha256=M1-RFuUKOsJAzsLm3xaaxuhX2bB9oRqS-HVSN-NpkmI,433 -flask_wtf/recaptcha/validators.py,sha256=K4e_pvPoq0JBcSFXEB2XRzWbvi9LZef3ioNbS2jdNgU,2437 -flask_wtf/recaptcha/widgets.py,sha256=OWSFCZDWaLBLkNJvzyqcIbRQVBD5tUyEOijfTv0Dpjo,1503 diff --git a/venv/Lib/site-packages/Flask_WTF-1.1.1.dist-info/REQUESTED b/venv/Lib/site-packages/Flask_WTF-1.1.1.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 diff --git a/venv/Lib/site-packages/Flask_WTF-1.1.1.dist-info/WHEEL b/venv/Lib/site-packages/Flask_WTF-1.1.1.dist-info/WHEEL deleted file mode 100644 index 57e3d84..0000000 --- a/venv/Lib/site-packages/Flask_WTF-1.1.1.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.38.4) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/venv/Lib/site-packages/Flask_WTF-1.1.1.dist-info/top_level.txt b/venv/Lib/site-packages/Flask_WTF-1.1.1.dist-info/top_level.txt deleted file mode 100644 index 716f422..0000000 --- a/venv/Lib/site-packages/Flask_WTF-1.1.1.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -flask_wtf diff --git a/venv/Lib/site-packages/SQLAlchemy-2.0.20.dist-info/INSTALLER b/venv/Lib/site-packages/SQLAlchemy-2.0.20.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/Lib/site-packages/SQLAlchemy-2.0.20.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/Lib/site-packages/SQLAlchemy-2.0.20.dist-info/LICENSE b/venv/Lib/site-packages/SQLAlchemy-2.0.20.dist-info/LICENSE deleted file mode 100644 index 7bf9bbe..0000000 --- a/venv/Lib/site-packages/SQLAlchemy-2.0.20.dist-info/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright 2005-2023 SQLAlchemy authors and contributors . - -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/venv/Lib/site-packages/SQLAlchemy-2.0.20.dist-info/METADATA b/venv/Lib/site-packages/SQLAlchemy-2.0.20.dist-info/METADATA deleted file mode 100644 index eab2ace..0000000 --- a/venv/Lib/site-packages/SQLAlchemy-2.0.20.dist-info/METADATA +++ /dev/null @@ -1,238 +0,0 @@ -Metadata-Version: 2.1 -Name: SQLAlchemy -Version: 2.0.20 -Summary: Database Abstraction Library -Home-page: https://www.sqlalchemy.org -Author: Mike Bayer -Author-email: mike_mp@zzzcomputing.com -License: MIT -Project-URL: Documentation, https://docs.sqlalchemy.org -Project-URL: Issue Tracker, https://github.com/sqlalchemy/sqlalchemy/ -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Topic :: Database :: Front-Ends -Requires-Python: >=3.7 -Description-Content-Type: text/x-rst -License-File: LICENSE -Requires-Dist: typing-extensions >=4.2.0 -Requires-Dist: greenlet !=0.4.17 ; 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"))))) -Requires-Dist: importlib-metadata ; python_version < "3.8" -Provides-Extra: aiomysql -Requires-Dist: greenlet !=0.4.17 ; extra == 'aiomysql' -Requires-Dist: aiomysql >=0.2.0 ; extra == 'aiomysql' -Provides-Extra: aiosqlite -Requires-Dist: greenlet !=0.4.17 ; extra == 'aiosqlite' -Requires-Dist: aiosqlite ; extra == 'aiosqlite' -Requires-Dist: typing-extensions !=3.10.0.1 ; extra == 'aiosqlite' -Provides-Extra: asyncio -Requires-Dist: greenlet !=0.4.17 ; extra == 'asyncio' -Provides-Extra: asyncmy -Requires-Dist: greenlet !=0.4.17 ; extra == 'asyncmy' -Requires-Dist: asyncmy !=0.2.4,!=0.2.6,>=0.2.3 ; extra == 'asyncmy' -Provides-Extra: mariadb_connector -Requires-Dist: mariadb !=1.1.2,!=1.1.5,>=1.0.1 ; extra == 'mariadb_connector' -Provides-Extra: mssql -Requires-Dist: pyodbc ; extra == 'mssql' -Provides-Extra: mssql_pymssql -Requires-Dist: pymssql ; extra == 'mssql_pymssql' -Provides-Extra: mssql_pyodbc -Requires-Dist: pyodbc ; extra == 'mssql_pyodbc' -Provides-Extra: mypy -Requires-Dist: mypy >=0.910 ; extra == 'mypy' -Provides-Extra: mysql -Requires-Dist: mysqlclient >=1.4.0 ; extra == 'mysql' -Provides-Extra: mysql_connector -Requires-Dist: mysql-connector-python ; extra == 'mysql_connector' -Provides-Extra: oracle -Requires-Dist: cx-oracle >=7 ; extra == 'oracle' -Provides-Extra: oracle_oracledb -Requires-Dist: oracledb >=1.0.1 ; extra == 'oracle_oracledb' -Provides-Extra: postgresql -Requires-Dist: psycopg2 >=2.7 ; extra == 'postgresql' -Provides-Extra: postgresql_asyncpg -Requires-Dist: greenlet !=0.4.17 ; extra == 'postgresql_asyncpg' -Requires-Dist: asyncpg ; extra == 'postgresql_asyncpg' -Provides-Extra: postgresql_pg8000 -Requires-Dist: pg8000 >=1.29.1 ; extra == 'postgresql_pg8000' -Provides-Extra: postgresql_psycopg -Requires-Dist: psycopg >=3.0.7 ; extra == 'postgresql_psycopg' -Provides-Extra: postgresql_psycopg2binary -Requires-Dist: psycopg2-binary ; extra == 'postgresql_psycopg2binary' -Provides-Extra: postgresql_psycopg2cffi -Requires-Dist: psycopg2cffi ; extra == 'postgresql_psycopg2cffi' -Provides-Extra: postgresql_psycopgbinary -Requires-Dist: psycopg[binary] >=3.0.7 ; extra == 'postgresql_psycopgbinary' -Provides-Extra: pymysql -Requires-Dist: pymysql ; extra == 'pymysql' -Provides-Extra: sqlcipher -Requires-Dist: sqlcipher3-binary ; extra == 'sqlcipher' - -SQLAlchemy -========== - -|PyPI| |Python| |Downloads| - -.. |PyPI| image:: https://img.shields.io/pypi/v/sqlalchemy - :target: https://pypi.org/project/sqlalchemy - :alt: PyPI - -.. |Python| image:: https://img.shields.io/pypi/pyversions/sqlalchemy - :target: https://pypi.org/project/sqlalchemy - :alt: PyPI - Python Version - -.. |Downloads| image:: https://static.pepy.tech/badge/sqlalchemy/month - :target: https://pepy.tech/project/sqlalchemy - :alt: PyPI - Downloads - - -The Python SQL Toolkit and Object Relational Mapper - -Introduction -------------- - -SQLAlchemy is the Python SQL toolkit and Object Relational Mapper -that gives application developers the full power and -flexibility of SQL. SQLAlchemy provides a full suite -of well known enterprise-level persistence patterns, -designed for efficient and high-performing database -access, adapted into a simple and Pythonic domain -language. - -Major SQLAlchemy features include: - -* An industrial strength ORM, built - from the core on the identity map, unit of work, - and data mapper patterns. These patterns - allow transparent persistence of objects - using a declarative configuration system. - Domain models - can be constructed and manipulated naturally, - and changes are synchronized with the - current transaction automatically. -* A relationally-oriented query system, exposing - the full range of SQL's capabilities - explicitly, including joins, subqueries, - correlation, and most everything else, - in terms of the object model. - Writing queries with the ORM uses the same - techniques of relational composition you use - when writing SQL. While you can drop into - literal SQL at any time, it's virtually never - needed. -* A comprehensive and flexible system - of eager loading for related collections and objects. - Collections are cached within a session, - and can be loaded on individual access, all - at once using joins, or by query per collection - across the full result set. -* A Core SQL construction system and DBAPI - interaction layer. The SQLAlchemy Core is - separate from the ORM and is a full database - abstraction layer in its own right, and includes - an extensible Python-based SQL expression - language, schema metadata, connection pooling, - type coercion, and custom types. -* All primary and foreign key constraints are - assumed to be composite and natural. Surrogate - integer primary keys are of course still the - norm, but SQLAlchemy never assumes or hardcodes - to this model. -* Database introspection and generation. Database - schemas can be "reflected" in one step into - Python structures representing database metadata; - those same structures can then generate - CREATE statements right back out - all within - the Core, independent of the ORM. - -SQLAlchemy's philosophy: - -* SQL databases behave less and less like object - collections the more size and performance start to - matter; object collections behave less and less like - tables and rows the more abstraction starts to matter. - SQLAlchemy aims to accommodate both of these - principles. -* An ORM doesn't need to hide the "R". A relational - database provides rich, set-based functionality - that should be fully exposed. SQLAlchemy's - ORM provides an open-ended set of patterns - that allow a developer to construct a custom - mediation layer between a domain model and - a relational schema, turning the so-called - "object relational impedance" issue into - a distant memory. -* The developer, in all cases, makes all decisions - regarding the design, structure, and naming conventions - of both the object model as well as the relational - schema. SQLAlchemy only provides the means - to automate the execution of these decisions. -* With SQLAlchemy, there's no such thing as - "the ORM generated a bad query" - you - retain full control over the structure of - queries, including how joins are organized, - how subqueries and correlation is used, what - columns are requested. Everything SQLAlchemy - does is ultimately the result of a developer-initiated - decision. -* Don't use an ORM if the problem doesn't need one. - SQLAlchemy consists of a Core and separate ORM - component. The Core offers a full SQL expression - language that allows Pythonic construction - of SQL constructs that render directly to SQL - strings for a target database, returning - result sets that are essentially enhanced DBAPI - cursors. -* Transactions should be the norm. With SQLAlchemy's - ORM, nothing goes to permanent storage until - commit() is called. SQLAlchemy encourages applications - to create a consistent means of delineating - the start and end of a series of operations. -* Never render a literal value in a SQL statement. - Bound parameters are used to the greatest degree - possible, allowing query optimizers to cache - query plans effectively and making SQL injection - attacks a non-issue. - -Documentation -------------- - -Latest documentation is at: - -https://www.sqlalchemy.org/docs/ - -Installation / Requirements ---------------------------- - -Full documentation for installation is at -`Installation `_. - -Getting Help / Development / Bug reporting ------------------------------------------- - -Please refer to the `SQLAlchemy Community Guide `_. - -Code of Conduct ---------------- - -Above all, SQLAlchemy places great emphasis on polite, thoughtful, and -constructive communication between users and developers. -Please see our current Code of Conduct at -`Code of Conduct `_. - -License -------- - -SQLAlchemy is distributed under the `MIT license -`_. - diff --git a/venv/Lib/site-packages/SQLAlchemy-2.0.20.dist-info/RECORD b/venv/Lib/site-packages/SQLAlchemy-2.0.20.dist-info/RECORD deleted file mode 100644 index c9b532e..0000000 --- a/venv/Lib/site-packages/SQLAlchemy-2.0.20.dist-info/RECORD +++ /dev/null @@ -1,524 +0,0 @@ -SQLAlchemy-2.0.20.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -SQLAlchemy-2.0.20.dist-info/LICENSE,sha256=ZbcQGZNtpoLy8YjvH-nyoobTdOwtEgtXopPVzxy6pCo,1119 -SQLAlchemy-2.0.20.dist-info/METADATA,sha256=nEFiWWNkJBol1Lb751ILyjQAvlSImwjdLuqoWTJ621A,9667 -SQLAlchemy-2.0.20.dist-info/RECORD,, -SQLAlchemy-2.0.20.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -SQLAlchemy-2.0.20.dist-info/WHEEL,sha256=Wb1el1iP4ORW7FiLElw7HfxLpDiHzwvd2B382b2Idl0,102 -SQLAlchemy-2.0.20.dist-info/top_level.txt,sha256=rp-ZgB7D8G11ivXON5VGPjupT1voYmWqkciDt5Uaw_Q,11 -sqlalchemy/__init__.py,sha256=mnL2g2e81Pw9K-IxeLNmqYYpQ6ZMc4_0dOUVB3lpAyk,12993 -sqlalchemy/__pycache__/__init__.cpython-310.pyc,, -sqlalchemy/__pycache__/events.cpython-310.pyc,, -sqlalchemy/__pycache__/exc.cpython-310.pyc,, -sqlalchemy/__pycache__/inspection.cpython-310.pyc,, -sqlalchemy/__pycache__/log.cpython-310.pyc,, -sqlalchemy/__pycache__/schema.cpython-310.pyc,, -sqlalchemy/__pycache__/types.cpython-310.pyc,, -sqlalchemy/connectors/__init__.py,sha256=sjPX1Mb2nWgRHLZY0mF350mGiqpi2CYBs2A1b8dh_wE,494 -sqlalchemy/connectors/__pycache__/__init__.cpython-310.pyc,, -sqlalchemy/connectors/__pycache__/pyodbc.cpython-310.pyc,, -sqlalchemy/connectors/pyodbc.py,sha256=GFZ_OqBAwQpEprwEmVVCm0imUEqw36PGv1YFOsH2Lag,8730 -sqlalchemy/cyextension/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -sqlalchemy/cyextension/__pycache__/__init__.cpython-310.pyc,, -sqlalchemy/cyextension/collections.cp310-win_amd64.pyd,sha256=7-Q6dQbt5KmaO6gtS17XhtPGx0yNiDFixx2G_Ovh9_g,173568 -sqlalchemy/cyextension/collections.pyx,sha256=UY81HxvMAD4MOFR52SjzUbLHCGGcHZDSfK6gw6AYB8A,12726 -sqlalchemy/cyextension/immutabledict.cp310-win_amd64.pyd,sha256=BLlAQZ1KNSPut7J14edvsMXDkbwSaGuNGei24P5ZfNM,72192 -sqlalchemy/cyextension/immutabledict.pxd,sha256=JsNJYZIekkbtQQ2Tz6Bn1bO1g07yXztY9bb3rvH1e0Y,43 -sqlalchemy/cyextension/immutabledict.pyx,sha256=VmhtF8aDXjEVVdA80LRY1iP85lNMwcz7vB6hZkAOGB0,3412 -sqlalchemy/cyextension/processors.cp310-win_amd64.pyd,sha256=8IJwIPDE7K7JKHp5FshSv4X-w9fv4HMO9o8nPTJqrK0,58880 -sqlalchemy/cyextension/processors.pyx,sha256=ZXuoi-hPRI9pVSbp6QbfJwy6S5kVCUZ8qj_h5-NvAFA,1607 -sqlalchemy/cyextension/resultproxy.cp310-win_amd64.pyd,sha256=3HcHkSMTU4dksuzq0v2MD7Q_BJ-c9KidQIlTwyBO28E,60416 -sqlalchemy/cyextension/resultproxy.pyx,sha256=qlk8eBpFo3UYbwQChdIWa3RqWXczuUL8ahulcLCL1bI,2573 -sqlalchemy/cyextension/util.cp310-win_amd64.pyd,sha256=5PWlHJDSaHyempijzTE4GTrYKAGOqsQOZzZjoCz1fSg,72704 -sqlalchemy/cyextension/util.pyx,sha256=H2FEg9uAAWO9UcNFyrfVuPhOznTq3h9UdjfmJ2BRD1Y,2374 -sqlalchemy/dialects/__init__.py,sha256=vUDqtIsKolzjds0KK763SAnVCCF1SGQ64zY4WNIxbwM,1847 -sqlalchemy/dialects/__pycache__/__init__.cpython-310.pyc,, -sqlalchemy/dialects/__pycache__/_typing.cpython-310.pyc,, -sqlalchemy/dialects/_typing.py,sha256=hA9jNttJjmVWDHKybSMSFWIlmRv2r5kuQPp8IeViifY,667 -sqlalchemy/dialects/mssql/__init__.py,sha256=dvJCLhXDMkDvtAXT_26kBllhR7-geM9nrZOUxr2IG6Q,1928 -sqlalchemy/dialects/mssql/__pycache__/__init__.cpython-310.pyc,, -sqlalchemy/dialects/mssql/__pycache__/base.cpython-310.pyc,, -sqlalchemy/dialects/mssql/__pycache__/information_schema.cpython-310.pyc,, -sqlalchemy/dialects/mssql/__pycache__/json.cpython-310.pyc,, -sqlalchemy/dialects/mssql/__pycache__/provision.cpython-310.pyc,, -sqlalchemy/dialects/mssql/__pycache__/pymssql.cpython-310.pyc,, -sqlalchemy/dialects/mssql/__pycache__/pyodbc.cpython-310.pyc,, -sqlalchemy/dialects/mssql/base.py,sha256=D8kqfvgGhZX98rfPlpluJmJBO72wx9QM3oirzj2CqO8,137310 -sqlalchemy/dialects/mssql/information_schema.py,sha256=ufbEeGAFsciot3MmKPmFFhW95r57F_ORHULBS_UuUSw,8320 -sqlalchemy/dialects/mssql/json.py,sha256=VOrBSxJWh7Fj-zIBA5aYZwx37DJq1OrWpJqc0xtWPhQ,4700 -sqlalchemy/dialects/mssql/provision.py,sha256=hlKU-pYiCAMlLtEOjEhPr7ESgvQ4iLCAywtDXNQqZus,5142 -sqlalchemy/dialects/mssql/pymssql.py,sha256=yA5NnGBs0YSzzjnGlqMrtHKdo4XHyJ6zKcySOvAw2ZA,4154 -sqlalchemy/dialects/mssql/pyodbc.py,sha256=y4yayQokx8NWPvmod_JVI8BshoNpohfhclLxQlEhTIE,27444 -sqlalchemy/dialects/mysql/__init__.py,sha256=060B9NtuQqUb8vNXDm8bdOGUUi6SUi_757-19DDhOQM,2245 -sqlalchemy/dialects/mysql/__pycache__/__init__.cpython-310.pyc,, -sqlalchemy/dialects/mysql/__pycache__/aiomysql.cpython-310.pyc,, -sqlalchemy/dialects/mysql/__pycache__/asyncmy.cpython-310.pyc,, -sqlalchemy/dialects/mysql/__pycache__/base.cpython-310.pyc,, -sqlalchemy/dialects/mysql/__pycache__/cymysql.cpython-310.pyc,, -sqlalchemy/dialects/mysql/__pycache__/dml.cpython-310.pyc,, -sqlalchemy/dialects/mysql/__pycache__/enumerated.cpython-310.pyc,, -sqlalchemy/dialects/mysql/__pycache__/expression.cpython-310.pyc,, -sqlalchemy/dialects/mysql/__pycache__/json.cpython-310.pyc,, -sqlalchemy/dialects/mysql/__pycache__/mariadb.cpython-310.pyc,, -sqlalchemy/dialects/mysql/__pycache__/mariadbconnector.cpython-310.pyc,, -sqlalchemy/dialects/mysql/__pycache__/mysqlconnector.cpython-310.pyc,, -sqlalchemy/dialects/mysql/__pycache__/mysqldb.cpython-310.pyc,, -sqlalchemy/dialects/mysql/__pycache__/provision.cpython-310.pyc,, -sqlalchemy/dialects/mysql/__pycache__/pymysql.cpython-310.pyc,, -sqlalchemy/dialects/mysql/__pycache__/pyodbc.cpython-310.pyc,, -sqlalchemy/dialects/mysql/__pycache__/reflection.cpython-310.pyc,, -sqlalchemy/dialects/mysql/__pycache__/reserved_words.cpython-310.pyc,, -sqlalchemy/dialects/mysql/__pycache__/types.cpython-310.pyc,, -sqlalchemy/dialects/mysql/aiomysql.py,sha256=xXvFyEjL613scXbU490iwK4fTegDGDojMUO565qo0iE,9831 -sqlalchemy/dialects/mysql/asyncmy.py,sha256=Ilpd6rTcXFr40iepVerDuZmni8db4tGLiK2j0B9pnII,9966 -sqlalchemy/dialects/mysql/base.py,sha256=JSYsIrsTQABPCE78llB7bYJyecJsAUlHkLBkPq4gUKw,122488 -sqlalchemy/dialects/mysql/cymysql.py,sha256=RdwzBclxwN3uXWTT34YySR0rQfTjVzZDSadhzlOqhag,2375 -sqlalchemy/dialects/mysql/dml.py,sha256=dDUvRalIG5l6_Iawkj0n-6p0NRfYfdP1wRl121qOYek,7855 -sqlalchemy/dialects/mysql/enumerated.py,sha256=whCwVR5DmKh455d4EVg2XHItfvLtuzxA5bWOWzK6Cnw,8683 -sqlalchemy/dialects/mysql/expression.py,sha256=-RmnmFCjWn16L_Nn82541wr6I3bUvvMk_6L7WhmeAK4,4206 -sqlalchemy/dialects/mysql/json.py,sha256=hZr1MD4W6BaItKT5LRStDRQbr7wcer4YdWbkh47-RTA,2341 -sqlalchemy/dialects/mysql/mariadb.py,sha256=SdFqsWMjIFwoC0bhlqksN4ju0Mnq3-iUDCKq7_idWk0,876 -sqlalchemy/dialects/mysql/mariadbconnector.py,sha256=yajW-43yKl94IxjCCFTzJ1Amr5RRDq0wkvBm_9IGBXU,7703 -sqlalchemy/dialects/mysql/mysqlconnector.py,sha256=8a2BZ_ChVR5HvTzonq0DtYoInD3iV4ihbA_9EbgtUxY,5845 -sqlalchemy/dialects/mysql/mysqldb.py,sha256=4ZLfGACIMD5icglEqx6jTj3W4adT_ANCV1xo5kvAHYw,9962 -sqlalchemy/dialects/mysql/provision.py,sha256=jdtfrsATv7hoMcepkMxHVG5QV2YkA92bg01CnOR9VMs,3327 -sqlalchemy/dialects/mysql/pymysql.py,sha256=f09IxnUy9HFCEnNrW-RqxvByVUREYWRpbHsa1yIPDGk,3045 -sqlalchemy/dialects/mysql/pyodbc.py,sha256=dfz0mekJDsOIvjs5utBRNltUr9YyhYuUH1rsUPb4NjI,4426 -sqlalchemy/dialects/mysql/reflection.py,sha256=4-lXatfmSjcmv7YocofW3WUvLeQV8f0qrn73H40evpg,23198 -sqlalchemy/dialects/mysql/reserved_words.py,sha256=KOR71_hBCzivGutG54Yq_K5t7dT6lgRBey0TcztWI3I,9712 -sqlalchemy/dialects/mysql/types.py,sha256=vOi0kn2OLaWTjPKTNz5xPcS-jiHRLv_l1no_oA_jdYQ,25031 -sqlalchemy/dialects/oracle/__init__.py,sha256=IghimaBtnKRrtkYdO5eFjJ5OUUGPJpYSZZJX0DIJb38,1368 -sqlalchemy/dialects/oracle/__pycache__/__init__.cpython-310.pyc,, -sqlalchemy/dialects/oracle/__pycache__/base.cpython-310.pyc,, -sqlalchemy/dialects/oracle/__pycache__/cx_oracle.cpython-310.pyc,, -sqlalchemy/dialects/oracle/__pycache__/dictionary.cpython-310.pyc,, -sqlalchemy/dialects/oracle/__pycache__/oracledb.cpython-310.pyc,, -sqlalchemy/dialects/oracle/__pycache__/provision.cpython-310.pyc,, -sqlalchemy/dialects/oracle/__pycache__/types.cpython-310.pyc,, -sqlalchemy/dialects/oracle/base.py,sha256=Ouc583EpWEzQ25yOTeaNCXNgvwM78PDSxoP6ETT82Zw,121073 -sqlalchemy/dialects/oracle/cx_oracle.py,sha256=8HYHDRepG0X2sm2F_8VObomiaoRQzf8lnhlKNktruu8,56585 -sqlalchemy/dialects/oracle/dictionary.py,sha256=yRmt5b218G1Q5pZR5kF1ocsusT4XAgl3v_t9WhKqlko,19993 -sqlalchemy/dialects/oracle/oracledb.py,sha256=ZweQdl0ZKR3jaXowa14JBlWg1KXcabm_FWhOR4vqPsk,3566 -sqlalchemy/dialects/oracle/provision.py,sha256=i4Ja1rCJLs0jIcpzt0PfcANHHoDOSWEpxqBvWYAdOcs,8269 -sqlalchemy/dialects/oracle/types.py,sha256=vF5neW-vxJcl9nLL9x74zn05gmU-_wkCTNmF0diqqaw,7738 -sqlalchemy/dialects/postgresql/__init__.py,sha256=kx5Iwob5j2_gYXMVF2qM6qIH5DCXxw1UYXVjuCgpvys,3897 -sqlalchemy/dialects/postgresql/__pycache__/__init__.cpython-310.pyc,, -sqlalchemy/dialects/postgresql/__pycache__/_psycopg_common.cpython-310.pyc,, -sqlalchemy/dialects/postgresql/__pycache__/array.cpython-310.pyc,, -sqlalchemy/dialects/postgresql/__pycache__/asyncpg.cpython-310.pyc,, -sqlalchemy/dialects/postgresql/__pycache__/base.cpython-310.pyc,, -sqlalchemy/dialects/postgresql/__pycache__/dml.cpython-310.pyc,, -sqlalchemy/dialects/postgresql/__pycache__/ext.cpython-310.pyc,, -sqlalchemy/dialects/postgresql/__pycache__/hstore.cpython-310.pyc,, -sqlalchemy/dialects/postgresql/__pycache__/json.cpython-310.pyc,, -sqlalchemy/dialects/postgresql/__pycache__/named_types.cpython-310.pyc,, -sqlalchemy/dialects/postgresql/__pycache__/operators.cpython-310.pyc,, -sqlalchemy/dialects/postgresql/__pycache__/pg8000.cpython-310.pyc,, -sqlalchemy/dialects/postgresql/__pycache__/pg_catalog.cpython-310.pyc,, -sqlalchemy/dialects/postgresql/__pycache__/provision.cpython-310.pyc,, -sqlalchemy/dialects/postgresql/__pycache__/psycopg.cpython-310.pyc,, -sqlalchemy/dialects/postgresql/__pycache__/psycopg2.cpython-310.pyc,, -sqlalchemy/dialects/postgresql/__pycache__/psycopg2cffi.cpython-310.pyc,, -sqlalchemy/dialects/postgresql/__pycache__/ranges.cpython-310.pyc,, -sqlalchemy/dialects/postgresql/__pycache__/types.cpython-310.pyc,, -sqlalchemy/dialects/postgresql/_psycopg_common.py,sha256=_DTODxy9UrjvqDk20-ZjEUAYhrzRFiosaH4GHp4mnNM,5841 -sqlalchemy/dialects/postgresql/array.py,sha256=3C-g6RRWgB4Th_MV4UWpbxXo8UT2-GDRxmXowyyml5A,14108 -sqlalchemy/dialects/postgresql/asyncpg.py,sha256=ooMOPDZEF4AnOJW9Mqz4zBpkXCUzZQGJwpxQGYXgvyA,40591 -sqlalchemy/dialects/postgresql/base.py,sha256=3Zi_VZU801kJBsgrEzJC-GHG_rmCIp-v95S87uzBp48,180277 -sqlalchemy/dialects/postgresql/dml.py,sha256=jESBXHjBdT-xzHSVADNz-2ljH-4I-rjjGuhKzrkGJII,11513 -sqlalchemy/dialects/postgresql/ext.py,sha256=MdYxZshShFutBq657bDNyq68kzczovktkJeuGq-WqmM,16749 -sqlalchemy/dialects/postgresql/hstore.py,sha256=x9kAVfXLHYDQfqg6IHPUhr4dvFSsBPoMKoBhqyaF_Vo,11929 -sqlalchemy/dialects/postgresql/json.py,sha256=vrSiTBejjt54B9JSOixbh-oR8fg2OGIJLW2gOsmb0gI,11528 -sqlalchemy/dialects/postgresql/named_types.py,sha256=fsAflctGz5teUyM7h2s0Z2Na14Dtt4vEj0rzf2VtRwU,17588 -sqlalchemy/dialects/postgresql/operators.py,sha256=oe7NQRjOkJM46ISEnNIGxV4qOm2ANrqn3PLKHqj6bmY,2928 -sqlalchemy/dialects/postgresql/pg8000.py,sha256=F6P7YT5iXWq3sYDIyiP1Qxoq3PrE7zFaUnivwMdRJSQ,19284 -sqlalchemy/dialects/postgresql/pg_catalog.py,sha256=8imUP46LsmtnVozUZa2qEtDcDHwjrYg4c2tSJsbCpfo,9169 -sqlalchemy/dialects/postgresql/provision.py,sha256=_sD_42mkypvAwDxwT6xeCGnHD5EMRVubIN5eonZ8MsQ,5678 -sqlalchemy/dialects/postgresql/psycopg.py,sha256=vcqBE7Nr9mfSRGUeg9rSz94kfWDiCco_xabLu16qQyM,22984 -sqlalchemy/dialects/postgresql/psycopg2.py,sha256=z2oVzGAfKnEIvJqEiJjb1nrsb84NaMjcHw6cWPC1PyU,32479 -sqlalchemy/dialects/postgresql/psycopg2cffi.py,sha256=gITk63w4Gi4wXQxBW22a0VGVUg-oBMyfg_YgIHc5kww,1800 -sqlalchemy/dialects/postgresql/ranges.py,sha256=qrrFd9KWkaR83B69QhNQadnkQJe1u5hUf3nnCzQnf94,31206 -sqlalchemy/dialects/postgresql/types.py,sha256=HuXQ2XabYNmWRkClpHTXCaB8vbI6tzwQI7y1aNZKNEo,7240 -sqlalchemy/dialects/sqlite/__init__.py,sha256=CHJgBNgr7eufrgF-0l27xohu4N317u1IOy7Hyyrxx0o,1230 -sqlalchemy/dialects/sqlite/__pycache__/__init__.cpython-310.pyc,, -sqlalchemy/dialects/sqlite/__pycache__/aiosqlite.cpython-310.pyc,, -sqlalchemy/dialects/sqlite/__pycache__/base.cpython-310.pyc,, -sqlalchemy/dialects/sqlite/__pycache__/dml.cpython-310.pyc,, -sqlalchemy/dialects/sqlite/__pycache__/json.cpython-310.pyc,, -sqlalchemy/dialects/sqlite/__pycache__/provision.cpython-310.pyc,, -sqlalchemy/dialects/sqlite/__pycache__/pysqlcipher.cpython-310.pyc,, -sqlalchemy/dialects/sqlite/__pycache__/pysqlite.cpython-310.pyc,, -sqlalchemy/dialects/sqlite/aiosqlite.py,sha256=PiO8heyB6GXeTC4lxsptX6eKQlKvyy0s9UGeBEAdxog,11258 -sqlalchemy/dialects/sqlite/base.py,sha256=ukLGX5LR8G6GlbmzG7bGDp8QmQ5-SzUzwAN9hTBWJl8,98978 -sqlalchemy/dialects/sqlite/dml.py,sha256=KRBENBnUuZrraGSMmg2ohgQgPPcgCMCmEoKkuhn6Yq8,8674 -sqlalchemy/dialects/sqlite/json.py,sha256=IZR_pBgC9sWLtP5SXm-o5FR6SScGLi4DEMGbLJzWN8E,2619 -sqlalchemy/dialects/sqlite/provision.py,sha256=2LNwUT3zftd3WeGBJ9UsVKtwXn38KEdDxwZaJ2WXNjM,5575 -sqlalchemy/dialects/sqlite/pysqlcipher.py,sha256=F8y3R0dILJcmqUzHotYF4tLUppe3PSU_C7Xdqm4YV0o,5502 -sqlalchemy/dialects/sqlite/pysqlite.py,sha256=fKhH8ZGMW5XK1F_H9mqz7ofmR4nrsGrGdAgNMPizAEI,28644 -sqlalchemy/dialects/type_migration_guidelines.txt,sha256=gyh3JCauAIFi_9XEfqm3vYv_jb2Eqcz2HjpmC9ZEPMM,8384 -sqlalchemy/engine/__init__.py,sha256=ZlB1LVIV2GjvwyvKm2W0qVYQf51g8AiQvTkHGb1C8A0,2880 -sqlalchemy/engine/__pycache__/__init__.cpython-310.pyc,, -sqlalchemy/engine/__pycache__/_py_processors.cpython-310.pyc,, -sqlalchemy/engine/__pycache__/_py_row.cpython-310.pyc,, -sqlalchemy/engine/__pycache__/_py_util.cpython-310.pyc,, -sqlalchemy/engine/__pycache__/base.cpython-310.pyc,, -sqlalchemy/engine/__pycache__/characteristics.cpython-310.pyc,, -sqlalchemy/engine/__pycache__/create.cpython-310.pyc,, -sqlalchemy/engine/__pycache__/cursor.cpython-310.pyc,, -sqlalchemy/engine/__pycache__/default.cpython-310.pyc,, -sqlalchemy/engine/__pycache__/events.cpython-310.pyc,, -sqlalchemy/engine/__pycache__/interfaces.cpython-310.pyc,, -sqlalchemy/engine/__pycache__/mock.cpython-310.pyc,, -sqlalchemy/engine/__pycache__/processors.cpython-310.pyc,, -sqlalchemy/engine/__pycache__/reflection.cpython-310.pyc,, -sqlalchemy/engine/__pycache__/result.cpython-310.pyc,, -sqlalchemy/engine/__pycache__/row.cpython-310.pyc,, -sqlalchemy/engine/__pycache__/strategies.cpython-310.pyc,, -sqlalchemy/engine/__pycache__/url.cpython-310.pyc,, -sqlalchemy/engine/__pycache__/util.cpython-310.pyc,, -sqlalchemy/engine/_py_processors.py,sha256=XuNIr2kzSay7mAWy14Aq1q2H3ZcineWY-ERfy0yvWpw,3880 -sqlalchemy/engine/_py_row.py,sha256=WASkBfwldq9LApfe1ILn93amhSc0ReihKic2lLO0gxI,3671 -sqlalchemy/engine/_py_util.py,sha256=HB-18ta-qhMrA1oNIDeobt4TtyqLUTzbfRlkN6elRb0,2313 -sqlalchemy/engine/base.py,sha256=3jNhTGA_esLDFLZOIkYWOovsyu1_yfmV-HiqKI8DoaQ,125509 -sqlalchemy/engine/characteristics.py,sha256=P7JlS02X1DKRSpgqpQPwt2sFsatm1L1hVxdvvw3u95s,2419 -sqlalchemy/engine/create.py,sha256=B1K2S_kTzfXrlOcOaPxJlxmKJWo9pbCpyAnODlJOul8,33489 -sqlalchemy/engine/cursor.py,sha256=mNuHRp9SUS-_a_99y1Gj6Bx5jWnFbPf5mn0pa9EpjgQ,76545 -sqlalchemy/engine/default.py,sha256=C0ooBrV9Tv1rsJgR3shVB1416-iL1Lg8ZlZ_GV15RAs,86235 -sqlalchemy/engine/events.py,sha256=1ujDzJrUoanwgk5nlgldti-YukWleLS3wqmt4NFW68c,38375 -sqlalchemy/engine/interfaces.py,sha256=-h2-AdHja9NLAUU7vynDBLa7HxgN6SCRMvl1XmviuOg,116234 -sqlalchemy/engine/mock.py,sha256=y6-Magp0YKkuS0SsSihT8eYxDrt7aMgpY44rbhbxEDw,4326 -sqlalchemy/engine/processors.py,sha256=GvY0nS06PrGMwgwk4HHYX8QGvIUA0vEaNAmuov08BiY,2444 -sqlalchemy/engine/reflection.py,sha256=Ob-mKkHcKHtmxwIdYV3gjPHxaO_HGSyjg_3baOgoqTc,77365 -sqlalchemy/engine/result.py,sha256=I-XjIh-TUcoN4AWk3qBpIN9fa6Tmn22lJUw2CFm26k8,80278 -sqlalchemy/engine/row.py,sha256=dM3rJY3ASx_PzFKzu7CUGErJA_aIQYx1DibLAWnzY8M,12360 -sqlalchemy/engine/strategies.py,sha256=Ryy15JovfbIMsF2sM23z0HYJ_7lXRBQlzpLacbn0mLg,461 -sqlalchemy/engine/url.py,sha256=Lxdv29vz0l-FuWuZS7Gn5uLOxR75OPW1wxQpE58OEg4,31607 -sqlalchemy/engine/util.py,sha256=YSuXV8ngYMaQy7mouAFJiin-rrtD6Pm04KZiIfM-sTs,5849 -sqlalchemy/event/__init__.py,sha256=2QcWKXnqGRkl0lroK7ei8jT2Qbt8SRn_jqlTuYXGLu0,1022 -sqlalchemy/event/__pycache__/__init__.cpython-310.pyc,, -sqlalchemy/event/__pycache__/api.cpython-310.pyc,, -sqlalchemy/event/__pycache__/attr.cpython-310.pyc,, -sqlalchemy/event/__pycache__/base.cpython-310.pyc,, -sqlalchemy/event/__pycache__/legacy.cpython-310.pyc,, -sqlalchemy/event/__pycache__/registry.cpython-310.pyc,, -sqlalchemy/event/api.py,sha256=_TjSW28so8R84M_s7gV6oMlgpvZ0MuM0fNxWEMj4BGM,8452 -sqlalchemy/event/attr.py,sha256=o-Vr3RAGxE2mCXIvlMAGWmdb4My6q-JPkNTQdCW3IpI,21079 -sqlalchemy/event/base.py,sha256=7R8MtAATdP9EybWyvlQDsnoHg5Biauxf13INBlEuLmg,15491 -sqlalchemy/event/legacy.py,sha256=e_NtSjva3NmKLhM8kaUwLk2D705gjym2lYwrgQS0r9I,8457 -sqlalchemy/event/registry.py,sha256=s7MlVn2cOPndD9pm4F7_NFE4sIP5fTGhDdSaRQV4xAU,11247 -sqlalchemy/events.py,sha256=T8_TlVzRzd0Af9AAKUPXPxROwxeux7KuNhHTG0Cxamg,553 -sqlalchemy/exc.py,sha256=qAEWjEGvoPvEdzLalZfqWSCr7D1OUh1LikZPie0Ld3s,24844 -sqlalchemy/ext/__init__.py,sha256=2ow4CHEH4B_6wyAWKh1wqEbAUXG5ia2z2zASTa0Oqdk,333 -sqlalchemy/ext/__pycache__/__init__.cpython-310.pyc,, -sqlalchemy/ext/__pycache__/associationproxy.cpython-310.pyc,, -sqlalchemy/ext/__pycache__/automap.cpython-310.pyc,, -sqlalchemy/ext/__pycache__/baked.cpython-310.pyc,, -sqlalchemy/ext/__pycache__/compiler.cpython-310.pyc,, -sqlalchemy/ext/__pycache__/horizontal_shard.cpython-310.pyc,, -sqlalchemy/ext/__pycache__/hybrid.cpython-310.pyc,, -sqlalchemy/ext/__pycache__/indexable.cpython-310.pyc,, -sqlalchemy/ext/__pycache__/instrumentation.cpython-310.pyc,, -sqlalchemy/ext/__pycache__/mutable.cpython-310.pyc,, -sqlalchemy/ext/__pycache__/orderinglist.cpython-310.pyc,, -sqlalchemy/ext/__pycache__/serializer.cpython-310.pyc,, -sqlalchemy/ext/associationproxy.py,sha256=Bgp1WjYLRhr8zTBv_1eHEj6eKZlTEiinqXofuzreH1A,68020 -sqlalchemy/ext/asyncio/__init__.py,sha256=Qh5SCnlKUSkm1Ko5mzlNZ3_BUuU-aFg0vnlkhEOJdOE,1279 -sqlalchemy/ext/asyncio/__pycache__/__init__.cpython-310.pyc,, -sqlalchemy/ext/asyncio/__pycache__/base.cpython-310.pyc,, -sqlalchemy/ext/asyncio/__pycache__/engine.cpython-310.pyc,, -sqlalchemy/ext/asyncio/__pycache__/exc.cpython-310.pyc,, -sqlalchemy/ext/asyncio/__pycache__/result.cpython-310.pyc,, -sqlalchemy/ext/asyncio/__pycache__/scoping.cpython-310.pyc,, -sqlalchemy/ext/asyncio/__pycache__/session.cpython-310.pyc,, -sqlalchemy/ext/asyncio/base.py,sha256=BRHwuXUqxmJDYBTgaOjRzvwwzG1qn9b3JOs_6opUs-g,9300 -sqlalchemy/ext/asyncio/engine.py,sha256=lWn-w4VrZPJNvtMXOJnwKjPev6RTqygsn0sb5NBqktU,49188 -sqlalchemy/ext/asyncio/exc.py,sha256=AeGYi7BtwZGHv4ZWaJl7wzE4u8dRlzi_06V_ipNPdfU,660 -sqlalchemy/ext/asyncio/result.py,sha256=DrGcMICQThnvVH3YabnERYWONrQ3-E1oM-oVrSFT66E,31546 -sqlalchemy/ext/asyncio/scoping.py,sha256=yVbP-AqxpYASySb5SerYIYMXj97jlauonMIYWr1idGA,52440 -sqlalchemy/ext/asyncio/session.py,sha256=mdrkOinsEgiwFvyfYwad49aG_0iQTrtPMY1_V9bfUqk,63005 -sqlalchemy/ext/automap.py,sha256=VC9p8sDu_EgWfqZ6aGAfVNBuUbnq4O2MjhUfgpY7keA,63089 -sqlalchemy/ext/baked.py,sha256=vHWGGYyceArr5v-nGxgDfwVgnvUjcuGOllAZ5zb_PXI,18392 -sqlalchemy/ext/compiler.py,sha256=pno-btbT4t16LEHUkRyVX5K6ct-MsPfixO41jhUI6R4,20946 -sqlalchemy/ext/declarative/__init__.py,sha256=4a8Wl2P_BqYVYmx-HsPtt_U-NvwpVsAKtfWUSNbA2uY,1883 -sqlalchemy/ext/declarative/__pycache__/__init__.cpython-310.pyc,, -sqlalchemy/ext/declarative/__pycache__/extensions.cpython-310.pyc,, -sqlalchemy/ext/declarative/extensions.py,sha256=GcAzNVSWKg6XXFbOIG6U4vXf0e__QB_Y7XWC8d23WhY,20095 -sqlalchemy/ext/horizontal_shard.py,sha256=I8-KZiCgbtSbGww_vOD6OPzMXXRNUg9X4n1fF8EZTRo,17249 -sqlalchemy/ext/hybrid.py,sha256=u7oR4DuriIuA2vNvde31fmtgMsRkBL667L7pqdzwGaE,54039 -sqlalchemy/ext/indexable.py,sha256=F3NC4VaUkhrx4jDmaEuJLQ2AXatk9l4l_aVI5Uzazbs,11369 -sqlalchemy/ext/instrumentation.py,sha256=biLs17X8UIGzisx-jC6JOphtldi-mlfR2bfumnlar70,16175 -sqlalchemy/ext/mutable.py,sha256=3s_qKPt6It7A-7gdQxjL5p7kFE72raf0lgjimK__lFk,38471 -sqlalchemy/ext/mypy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -sqlalchemy/ext/mypy/__pycache__/__init__.cpython-310.pyc,, -sqlalchemy/ext/mypy/__pycache__/apply.cpython-310.pyc,, -sqlalchemy/ext/mypy/__pycache__/decl_class.cpython-310.pyc,, -sqlalchemy/ext/mypy/__pycache__/infer.cpython-310.pyc,, -sqlalchemy/ext/mypy/__pycache__/names.cpython-310.pyc,, -sqlalchemy/ext/mypy/__pycache__/plugin.cpython-310.pyc,, -sqlalchemy/ext/mypy/__pycache__/util.cpython-310.pyc,, -sqlalchemy/ext/mypy/apply.py,sha256=O3Rh-FCWiWJPeUT0dVsFD_fcL5oEJbrAkB0bAJ5I7Sg,10821 -sqlalchemy/ext/mypy/decl_class.py,sha256=hfTpozOGwxeX9Vbkm12i8SawR91ngs1nfsiPC_f0PSg,17892 -sqlalchemy/ext/mypy/infer.py,sha256=BsiKdH1IvbgRGpqGzDPt1bkDXCcBjzEhQcyHdaToohs,19954 -sqlalchemy/ext/mypy/names.py,sha256=syJhY2UYcodS_NjuNdg-7ay_ZW8kf6xXMbTpMjHrdLQ,11310 -sqlalchemy/ext/mypy/plugin.py,sha256=XF1E_XqZJA-RnI_d0_FWvwFIBTyBRA95sFUP0uqUygk,10053 -sqlalchemy/ext/mypy/util.py,sha256=daH6X26-zYEBR1dnX3K5MJ946HHtgcYSH848LGT_uko,9762 -sqlalchemy/ext/orderinglist.py,sha256=xeonIRL-m5Y4vB2n_1Nab8B61geRLHR0kyC_KnXTS7k,14800 -sqlalchemy/ext/serializer.py,sha256=BhyC7ydKcKKz4vlxyU_8ranVigiGSO1hw_LieCxLCgM,6363 -sqlalchemy/future/__init__.py,sha256=Iio4lD-SrIcuBq0gP7MRgVnU4v36gIMLHiQrSKy-sPM,532 -sqlalchemy/future/__pycache__/__init__.cpython-310.pyc,, -sqlalchemy/future/__pycache__/engine.cpython-310.pyc,, -sqlalchemy/future/engine.py,sha256=4iO5THuQWIy3UGpOOMml23daun4wHdRZ6JVSwWykjJI,514 -sqlalchemy/inspection.py,sha256=tJc_KriMGJ6kSRkKn5MvhxooFbPEAq3W5l-ggFw2sdE,5326 -sqlalchemy/log.py,sha256=_31kfcLRj9dtaQs-VRMHqjPq2sGVYUeSUyO-OiafdlQ,8918 -sqlalchemy/orm/__init__.py,sha256=M1pqaRU6NQuDcycnrbkKHcKjNAo3ZbGne3MOFPK0n1o,8633 -sqlalchemy/orm/__pycache__/__init__.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/_orm_constructors.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/_typing.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/attributes.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/base.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/bulk_persistence.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/clsregistry.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/collections.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/context.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/decl_api.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/decl_base.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/dependency.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/descriptor_props.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/dynamic.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/evaluator.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/events.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/exc.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/identity.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/instrumentation.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/interfaces.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/loading.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/mapped_collection.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/mapper.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/path_registry.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/persistence.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/properties.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/query.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/relationships.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/scoping.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/session.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/state.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/state_changes.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/strategies.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/strategy_options.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/sync.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/unitofwork.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/util.cpython-310.pyc,, -sqlalchemy/orm/__pycache__/writeonly.cpython-310.pyc,, -sqlalchemy/orm/_orm_constructors.py,sha256=5CbxrInx1FYY40QxUNytbWfHRh3X0WH7WeUYXeYOiwQ,102250 -sqlalchemy/orm/_typing.py,sha256=BmW1g-19ze_sbqF9uKlAqrPyp4jxVkmv-jjJmFpYhdg,5192 -sqlalchemy/orm/attributes.py,sha256=sjCxIVm8nVjQnPt_MDgI3-DKZz4WYOsMuLKbEeIDJLk,95458 -sqlalchemy/orm/base.py,sha256=KP34QXa9bLKPOMKHQ2Jf9bpEhTqqrbRG7uMxh7_2TLI,28459 -sqlalchemy/orm/bulk_persistence.py,sha256=_OqUjW9yi3l7VYj1564CYvc8p4CjEXsFYGDt6wR0M0I,72044 -sqlalchemy/orm/clsregistry.py,sha256=dgGogYd-ED3EUIgQkdUesequKBiGTs7csAB6Z5ROjrU,18521 -sqlalchemy/orm/collections.py,sha256=HhJOKqeaDdeYFVyFyU4blvoD6tRsXF4X7TG1xUyhbdk,53778 -sqlalchemy/orm/context.py,sha256=dmqih2qp7EkiIjp6ATihNOBTtAduYdjv8kLp2vah5EY,114925 -sqlalchemy/orm/decl_api.py,sha256=w2FWGSAgq2_T7r3g1DaaLLX9Y_AQw6UCwrTxU23EcVo,65649 -sqlalchemy/orm/decl_base.py,sha256=gGasl-rchnQxz9YcQESMe0zn201d5sFhx39Yph1trWc,83425 -sqlalchemy/orm/dependency.py,sha256=vXDcvgrY8_9x5lLWIpoLvzwuN0b-2-DwhXux1nNf0E8,48885 -sqlalchemy/orm/descriptor_props.py,sha256=fwsr88pQytZLQ8r0u-nXjgk1evU9MYtxmvgHs42gl_I,38502 -sqlalchemy/orm/dynamic.py,sha256=MWkalEIrgW0p_CRr5Uclt6Ak-jUvcpyYHaTWidIuXdc,8898 -sqlalchemy/orm/evaluator.py,sha256=lQ_uAoUBKJtQAyvhyFfHOf8gvxk0_-r4KpqQR53-COE,12293 -sqlalchemy/orm/events.py,sha256=UguRQ343Q-rGxKjPQTgqOs5uVUkW1rcLBWoOSZUHirI,130506 -sqlalchemy/orm/exc.py,sha256=k9K4M3zZvE7877TiTOI5gG4MOgnBEbKqvAsP43JU2Dk,7583 -sqlalchemy/orm/identity.py,sha256=mVaoHHtniM1-wSqJ0VPu2v6LaSJfer4_vLsxFVw8aXc,9551 -sqlalchemy/orm/instrumentation.py,sha256=VIWeAsEMveE2N-9W6mS5Lw40wwldHL_fGhln0EowEsY,25207 -sqlalchemy/orm/interfaces.py,sha256=smpV-eYelH0Eswfav_kxOFRB4VE9_Nm0BPUNDMSqYSI,49878 -sqlalchemy/orm/loading.py,sha256=qqr6wMPgP5qChbiaz4s4ea-fRNiqyc8Fu9_wj_UjfhQ,58032 -sqlalchemy/orm/mapped_collection.py,sha256=kxy8_wQPjbjEMxCEe-l5lgH9wza_JedWzcksXXjLK9E,20260 -sqlalchemy/orm/mapper.py,sha256=NGoiIjmTIK28MyvDnxgWkWdYv2e7fSUroqvoj0dPpOg,175446 -sqlalchemy/orm/path_registry.py,sha256=hvTSOojMC31-nUJFHz2DynIh4_x85QQzemn7RFTdddc,26436 -sqlalchemy/orm/persistence.py,sha256=flpr9E1BjytqAeijNJu13DiYcVf7rYUXCQce9-o4WCg,62271 -sqlalchemy/orm/properties.py,sha256=unDpqioAz2DGH-ftJrJ_V9G0QcqVeD-PzTvqbTY6bj4,27622 -sqlalchemy/orm/query.py,sha256=fp5Oe5J7_RMHBcw74ScgOLmrfEm-zkZFDiFJRTJVfP0,121046 -sqlalchemy/orm/relationships.py,sha256=1ZN1WTkSCEICtl0cRpUyIRfeF0VxvAjtjiRfQ_lMrPE,131317 -sqlalchemy/orm/scoping.py,sha256=O1-yguXL3W9Vtq8_wtC2B9Nc_0LtPB50NeOe8H6FrhA,77441 -sqlalchemy/orm/session.py,sha256=FivieQ2V4UjKP08zJij8RbiwHDqao9fbfqoO7XdIb6U,193191 -sqlalchemy/orm/state.py,sha256=UrAw3nTX9wlFoJbzKL1DXvD_KGvgfcD8xMnqzM5qO5U,38719 -sqlalchemy/orm/state_changes.py,sha256=9jHui0oF4V7xIoL8hSUiFDhHrJVPmq3doX5zxY5dR3g,7013 -sqlalchemy/orm/strategies.py,sha256=dUNlfzmWDzRb1JOG_xFisMtlmDTxeQLn4GkmBsN9b3o,117432 -sqlalchemy/orm/strategy_options.py,sha256=cBic_Tm6rwmOiHncwUC8eM3SWPcVJkHM5T4YFwSto4U,84304 -sqlalchemy/orm/sync.py,sha256=jLZWFRsn2iobdX23gQlthxhnFHQum3mWQHHcx8uj0t4,5912 -sqlalchemy/orm/unitofwork.py,sha256=Jyri2dH5VmkX7oN-XWRzzKMCjQAzvBPWWem5XQL5SYY,27829 -sqlalchemy/orm/util.py,sha256=4Mk2QOA-XjVybwEbdExpQ-9w9PKCPffYh1blvNl4CWU,82375 -sqlalchemy/orm/writeonly.py,sha256=AKgGFWiOSAvYoqvAaKA9wiOJkZ6pvCR3AM-K1I51crY,20154 -sqlalchemy/pool/__init__.py,sha256=rvWJtziqz1Yp_9NU7r-cKH1WKi8MwcjZX6kuBYu_s6s,1859 -sqlalchemy/pool/__pycache__/__init__.cpython-310.pyc,, -sqlalchemy/pool/__pycache__/base.cpython-310.pyc,, -sqlalchemy/pool/__pycache__/events.cpython-310.pyc,, -sqlalchemy/pool/__pycache__/impl.cpython-310.pyc,, -sqlalchemy/pool/base.py,sha256=3-o9EcxLi_D6lrd5SDR6dhBv9oiMf-JX5SD-BekG7FE,53869 -sqlalchemy/pool/events.py,sha256=dQDxP7Rwz3nDv2xkxQvkq3Eyj-00sBYIoF02lrKUHLM,13571 -sqlalchemy/pool/impl.py,sha256=FpgcyklqBciEorQq5M0XxsbZG6HD-tqrXuqxA3wEkO8,18292 -sqlalchemy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -sqlalchemy/schema.py,sha256=Liwt9G2PyOZZGfQkTGx7fFjTNH2o8t9kPcCAIHF9etw,3264 -sqlalchemy/sql/__init__.py,sha256=9ffSt_Gl2TJYE4_PyWxtRNfBF8yGmIV2J_CaoAyx2QQ,5965 -sqlalchemy/sql/__pycache__/__init__.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/_dml_constructors.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/_elements_constructors.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/_orm_types.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/_py_util.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/_selectable_constructors.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/_typing.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/annotation.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/base.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/cache_key.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/coercions.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/compiler.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/crud.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/ddl.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/default_comparator.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/dml.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/elements.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/events.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/expression.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/functions.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/lambdas.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/naming.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/operators.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/roles.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/schema.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/selectable.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/sqltypes.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/traversals.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/type_api.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/util.cpython-310.pyc,, -sqlalchemy/sql/__pycache__/visitors.cpython-310.pyc,, -sqlalchemy/sql/_dml_constructors.py,sha256=CRI_cxOwcSBPUhouMuNoxBVb3EB0b6zQo6YSjI1d2Vo,4007 -sqlalchemy/sql/_elements_constructors.py,sha256=gSshp_t_TteDk4mvekbPBDABWDW-umShMPmjCrUrLBs,64764 -sqlalchemy/sql/_orm_types.py,sha256=WIdXTDALHCd3PuzpAPot2psv505T817wnQ3oXuGH7CU,640 -sqlalchemy/sql/_py_util.py,sha256=YCkagVa5Ov1OjCfMhUbNa527zX2NsUGPuCLEWmbQQMA,2248 -sqlalchemy/sql/_selectable_constructors.py,sha256=kHsJViBwydt3l-aiqtI2yLK4BgjEsVB9lpKPuWSWv60,19454 -sqlalchemy/sql/_typing.py,sha256=WSEwGys86fVA_WAY6Nbu1Qn3Zam25Togi-OxM7Nlu2E,12724 -sqlalchemy/sql/annotation.py,sha256=2c7wyGxH2gk9TIZELK3x8OSbQBKE4MGAFEWv3hefIbI,18881 -sqlalchemy/sql/base.py,sha256=d7sIYp0XUH6FPqbehP5VC_8o31PuamwQgBILiotwE3o,76137 -sqlalchemy/sql/cache_key.py,sha256=AaPpvFDwYMfGixEmEto02flVKyf4UifGdNbu2Z4rfMc,33773 -sqlalchemy/sql/coercions.py,sha256=YXSGtgtUIJeDPPjtBpFA2PuZ0bP-x8E6N01OIDWJvxw,41959 -sqlalchemy/sql/compiler.py,sha256=G1Vv0zq1RSjJe0fKE0ih8UXUMCKIljBHqbw-BSoBLqg,276204 -sqlalchemy/sql/crud.py,sha256=rJ9U55a0oVH5cl4Su5mwCpS6UogZsz1ue6bNvEShrMc,57295 -sqlalchemy/sql/ddl.py,sha256=J9wtcvAfh2E08Fg-bjr_TWQGmYWWn4vSr5VFJPxThk4,47069 -sqlalchemy/sql/default_comparator.py,sha256=-sSDLcxHfL4jgIh5f_g2-8wOGazDHhTPyB0pA9Gr_Uk,17212 -sqlalchemy/sql/dml.py,sha256=vzOpq8TqhdYN7jfla27c4pQITdO0IPcKdV5y92vjONM,67380 -sqlalchemy/sql/elements.py,sha256=90qmYcYRdwEI_E4dREe98AXIUO7pAoyZ3D4pSq5KEko,176494 -sqlalchemy/sql/events.py,sha256=ELMw8mkKUvVVeb354hfD_9Fk-KSX28hCfNdnMgnv2zI,18756 -sqlalchemy/sql/expression.py,sha256=bD-nG9OxLmhgvKkCKFpMtycxq8szzUsxhDeH3E9WmkQ,7748 -sqlalchemy/sql/functions.py,sha256=YMkPdiSBZnrA4ZrcolA58w1nsoEQbwrL38kMKwiLZP0,56289 -sqlalchemy/sql/lambdas.py,sha256=lKggh8EyKJThwop8ulclAcMzJh4gydSTwEL8cyMCN10,50759 -sqlalchemy/sql/naming.py,sha256=3J_KScJBe7dPY4Stj5veIzGfSnaWG9-f7IGbxhc7luE,7077 -sqlalchemy/sql/operators.py,sha256=nqVC7ggPHfwF4QFMZz7uk0WvPUdxw7s92jjTGkgLJzs,78483 -sqlalchemy/sql/roles.py,sha256=Rkbx36tMWkq6uu6bl1DMDkLQY8VFpKZtqfmYxooE8MQ,7952 -sqlalchemy/sql/schema.py,sha256=5oaelPn8oUFB9b7XYJ4OjNqPhWQXvKie3UoReB0KfgY,233840 -sqlalchemy/sql/selectable.py,sha256=QCeqrL6dU1-ZncSO3z0G5KksghMZyanAm6Egtj_5Xak,239710 -sqlalchemy/sql/sqltypes.py,sha256=HsFU48oRsD-bLDSHim6LVcyZUpkPxK2eB-MUllRBZyg,129894 -sqlalchemy/sql/traversals.py,sha256=3s9dNBNwsrpg57x0vxF5J-bdeZpzURGEbfpUhaCt1wU,34622 -sqlalchemy/sql/type_api.py,sha256=QcUD2j49soLl07LQVHdDilZ1kUkRC_USwJx8xI6Qcyg,87359 -sqlalchemy/sql/util.py,sha256=5UCudam-vT7lMoYKv2juS483vjdiY2kcFejfjk17KlI,49770 -sqlalchemy/sql/visitors.py,sha256=1jPX8S1C6pFovW0HWkliVsI0BD0tmEUN8GYZ0F5Di6o,37534 -sqlalchemy/testing/__init__.py,sha256=I_4C9vgF-GRODJ_IRNxIXXSQHgUDNVggGFFv6v0BJBQ,3221 -sqlalchemy/testing/__pycache__/__init__.cpython-310.pyc,, -sqlalchemy/testing/__pycache__/assertions.cpython-310.pyc,, -sqlalchemy/testing/__pycache__/assertsql.cpython-310.pyc,, -sqlalchemy/testing/__pycache__/asyncio.cpython-310.pyc,, -sqlalchemy/testing/__pycache__/config.cpython-310.pyc,, -sqlalchemy/testing/__pycache__/engines.cpython-310.pyc,, -sqlalchemy/testing/__pycache__/entities.cpython-310.pyc,, -sqlalchemy/testing/__pycache__/exclusions.cpython-310.pyc,, -sqlalchemy/testing/__pycache__/pickleable.cpython-310.pyc,, -sqlalchemy/testing/__pycache__/profiling.cpython-310.pyc,, -sqlalchemy/testing/__pycache__/provision.cpython-310.pyc,, -sqlalchemy/testing/__pycache__/requirements.cpython-310.pyc,, -sqlalchemy/testing/__pycache__/schema.cpython-310.pyc,, -sqlalchemy/testing/__pycache__/util.cpython-310.pyc,, -sqlalchemy/testing/__pycache__/warnings.cpython-310.pyc,, -sqlalchemy/testing/assertions.py,sha256=K_wIe570kI6xbtZmWMnLiuhBaCFyoQx-iaau9CR1PLI,32428 -sqlalchemy/testing/assertsql.py,sha256=F8R_LgsUiZ31sgkCigFbxFcVOzt57EI1tRSHgk88CjQ,17290 -sqlalchemy/testing/asyncio.py,sha256=7LatmcAk09IVuOMWcAdpVltLyhDWVG1cV7iOaR6soz0,3858 -sqlalchemy/testing/config.py,sha256=L5Z7Inl6th23xpuVDo6Fhn3ItMca0yBT6YofkYRZiKI,11397 -sqlalchemy/testing/engines.py,sha256=mTwCxPdb6K8S2y-O7dcJwO5kEE4qIAU8Kp6qawiP2TM,13824 -sqlalchemy/testing/entities.py,sha256=E7IkhsQaziZSOZkKkFnfUvB0165SH5MP1q4QkGKdf98,3471 -sqlalchemy/testing/exclusions.py,sha256=rWyo1SZpZ-EjNkvr-O085A3XSAqxSL5uqgOE4L5mzM0,12879 -sqlalchemy/testing/fixtures/__init__.py,sha256=SHlEUIlUaqU2xjziZeBDL1Yd_URWou6dnZqG8s-Ay0g,1226 -sqlalchemy/testing/fixtures/__pycache__/__init__.cpython-310.pyc,, -sqlalchemy/testing/fixtures/__pycache__/base.cpython-310.pyc,, -sqlalchemy/testing/fixtures/__pycache__/mypy.cpython-310.pyc,, -sqlalchemy/testing/fixtures/__pycache__/orm.cpython-310.pyc,, -sqlalchemy/testing/fixtures/__pycache__/sql.cpython-310.pyc,, -sqlalchemy/testing/fixtures/base.py,sha256=HQPgUuOnBVNUm9l7dcoT4AuggG0jXW4a23dVZhbSA9k,12622 -sqlalchemy/testing/fixtures/mypy.py,sha256=TGTo8x02m9Qt10-iRjic_F66-uA2T82QbKYmpUyVzCw,12153 -sqlalchemy/testing/fixtures/orm.py,sha256=VZBnFHHfQpVdLqV-F9myH886uq3clDIzixMwEe5TjMc,6322 -sqlalchemy/testing/fixtures/sql.py,sha256=1c2omUuUSRlWNYtKr3ADJFaQeFnq1EnQtKTKn67B-2Q,16196 -sqlalchemy/testing/pickleable.py,sha256=_E141_vPqtE-H_6cNBnWRDuMtvjeeBKovOI2_P9KJGQ,2988 -sqlalchemy/testing/plugin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -sqlalchemy/testing/plugin/__pycache__/__init__.cpython-310.pyc,, -sqlalchemy/testing/plugin/__pycache__/bootstrap.cpython-310.pyc,, -sqlalchemy/testing/plugin/__pycache__/plugin_base.cpython-310.pyc,, -sqlalchemy/testing/plugin/__pycache__/pytestplugin.cpython-310.pyc,, -sqlalchemy/testing/plugin/bootstrap.py,sha256=3WkvZXQad0oyxg6nJyLEthN30zBuueB33LFxWeMBdKc,1482 -sqlalchemy/testing/plugin/plugin_base.py,sha256=300KMijfgPiKFbjj1F_6Dj6HAH8T-EuHuX3CQ6Z1m00,22110 -sqlalchemy/testing/plugin/pytestplugin.py,sha256=IYmAr-FaAODCInWpnKJCNGw03cyRJK5YcZ07hrmtSNg,28151 -sqlalchemy/testing/profiling.py,sha256=BLknvjemW8oDl0aCSUXQw_ESgoFfx0RoeQYclzhNv0Q,10472 -sqlalchemy/testing/provision.py,sha256=fnmlxUacztdUcZOPTiSJ-rYe-tpIwyl8O97YRI24FLk,14686 -sqlalchemy/testing/requirements.py,sha256=qc5zgxUJGmpZjKO4pVSDlKOYs_f8_W7KienkLgoJJZ4,52702 -sqlalchemy/testing/schema.py,sha256=O76C-woOcc6qjk1csf9yljor-6wjRZzKQNrXdmLLtw8,6737 -sqlalchemy/testing/suite/__init__.py,sha256=u3lEc0j47s7Dad_2SVWOZ6EU2aOMRWqE_WrQ17HmBsA,489 -sqlalchemy/testing/suite/__pycache__/__init__.cpython-310.pyc,, -sqlalchemy/testing/suite/__pycache__/test_cte.cpython-310.pyc,, -sqlalchemy/testing/suite/__pycache__/test_ddl.cpython-310.pyc,, -sqlalchemy/testing/suite/__pycache__/test_deprecations.cpython-310.pyc,, -sqlalchemy/testing/suite/__pycache__/test_dialect.cpython-310.pyc,, -sqlalchemy/testing/suite/__pycache__/test_insert.cpython-310.pyc,, -sqlalchemy/testing/suite/__pycache__/test_reflection.cpython-310.pyc,, -sqlalchemy/testing/suite/__pycache__/test_results.cpython-310.pyc,, -sqlalchemy/testing/suite/__pycache__/test_rowcount.cpython-310.pyc,, -sqlalchemy/testing/suite/__pycache__/test_select.cpython-310.pyc,, -sqlalchemy/testing/suite/__pycache__/test_sequence.cpython-310.pyc,, -sqlalchemy/testing/suite/__pycache__/test_types.cpython-310.pyc,, -sqlalchemy/testing/suite/__pycache__/test_unicode_ddl.cpython-310.pyc,, -sqlalchemy/testing/suite/__pycache__/test_update_delete.cpython-310.pyc,, -sqlalchemy/testing/suite/test_cte.py,sha256=RFvWCSmmy3-JEIXIcZEkYpjt_bJQTe7SvfnpXeUFl9o,6410 -sqlalchemy/testing/suite/test_ddl.py,sha256=VQuejaNUMN484DxwkYL57ZEnPY5UhNGWkQVgquPrWHA,12168 -sqlalchemy/testing/suite/test_deprecations.py,sha256=8mhjZyrECXiVyE88BJLbyj4Jz_niXOs6ZOXd9rFAWsk,5229 -sqlalchemy/testing/suite/test_dialect.py,sha256=C3aUUd16iS19WJrqZLGkG4DPhWMAADTCfTDkYYlUz5U,23407 -sqlalchemy/testing/suite/test_insert.py,sha256=NVPw5lMxNSY99E7p_YZ2bBJG2C4SBCGv2nPyQtrxQnk,17948 -sqlalchemy/testing/suite/test_reflection.py,sha256=si5nXSHcBWJRrcFC-0sto1m9jXf6hYwlYuQ43YqXiJo,107540 -sqlalchemy/testing/suite/test_results.py,sha256=fl8qv9YdcEqSQFe1fDf7vrFk7Cam_MzJiETLzx5KYuU,16127 -sqlalchemy/testing/suite/test_rowcount.py,sha256=ID2Y1jDZ1MjQyZldWQPt40qD2eu0haTaYB2AdWQ1Nnk,6356 -sqlalchemy/testing/suite/test_select.py,sha256=3SCpfuy-D0q0l4elRNgMc0KlIjo3Nh1nGHo0uEZKAUo,60207 -sqlalchemy/testing/suite/test_sequence.py,sha256=WqriMWJTPnmCBydP5vehSD2zXxwSyFGug_K2IyEIRSY,9983 -sqlalchemy/testing/suite/test_types.py,sha256=NObEx25I9LQdMaW470ACm4w9fWRVYf9B0i1VafrOhGQ,63791 -sqlalchemy/testing/suite/test_unicode_ddl.py,sha256=1n0xf7EyGuLYIMiwc5lANGWvCrmoXf3gtQM93sMcd3c,6070 -sqlalchemy/testing/suite/test_update_delete.py,sha256=cj9C7U8MFxMSfdckAdODQHsnqwOtU112zqk5U8iyCTM,1710 -sqlalchemy/testing/util.py,sha256=QH355pEJeqUn4h2LPTleNGinD50hE40R1HRW2LEXF6U,14599 -sqlalchemy/testing/warnings.py,sha256=ymXClxi_YtysQJZZQzgjT-d3tW63z4pOfKJsTqaBLMQ,1598 -sqlalchemy/types.py,sha256=bV5WvXIjsG-bWRcwCVACJ6m3tlSMS5XNdtXVXGTMeI8,3244 -sqlalchemy/util/__init__.py,sha256=NILyXDswLeG8lpxsPh2iIOs4BweaFz7tbn3wQ0-hK5c,8404 -sqlalchemy/util/__pycache__/__init__.cpython-310.pyc,, -sqlalchemy/util/__pycache__/_collections.cpython-310.pyc,, -sqlalchemy/util/__pycache__/_concurrency_py3k.cpython-310.pyc,, -sqlalchemy/util/__pycache__/_has_cy.cpython-310.pyc,, -sqlalchemy/util/__pycache__/_py_collections.cpython-310.pyc,, -sqlalchemy/util/__pycache__/compat.cpython-310.pyc,, -sqlalchemy/util/__pycache__/concurrency.cpython-310.pyc,, -sqlalchemy/util/__pycache__/deprecations.cpython-310.pyc,, -sqlalchemy/util/__pycache__/langhelpers.cpython-310.pyc,, -sqlalchemy/util/__pycache__/preloaded.cpython-310.pyc,, -sqlalchemy/util/__pycache__/queue.cpython-310.pyc,, -sqlalchemy/util/__pycache__/tool_support.cpython-310.pyc,, -sqlalchemy/util/__pycache__/topological.cpython-310.pyc,, -sqlalchemy/util/__pycache__/typing.cpython-310.pyc,, -sqlalchemy/util/_collections.py,sha256=yUsrZu5aQh0lK_ht3540KXsoaM-lz4nqK1gHXx29lBc,21124 -sqlalchemy/util/_concurrency_py3k.py,sha256=LhS5ppk9UGJ2P36rbHaauV3hl57p1Zw_b3SzLkkOiTE,8544 -sqlalchemy/util/_has_cy.py,sha256=7V8ZfMrlED0bIc6DWsBC_lTEP1JEihWKPdjyLJtxfaE,1268 -sqlalchemy/util/_py_collections.py,sha256=lwf6V7hnvqP_88eVKZa6GqshDxyBkhPczaIhpfrXE-Y,17217 -sqlalchemy/util/compat.py,sha256=xwPQl5QoV9Nrje-ZD_csX0penWXrhFi667v5WMdloB8,9416 -sqlalchemy/util/concurrency.py,sha256=rLb4LbPSTnGaSb381_e3VwHbEjqiF10lkarFjihywTY,2353 -sqlalchemy/util/deprecations.py,sha256=JMG1QpXb_HhCssZBkm0_vvCSWiCMIbAwIlULtP4DNgs,12514 -sqlalchemy/util/langhelpers.py,sha256=iJO7hWDKfeAndgu6iDcWRx3tMmbNquzSnxDruMK6130,67147 -sqlalchemy/util/preloaded.py,sha256=tMuj_6GELLQj1I8YRAKu--VLnxI9kH8Si_IwlDfre4M,6055 -sqlalchemy/util/queue.py,sha256=-DPCfkQgtqP9znBvm3bRdYjAWs4dysflpL805IMf22A,10529 -sqlalchemy/util/tool_support.py,sha256=SOfhWXzZXqx5RYX9WM_CeBJGGgV0eaxpv96VFb5KEKs,6167 -sqlalchemy/util/topological.py,sha256=-i2pX8AD9hjaqpLDu5P3R5w6D8_t5nDWlwLI6xXYyyc,3578 -sqlalchemy/util/typing.py,sha256=yFUquXzDGUuoyn4idoBkIsqjF_2noHM34DDInh2uERs,16207 diff --git a/venv/Lib/site-packages/SQLAlchemy-2.0.20.dist-info/REQUESTED b/venv/Lib/site-packages/SQLAlchemy-2.0.20.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 diff --git a/venv/Lib/site-packages/SQLAlchemy-2.0.20.dist-info/WHEEL b/venv/Lib/site-packages/SQLAlchemy-2.0.20.dist-info/WHEEL deleted file mode 100644 index ec555de..0000000 --- a/venv/Lib/site-packages/SQLAlchemy-2.0.20.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.41.1) -Root-Is-Purelib: false -Tag: cp310-cp310-win_amd64 - diff --git a/venv/Lib/site-packages/SQLAlchemy-2.0.20.dist-info/top_level.txt b/venv/Lib/site-packages/SQLAlchemy-2.0.20.dist-info/top_level.txt deleted file mode 100644 index 39fb2be..0000000 --- a/venv/Lib/site-packages/SQLAlchemy-2.0.20.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -sqlalchemy diff --git a/venv/Lib/site-packages/flask_sqlalchemy-3.0.5.dist-info/INSTALLER b/venv/Lib/site-packages/flask_sqlalchemy-3.0.5.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/Lib/site-packages/flask_sqlalchemy-3.0.5.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/Lib/site-packages/flask_sqlalchemy-3.0.5.dist-info/LICENSE.rst b/venv/Lib/site-packages/flask_sqlalchemy-3.0.5.dist-info/LICENSE.rst deleted file mode 100644 index 9d227a0..0000000 --- a/venv/Lib/site-packages/flask_sqlalchemy-3.0.5.dist-info/LICENSE.rst +++ /dev/null @@ -1,28 +0,0 @@ -Copyright 2010 Pallets - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/Lib/site-packages/flask_sqlalchemy-3.0.5.dist-info/METADATA b/venv/Lib/site-packages/flask_sqlalchemy-3.0.5.dist-info/METADATA deleted file mode 100644 index f0cb56c..0000000 --- a/venv/Lib/site-packages/flask_sqlalchemy-3.0.5.dist-info/METADATA +++ /dev/null @@ -1,104 +0,0 @@ -Metadata-Version: 2.1 -Name: Flask-SQLAlchemy -Version: 3.0.5 -Summary: Add SQLAlchemy support to your Flask application. -Maintainer-email: Pallets -Requires-Python: >=3.7 -Description-Content-Type: text/x-rst -Classifier: Development Status :: 5 - Production/Stable -Classifier: Environment :: Web Environment -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: BSD License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content -Requires-Dist: flask>=2.2.5 -Requires-Dist: sqlalchemy>=1.4.18 -Project-URL: Changes, https://flask-sqlalchemy.palletsprojects.com/changes/ -Project-URL: Chat, https://discord.gg/pallets -Project-URL: Documentation, https://flask-sqlalchemy.palletsprojects.com -Project-URL: Donate, https://palletsprojects.com/donate -Project-URL: Issue Tracker, https://github.com/pallets-eco/flask-sqlalchemy/issues/ -Project-URL: Source Code, https://github.com/pallets-eco/flask-sqlalchemy/ - -Flask-SQLAlchemy -================ - -Flask-SQLAlchemy is an extension for `Flask`_ that adds support for -`SQLAlchemy`_ to your application. It aims to simplify using SQLAlchemy -with Flask by providing useful defaults and extra helpers that make it -easier to accomplish common tasks. - -.. _Flask: https://palletsprojects.com/p/flask/ -.. _SQLAlchemy: https://www.sqlalchemy.org - - -Installing ----------- - -Install and update using `pip`_: - -.. code-block:: text - - $ pip install -U Flask-SQLAlchemy - -.. _pip: https://pip.pypa.io/en/stable/getting-started/ - - -A Simple Example ----------------- - -.. code-block:: python - - from flask import Flask - from flask_sqlalchemy import SQLAlchemy - - app = Flask(__name__) - app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///example.sqlite" - db = SQLAlchemy(app) - - class User(db.Model): - id = db.Column(db.Integer, primary_key=True) - username = db.Column(db.String, unique=True, nullable=False) - - with app.app_context(): - db.create_all() - - db.session.add(User(username="example")) - db.session.commit() - - users = db.session.execute(db.select(User)).scalars() - - -Contributing ------------- - -For guidance on setting up a development environment and how to make a -contribution to Flask-SQLAlchemy, see the `contributing guidelines`_. - -.. _contributing guidelines: https://github.com/pallets-eco/flask-sqlalchemy/blob/main/CONTRIBUTING.rst - - -Donate ------- - -The Pallets organization develops and supports Flask-SQLAlchemy and -other popular packages. In order to grow the community of contributors -and users, and allow the maintainers to devote more time to the -projects, `please donate today`_. - -.. _please donate today: https://palletsprojects.com/donate - - -Links ------ - -- Documentation: https://flask-sqlalchemy.palletsprojects.com/ -- Changes: https://flask-sqlalchemy.palletsprojects.com/changes/ -- PyPI Releases: https://pypi.org/project/Flask-SQLAlchemy/ -- Source Code: https://github.com/pallets-eco/flask-sqlalchemy/ -- Issue Tracker: https://github.com/pallets-eco/flask-sqlalchemy/issues/ -- Website: https://palletsprojects.com/ -- Twitter: https://twitter.com/PalletsTeam -- Chat: https://discord.gg/pallets - diff --git a/venv/Lib/site-packages/flask_sqlalchemy-3.0.5.dist-info/RECORD b/venv/Lib/site-packages/flask_sqlalchemy-3.0.5.dist-info/RECORD deleted file mode 100644 index de77aad..0000000 --- a/venv/Lib/site-packages/flask_sqlalchemy-3.0.5.dist-info/RECORD +++ /dev/null @@ -1,27 +0,0 @@ -flask_sqlalchemy-3.0.5.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -flask_sqlalchemy-3.0.5.dist-info/LICENSE.rst,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475 -flask_sqlalchemy-3.0.5.dist-info/METADATA,sha256=TP2sMyz9YuKRrcMbnrPjSC0A3NWysepDoNhKaPc_efI,3264 -flask_sqlalchemy-3.0.5.dist-info/RECORD,, -flask_sqlalchemy-3.0.5.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -flask_sqlalchemy-3.0.5.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81 -flask_sqlalchemy/__init__.py,sha256=7toyeeZoZtSxWWqUTZGMiwIgyzTPhyDaCSMGSkUd-Vs,1250 -flask_sqlalchemy/__pycache__/__init__.cpython-310.pyc,, -flask_sqlalchemy/__pycache__/cli.cpython-310.pyc,, -flask_sqlalchemy/__pycache__/extension.cpython-310.pyc,, -flask_sqlalchemy/__pycache__/model.cpython-310.pyc,, -flask_sqlalchemy/__pycache__/pagination.cpython-310.pyc,, -flask_sqlalchemy/__pycache__/query.cpython-310.pyc,, -flask_sqlalchemy/__pycache__/record_queries.cpython-310.pyc,, -flask_sqlalchemy/__pycache__/session.cpython-310.pyc,, -flask_sqlalchemy/__pycache__/table.cpython-310.pyc,, -flask_sqlalchemy/__pycache__/track_modifications.cpython-310.pyc,, -flask_sqlalchemy/cli.py,sha256=pg3QDxP36GW2qnwe_CpPtkRhPchyVSGM6zlBNWuNCFE,484 -flask_sqlalchemy/extension.py,sha256=K_PMP0TlxSptgJqsK7Owq2DB20R0KkjgVolbZUbzwhA,38293 -flask_sqlalchemy/model.py,sha256=LvR7sWR_9I5EYkKFs9U7r00W57hzg7wbXF-CXrYA9tw,7112 -flask_sqlalchemy/pagination.py,sha256=JFpllrqkRkwacb8DAmQWaz9wsvQa0dypfSkhUDSC2ws,11119 -flask_sqlalchemy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -flask_sqlalchemy/query.py,sha256=Uls9qbmnpb9Vba43EDfsRP17eHJ0X4VG7SE22tH5R3g,3748 -flask_sqlalchemy/record_queries.py,sha256=DhEhgKRdTzT63Ti399BG_tzy9tLlyx9efA00FgPLFxc,4306 -flask_sqlalchemy/session.py,sha256=e3oOf2gClNJrXJ5o5kHsTjTO5MQsah_uNFMtQHi_LjI,3189 -flask_sqlalchemy/table.py,sha256=wAPOy8qwyAxpMwOIUJY4iMOultzz2W0D6xvBkQ7U2CE,859 -flask_sqlalchemy/track_modifications.py,sha256=yieyozj7IiVzwnAGZ-ZrgqrzjrUfG0kPrXBfW_hStSU,2755 diff --git a/venv/Lib/site-packages/flask_sqlalchemy-3.0.5.dist-info/REQUESTED b/venv/Lib/site-packages/flask_sqlalchemy-3.0.5.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 diff --git a/venv/Lib/site-packages/flask_sqlalchemy-3.0.5.dist-info/WHEEL b/venv/Lib/site-packages/flask_sqlalchemy-3.0.5.dist-info/WHEEL deleted file mode 100644 index 3b5e64b..0000000 --- a/venv/Lib/site-packages/flask_sqlalchemy-3.0.5.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: flit 3.9.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/venv/Lib/site-packages/flask_sqlalchemy/__init__.py b/venv/Lib/site-packages/flask_sqlalchemy/__init__.py index 5d530cf..c2fa059 100644 --- a/venv/Lib/site-packages/flask_sqlalchemy/__init__.py +++ b/venv/Lib/site-packages/flask_sqlalchemy/__init__.py @@ -4,43 +4,23 @@ import typing as t from .extension import SQLAlchemy -__version__ = "3.0.5" - __all__ = [ "SQLAlchemy", ] -_deprecated_map = { - "Model": ".model.Model", - "DefaultMeta": ".model.DefaultMeta", - "Pagination": ".pagination.Pagination", - "BaseQuery": ".query.Query", - "get_debug_queries": ".record_queries.get_recorded_queries", - "SignallingSession": ".session.Session", - "before_models_committed": ".track_modifications.before_models_committed", - "models_committed": ".track_modifications.models_committed", -} - def __getattr__(name: str) -> t.Any: - import importlib - import warnings - - if name in _deprecated_map: - path = _deprecated_map[name] - import_path, _, new_name = path.rpartition(".") - action = "moved and renamed" - - if new_name == name: - action = "moved" + if name == "__version__": + import importlib.metadata + import warnings warnings.warn( - f"'{name}' has been {action} to '{path[1:]}'. The top-level import is" - " deprecated and will be removed in Flask-SQLAlchemy 3.1.", + "The '__version__' attribute is deprecated and will be removed in" + " Flask-SQLAlchemy 3.2. Use feature detection or" + " 'importlib.metadata.version(\"flask-sqlalchemy\")' instead.", DeprecationWarning, stacklevel=2, ) - mod = importlib.import_module(import_path, __name__) - return getattr(mod, new_name) + return importlib.metadata.version("flask-sqlalchemy") raise AttributeError(name) diff --git a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/__init__.cpython-310.pyc index 7ad8a8e..5f20b56 100644 Binary files a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/cli.cpython-310.pyc b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/cli.cpython-310.pyc index 45c402a..e5454dc 100644 Binary files a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/cli.cpython-310.pyc and b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/cli.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/extension.cpython-310.pyc b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/extension.cpython-310.pyc index 69c489e..7ba3580 100644 Binary files a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/extension.cpython-310.pyc and b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/extension.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/model.cpython-310.pyc b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/model.cpython-310.pyc index f21b73d..6afbfbe 100644 Binary files a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/model.cpython-310.pyc and b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/model.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/pagination.cpython-310.pyc b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/pagination.cpython-310.pyc index 9950663..bdcbf5e 100644 Binary files a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/pagination.cpython-310.pyc and b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/pagination.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/query.cpython-310.pyc b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/query.cpython-310.pyc index 2a2e35c..3794406 100644 Binary files a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/query.cpython-310.pyc and b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/query.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/record_queries.cpython-310.pyc b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/record_queries.cpython-310.pyc index 76330f2..293fe3c 100644 Binary files a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/record_queries.cpython-310.pyc and b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/record_queries.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/session.cpython-310.pyc b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/session.cpython-310.pyc index c15eae2..3477d93 100644 Binary files a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/session.cpython-310.pyc and b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/session.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/table.cpython-310.pyc b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/table.cpython-310.pyc index e69a303..4408fb2 100644 Binary files a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/table.cpython-310.pyc and b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/table.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/track_modifications.cpython-310.pyc b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/track_modifications.cpython-310.pyc index 4b7de49..074ec5a 100644 Binary files a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/track_modifications.cpython-310.pyc and b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/track_modifications.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/flask_sqlalchemy/extension.py b/venv/Lib/site-packages/flask_sqlalchemy/extension.py index eb2a80d..43e1b9a 100644 --- a/venv/Lib/site-packages/flask_sqlalchemy/extension.py +++ b/venv/Lib/site-packages/flask_sqlalchemy/extension.py @@ -1,7 +1,9 @@ from __future__ import annotations import os +import types import typing as t +import warnings from weakref import WeakKeyDictionary import sqlalchemy as sa @@ -14,8 +16,11 @@ from flask import Flask from flask import has_app_context from .model import _QueryProperty +from .model import BindMixin from .model import DefaultMeta +from .model import DefaultMetaNoName from .model import Model +from .model import NameMixin from .pagination import Pagination from .pagination import SelectPagination from .query import Query @@ -26,6 +31,33 @@ from .table import _Table _O = t.TypeVar("_O", bound=object) # Based on sqlalchemy.orm._typing.py +# Type accepted for model_class argument +_FSA_MCT = t.TypeVar( + "_FSA_MCT", + bound=t.Union[ + t.Type[Model], + sa_orm.DeclarativeMeta, + t.Type[sa_orm.DeclarativeBase], + t.Type[sa_orm.DeclarativeBaseNoMeta], + ], +) + + +# Type returned by make_declarative_base +class _FSAModel(Model): + metadata: sa.MetaData + + +def _get_2x_declarative_bases( + model_class: _FSA_MCT, +) -> list[t.Type[t.Union[sa_orm.DeclarativeBase, sa_orm.DeclarativeBaseNoMeta]]]: + return [ + b + for b in model_class.__bases__ + if issubclass(b, (sa_orm.DeclarativeBase, sa_orm.DeclarativeBaseNoMeta)) + ] + + class SQLAlchemy: """Integrates SQLAlchemy with Flask. This handles setting up one or more engines, associating tables and models with specific engines, and cleaning up connections and @@ -66,6 +98,18 @@ class SQLAlchemy: :param add_models_to_shell: Add the ``db`` instance and all model classes to ``flask shell``. + .. versionchanged:: 3.1.0 + The ``metadata`` parameter can still be used with SQLAlchemy 1.x classes, + but is ignored when using SQLAlchemy 2.x style of declarative classes. + Instead, specify metadata on your Base class. + + .. versionchanged:: 3.1.0 + Added the ``disable_autonaming`` parameter. + + .. versionchanged:: 3.1.0 + Changed ``model_class`` parameter to accepta SQLAlchemy 2.x + declarative base subclass. + .. versionchanged:: 3.0 An active Flask application context is always required to access ``session`` and ``engine``. @@ -100,11 +144,6 @@ class SQLAlchemy: .. versionchanged:: 3.0 Removed the ``use_native_unicode`` parameter and config. - .. versionchanged:: 3.0 - The ``COMMIT_ON_TEARDOWN`` configuration is deprecated and will - be removed in Flask-SQLAlchemy 3.1. Call ``db.session.commit()`` - directly instead. - .. versionchanged:: 2.4 Added the ``engine_options`` parameter. @@ -129,9 +168,10 @@ class SQLAlchemy: metadata: sa.MetaData | None = None, session_options: dict[str, t.Any] | None = None, query_class: type[Query] = Query, - model_class: type[Model] | sa_orm.DeclarativeMeta = Model, + model_class: _FSA_MCT = Model, # type: ignore[assignment] engine_options: dict[str, t.Any] | None = None, add_models_to_shell: bool = True, + disable_autonaming: bool = False, ): if session_options is None: session_options = {} @@ -173,8 +213,17 @@ class SQLAlchemy: """ if metadata is not None: - metadata.info["bind_key"] = None - self.metadatas[None] = metadata + if len(_get_2x_declarative_bases(model_class)) > 0: + warnings.warn( + "When using SQLAlchemy 2.x style of declarative classes," + " the `metadata` should be an attribute of the base class." + "The metadata passed into SQLAlchemy() is ignored.", + DeprecationWarning, + stacklevel=2, + ) + else: + metadata.info["bind_key"] = None + self.metadatas[None] = metadata self.Table = self._make_table_class() """A :class:`sqlalchemy.schema.Table` class that chooses a metadata @@ -192,7 +241,9 @@ class SQLAlchemy: This is a subclass of SQLAlchemy's ``Table`` rather than a function. """ - self.Model = self._make_declarative_base(model_class) + self.Model = self._make_declarative_base( + model_class, disable_autonaming=disable_autonaming + ) """A SQLAlchemy declarative model class. Subclass this to define database models. @@ -204,9 +255,15 @@ class SQLAlchemy: database engine. Otherwise, it will use the default :attr:`metadata` and :attr:`engine`. This is ignored if the model sets ``metadata`` or ``__table__``. - Customize this by subclassing :class:`.Model` and passing the ``model_class`` - parameter to the extension. A fully created declarative model class can be + For code using the SQLAlchemy 1.x API, customize this model by subclassing + :class:`.Model` and passing the ``model_class`` parameter to the extension. + A fully created declarative model class can be passed as well, to use a custom metaclass. + + For code using the SQLAlchemy 2.x API, customize this model by subclassing + :class:`sqlalchemy.orm.DeclarativeBase` or + :class:`sqlalchemy.orm.DeclarativeBaseNoMeta` + and passing the ``model_class`` parameter to the extension. """ if engine_options is None: @@ -258,25 +315,13 @@ class SQLAlchemy: ) app.extensions["sqlalchemy"] = self + app.teardown_appcontext(self._teardown_session) if self._add_models_to_shell: from .cli import add_models_to_shell app.shell_context_processor(add_models_to_shell) - if app.config.get("SQLALCHEMY_COMMIT_ON_TEARDOWN", False): - import warnings - - warnings.warn( - "'SQLALCHEMY_COMMIT_ON_TEARDOWN' is deprecated and will be removed in" - " Flask-SQAlchemy 3.1. Call 'db.session.commit()'` directly instead.", - DeprecationWarning, - stacklevel=2, - ) - app.teardown_appcontext(self._teardown_commit) - else: - app.teardown_appcontext(self._teardown_session) - basic_uri: str | sa.engine.URL | None = app.config.setdefault( "SQLALCHEMY_DATABASE_URI", None ) @@ -393,20 +438,6 @@ class SQLAlchemy: options.setdefault("query_cls", self.Query) return sa_orm.sessionmaker(db=self, **options) - def _teardown_commit(self, exc: BaseException | None) -> None: - """Commit the session at the end of the request if there was not an unhandled - exception during the request. - - :meta private: - - .. deprecated:: 3.0 - Will be removed in 3.1. Use ``db.session.commit()`` directly instead. - """ - if exc is None: - self.session.commit() - - self.session.remove() - def _teardown_session(self, exc: BaseException | None) -> None: """Remove the current session at the end of the request. @@ -464,29 +495,16 @@ class SQLAlchemy: if not args or (len(args) >= 2 and isinstance(args[1], sa.MetaData)): return super().__new__(cls, *args, **kwargs) - if ( - bind_key is None - and "info" in kwargs - and "bind_key" in kwargs["info"] - ): - import warnings - - warnings.warn( - "'table.info['bind_key'] is deprecated and will not be used in" - " Flask-SQLAlchemy 3.1. Pass the 'bind_key' parameter instead.", - DeprecationWarning, - stacklevel=2, - ) - bind_key = kwargs["info"].get("bind_key") - metadata = self._make_metadata(bind_key) return super().__new__(cls, *[args[0], metadata, *args[1:]], **kwargs) return Table def _make_declarative_base( - self, model: type[Model] | sa_orm.DeclarativeMeta - ) -> type[t.Any]: + self, + model_class: _FSA_MCT, + disable_autonaming: bool = False, + ) -> t.Type[_FSAModel]: """Create a SQLAlchemy declarative model class. The result is available as :attr:`Model`. @@ -498,7 +516,14 @@ class SQLAlchemy: :meta private: - :param model: A model base class, or an already created declarative model class. + :param model_class: A model base class, or an already created declarative model + class. + + :param disable_autonaming: Turns off automatic tablename generation in models. + + .. versionchanged:: 3.1.0 + Added support for passing SQLAlchemy 2.x base class as model class. + Added optional ``disable_autonaming`` parameter. .. versionchanged:: 3.0 Renamed with a leading underscore, this method is internal. @@ -506,22 +531,45 @@ class SQLAlchemy: .. versionchanged:: 2.3 ``model`` can be an already created declarative model class. """ - if not isinstance(model, sa_orm.DeclarativeMeta): - metadata = self._make_metadata(None) - model = sa_orm.declarative_base( - metadata=metadata, cls=model, name="Model", metaclass=DefaultMeta + model: t.Type[_FSAModel] + declarative_bases = _get_2x_declarative_bases(model_class) + if len(declarative_bases) > 1: + # raise error if more than one declarative base is found + raise ValueError( + "Only one declarative base can be passed to SQLAlchemy." + " Got: {}".format(model_class.__bases__) ) + elif len(declarative_bases) == 1: + body = dict(model_class.__dict__) + body["__fsa__"] = self + mixin_classes = [BindMixin, NameMixin, Model] + if disable_autonaming: + mixin_classes.remove(NameMixin) + model = types.new_class( + "FlaskSQLAlchemyBase", + (*mixin_classes, *model_class.__bases__), + {"metaclass": type(declarative_bases[0])}, + lambda ns: ns.update(body), + ) + elif not isinstance(model_class, sa_orm.DeclarativeMeta): + metadata = self._make_metadata(None) + metaclass = DefaultMetaNoName if disable_autonaming else DefaultMeta + model = sa_orm.declarative_base( + metadata=metadata, cls=model_class, name="Model", metaclass=metaclass + ) + else: + model = model_class # type: ignore[assignment] if None not in self.metadatas: # Use the model's metadata as the default metadata. - model.metadata.info["bind_key"] = None # type: ignore[union-attr] - self.metadatas[None] = model.metadata # type: ignore[union-attr] + model.metadata.info["bind_key"] = None + self.metadatas[None] = model.metadata else: # Use the passed in default metadata as the model's metadata. - model.metadata = self.metadatas[None] # type: ignore[union-attr] + model.metadata = self.metadatas[None] model.query_class = self.Query - model.query = _QueryProperty() + model.query = _QueryProperty() # type: ignore[assignment] model.__fsa__ = self return model @@ -660,80 +708,41 @@ class SQLAlchemy: """ return self.engines[None] - def get_engine(self, bind_key: str | None = None) -> sa.engine.Engine: + def get_engine( + self, bind_key: str | None = None, **kwargs: t.Any + ) -> sa.engine.Engine: """Get the engine for the given bind key for the current application. - This requires that a Flask application context is active. :param bind_key: The name of the engine. .. deprecated:: 3.0 - Will be removed in Flask-SQLAlchemy 3.1. Use ``engines[key]`` instead. + Will be removed in Flask-SQLAlchemy 3.2. Use ``engines[key]`` instead. .. versionchanged:: 3.0 Renamed the ``bind`` parameter to ``bind_key``. Removed the ``app`` parameter. """ - import warnings - warnings.warn( - "'get_engine' is deprecated and will be removed in Flask-SQLAlchemy 3.1." - " Use 'engine' or 'engines[key]' instead.", + "'get_engine' is deprecated and will be removed in Flask-SQLAlchemy" + " 3.2. Use 'engine' or 'engines[key]' instead. If you're using" + " Flask-Migrate or Alembic, you'll need to update your 'env.py' file.", DeprecationWarning, stacklevel=2, ) + + if "bind" in kwargs: + bind_key = kwargs.pop("bind") + return self.engines[bind_key] - def get_tables_for_bind(self, bind_key: str | None = None) -> list[sa.Table]: - """Get all tables in the metadata for the given bind key. - - :param bind_key: The bind key to get. - - .. deprecated:: 3.0 - Will be removed in Flask-SQLAlchemy 3.1. Use ``metadata.tables`` instead. - - .. versionchanged:: 3.0 - Renamed the ``bind`` parameter to ``bind_key``. - """ - import warnings - - warnings.warn( - "'get_tables_for_bind' is deprecated and will be removed in" - " Flask-SQLAlchemy 3.1. Use 'metadata.tables' instead.", - DeprecationWarning, - stacklevel=2, - ) - return list(self.metadatas[bind_key].tables.values()) - - def get_binds(self) -> dict[sa.Table, sa.engine.Engine]: - """Map all tables to their engine based on their bind key, which can be used to - create a session with ``Session(binds=db.get_binds(app))``. - - This requires that a Flask application context is active. - - .. deprecated:: 3.0 - Will be removed in Flask-SQLAlchemy 3.1. ``db.session`` supports multiple - binds directly. - - .. versionchanged:: 3.0 - Removed the ``app`` parameter. - """ - import warnings - - warnings.warn( - "'get_binds' is deprecated and will be removed in Flask-SQLAlchemy 3.1." - " 'db.session' supports multiple binds directly.", - DeprecationWarning, - stacklevel=2, - ) - return { - table: engine - for bind_key, engine in self.engines.items() - for table in self.metadatas[bind_key].tables.values() - } - def get_or_404( - self, entity: type[_O], ident: t.Any, *, description: str | None = None + self, + entity: type[_O], + ident: t.Any, + *, + description: str | None = None, + **kwargs: t.Any, ) -> _O: """Like :meth:`session.get() ` but aborts with a ``404 Not Found`` error instead of returning ``None``. @@ -741,10 +750,14 @@ class SQLAlchemy: :param entity: The model class to query. :param ident: The primary key to query. :param description: A custom message to show on the error page. + :param kwargs: Extra arguments passed to ``session.get()``. + + .. versionchanged:: 3.1 + Pass extra keyword arguments to ``session.get()``. .. versionadded:: 3.0 """ - value = self.session.get(entity, ident) + value = self.session.get(entity, ident, **kwargs) if value is None: abort(404, description=description) @@ -974,24 +987,11 @@ class SQLAlchemy: .. versionchanged:: 3.0 The :attr:`Query` class is set on ``backref``. """ - # Deprecated, removed in SQLAlchemy 2.0. Accessed through ``__getattr__``. self._set_rel_query(kwargs) f = sa_orm.relationship return f(*args, **kwargs) def __getattr__(self, name: str) -> t.Any: - if name == "db": - import warnings - - warnings.warn( - "The 'db' attribute is deprecated and will be removed in" - " Flask-SQLAlchemy 3.1. The extension is registered directly as" - " 'app.extensions[\"sqlalchemy\"]'.", - DeprecationWarning, - stacklevel=2, - ) - return self - if name == "relation": return self._relation diff --git a/venv/Lib/site-packages/flask_sqlalchemy/model.py b/venv/Lib/site-packages/flask_sqlalchemy/model.py index 4b202a5..c6f9e5a 100644 --- a/venv/Lib/site-packages/flask_sqlalchemy/model.py +++ b/venv/Lib/site-packages/flask_sqlalchemy/model.py @@ -18,14 +18,6 @@ class _QueryProperty: :meta private: """ - @t.overload - def __get__(self, obj: None, cls: type[Model]) -> Query: - ... - - @t.overload - def __get__(self, obj: Model, cls: type[Model]) -> Query: - ... - def __get__(self, obj: Model | None, cls: type[Model]) -> Query: return cls.query_class( cls, session=cls.__fsa__.session() # type: ignore[arg-type] @@ -100,6 +92,38 @@ class BindMetaMixin(type): super().__init__(name, bases, d, **kwargs) +class BindMixin: + """DeclarativeBase mixin to set a model's ``metadata`` based on ``__bind_key__``. + + If no ``__bind_key__`` is specified, the model will use the default metadata + provided by ``DeclarativeBase`` or ``DeclarativeBaseNoMeta``. + If the model doesn't set ``metadata`` or ``__table__`` directly + and does set ``__bind_key__``, the model will use the metadata + for the specified bind key. + If the ``metadata`` is the same as the parent model, it will not be set + directly on the child model. + + .. versionchanged:: 3.1.0 + """ + + __fsa__: SQLAlchemy + metadata: sa.MetaData + + @classmethod + def __init_subclass__(cls: t.Type[BindMixin], **kwargs: t.Dict[str, t.Any]) -> None: + if not ("metadata" in cls.__dict__ or "__table__" in cls.__dict__) and hasattr( + cls, "__bind_key__" + ): + bind_key = getattr(cls, "__bind_key__", None) + parent_metadata = getattr(cls, "metadata", None) + metadata = cls.__fsa__._make_metadata(bind_key) + + if metadata is not parent_metadata: + cls.metadata = metadata + + super().__init_subclass__(**kwargs) + + class NameMetaMixin(type): """Metaclass mixin that sets a model's ``__tablename__`` by converting the ``CamelCase`` class name to ``snake_case``. A name is set for non-abstract models @@ -169,6 +193,77 @@ class NameMetaMixin(type): return None +class NameMixin: + """DeclarativeBase mixin that sets a model's ``__tablename__`` by converting the + ``CamelCase`` class name to ``snake_case``. A name is set for non-abstract models + that do not otherwise define ``__tablename__``. If a model does not define a primary + key, it will not generate a name or ``__table__``, for single-table inheritance. + + .. versionchanged:: 3.1.0 + """ + + metadata: sa.MetaData + __tablename__: str + __table__: sa.Table + + @classmethod + def __init_subclass__(cls: t.Type[NameMixin], **kwargs: t.Dict[str, t.Any]) -> None: + if should_set_tablename(cls): + cls.__tablename__ = camel_to_snake_case(cls.__name__) + + super().__init_subclass__(**kwargs) + + # __table_cls__ has run. If no table was created, use the parent table. + if ( + "__tablename__" not in cls.__dict__ + and "__table__" in cls.__dict__ + and cls.__dict__["__table__"] is None + ): + del cls.__table__ + + @classmethod + def __table_cls__(cls, *args: t.Any, **kwargs: t.Any) -> sa.Table | None: + """This is called by SQLAlchemy during mapper setup. It determines the final + table object that the model will use. + + If no primary key is found, that indicates single-table inheritance, so no table + will be created and ``__tablename__`` will be unset. + """ + schema = kwargs.get("schema") + + if schema is None: + key = args[0] + else: + key = f"{schema}.{args[0]}" + + # Check if a table with this name already exists. Allows reflected tables to be + # applied to models by name. + if key in cls.metadata.tables: + return sa.Table(*args, **kwargs) + + # If a primary key is found, create a table for joined-table inheritance. + for arg in args: + if (isinstance(arg, sa.Column) and arg.primary_key) or isinstance( + arg, sa.PrimaryKeyConstraint + ): + return sa.Table(*args, **kwargs) + + # If no base classes define a table, return one that's missing a primary key + # so SQLAlchemy shows the correct error. + for base in cls.__mro__[1:-1]: + if "__table__" in base.__dict__: + break + else: + return sa.Table(*args, **kwargs) + + # Single-table inheritance, use the parent table name. __init__ will unset + # __table__ based on this. + if "__tablename__" in cls.__dict__: + del cls.__tablename__ + + return None + + def should_set_tablename(cls: type) -> bool: """Determine whether ``__tablename__`` should be generated for a model. @@ -181,8 +276,16 @@ def should_set_tablename(cls: type) -> bool: Later, ``__table_cls__`` will determine if the model looks like single or joined-table inheritance. If no primary key is found, the name will be unset. """ - if cls.__dict__.get("__abstract__", False) or not any( - isinstance(b, sa_orm.DeclarativeMeta) for b in cls.__mro__[1:] + if ( + cls.__dict__.get("__abstract__", False) + or ( + not issubclass(cls, (sa_orm.DeclarativeBase, sa_orm.DeclarativeBaseNoMeta)) + and not any(isinstance(b, sa_orm.DeclarativeMeta) for b in cls.__mro__[1:]) + ) + or any( + (b is sa_orm.DeclarativeBase or b is sa_orm.DeclarativeBaseNoMeta) + for b in cls.__bases__ + ) ): return False @@ -196,7 +299,14 @@ def should_set_tablename(cls: type) -> bool: return not ( base is cls or base.__dict__.get("__abstract__", False) - or not isinstance(base, sa_orm.DeclarativeMeta) + or not ( + # SQLAlchemy 1.x + isinstance(base, sa_orm.DeclarativeMeta) + # 2.x: DeclarativeBas uses this as metaclass + or isinstance(base, sa_orm.decl_api.DeclarativeAttributeIntercept) + # 2.x: DeclarativeBaseNoMeta doesn't use a metaclass + or issubclass(base, sa_orm.DeclarativeBaseNoMeta) + ) ) return True @@ -212,3 +322,9 @@ class DefaultMeta(BindMetaMixin, NameMetaMixin, sa_orm.DeclarativeMeta): """SQLAlchemy declarative metaclass that provides ``__bind_key__`` and ``__tablename__`` support. """ + + +class DefaultMetaNoName(BindMetaMixin, sa_orm.DeclarativeMeta): + """SQLAlchemy declarative metaclass that provides ``__bind_key__`` and + ``__tablename__`` support. + """ diff --git a/venv/Lib/site-packages/flask_sqlalchemy/record_queries.py b/venv/Lib/site-packages/flask_sqlalchemy/record_queries.py index 42278ba..e8273be 100644 --- a/venv/Lib/site-packages/flask_sqlalchemy/record_queries.py +++ b/venv/Lib/site-packages/flask_sqlalchemy/record_queries.py @@ -70,30 +70,6 @@ class _QueryInfo: def duration(self) -> float: return self.end_time - self.start_time - @property - def context(self) -> str: - import warnings - - warnings.warn( - "'context' is renamed to 'location'. The old name is deprecated and will be" - " removed in Flask-SQLAlchemy 3.1.", - DeprecationWarning, - stacklevel=2, - ) - return self.location - - def __getitem__(self, key: int) -> object: - import warnings - - name = ("statement", "parameters", "start_time", "end_time", "location")[key] - warnings.warn( - "Query info is a dataclass, not a tuple. Lookup by index is deprecated and" - f" will be removed in Flask-SQLAlchemy 3.1. Use 'info.{name}' instead.", - DeprecationWarning, - stacklevel=2, - ) - return getattr(self, name) - def _listen(engine: sa.engine.Engine) -> None: sa_event.listen(engine, "before_cursor_execute", _record_start, named=True) diff --git a/venv/Lib/site-packages/flask_sqlalchemy/session.py b/venv/Lib/site-packages/flask_sqlalchemy/session.py index b0ae871..631fffa 100644 --- a/venv/Lib/site-packages/flask_sqlalchemy/session.py +++ b/venv/Lib/site-packages/flask_sqlalchemy/session.py @@ -79,13 +79,22 @@ class Session(sa_orm.Session): def _clause_to_engine( - clause: t.Any | None, engines: t.Mapping[str | None, sa.engine.Engine] + clause: sa.ClauseElement | None, + engines: t.Mapping[str | None, sa.engine.Engine], ) -> sa.engine.Engine | None: """If the clause is a table, return the engine associated with the table's metadata's bind key. """ - if isinstance(clause, sa.Table) and "bind_key" in clause.metadata.info: - key = clause.metadata.info["bind_key"] + table = None + + if clause is not None: + if isinstance(clause, sa.Table): + table = clause + elif isinstance(clause, sa.UpdateBase) and isinstance(clause.table, sa.Table): + table = clause.table + + if table is not None and "bind_key" in table.metadata.info: + key = table.metadata.info["bind_key"] if key not in engines: raise sa_exc.UnboundExecutionError( diff --git a/venv/Lib/site-packages/flask_wtf/__init__.py b/venv/Lib/site-packages/flask_wtf/__init__.py index 59bc895..be2649e 100644 --- a/venv/Lib/site-packages/flask_wtf/__init__.py +++ b/venv/Lib/site-packages/flask_wtf/__init__.py @@ -5,4 +5,4 @@ from .recaptcha import Recaptcha from .recaptcha import RecaptchaField from .recaptcha import RecaptchaWidget -__version__ = "1.1.1" +__version__ = "1.2.1" diff --git a/venv/Lib/site-packages/flask_wtf/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/flask_wtf/__pycache__/__init__.cpython-310.pyc index ba58382..f164b1a 100644 Binary files a/venv/Lib/site-packages/flask_wtf/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/flask_wtf/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/flask_wtf/__pycache__/_compat.cpython-310.pyc b/venv/Lib/site-packages/flask_wtf/__pycache__/_compat.cpython-310.pyc index 935eccd..a157582 100644 Binary files a/venv/Lib/site-packages/flask_wtf/__pycache__/_compat.cpython-310.pyc and b/venv/Lib/site-packages/flask_wtf/__pycache__/_compat.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/flask_wtf/__pycache__/csrf.cpython-310.pyc b/venv/Lib/site-packages/flask_wtf/__pycache__/csrf.cpython-310.pyc index 816524f..b4f4e4f 100644 Binary files a/venv/Lib/site-packages/flask_wtf/__pycache__/csrf.cpython-310.pyc and b/venv/Lib/site-packages/flask_wtf/__pycache__/csrf.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/flask_wtf/__pycache__/file.cpython-310.pyc b/venv/Lib/site-packages/flask_wtf/__pycache__/file.cpython-310.pyc index 684dc3e..49722e0 100644 Binary files a/venv/Lib/site-packages/flask_wtf/__pycache__/file.cpython-310.pyc and b/venv/Lib/site-packages/flask_wtf/__pycache__/file.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/flask_wtf/__pycache__/form.cpython-310.pyc b/venv/Lib/site-packages/flask_wtf/__pycache__/form.cpython-310.pyc index 2044a29..17d41bc 100644 Binary files a/venv/Lib/site-packages/flask_wtf/__pycache__/form.cpython-310.pyc and b/venv/Lib/site-packages/flask_wtf/__pycache__/form.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/flask_wtf/__pycache__/i18n.cpython-310.pyc b/venv/Lib/site-packages/flask_wtf/__pycache__/i18n.cpython-310.pyc index 024c610..05a71f0 100644 Binary files a/venv/Lib/site-packages/flask_wtf/__pycache__/i18n.cpython-310.pyc and b/venv/Lib/site-packages/flask_wtf/__pycache__/i18n.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/flask_wtf/csrf.py b/venv/Lib/site-packages/flask_wtf/csrf.py index 18e7597..06afa0c 100644 --- a/venv/Lib/site-packages/flask_wtf/csrf.py +++ b/venv/Lib/site-packages/flask_wtf/csrf.py @@ -217,7 +217,7 @@ class CSRFProtect: if not request.endpoint: return - if request.blueprint in self._exempt_blueprints: + if app.blueprints.get(request.blueprint) in self._exempt_blueprints: return view = app.view_functions.get(request.endpoint) @@ -292,7 +292,7 @@ class CSRFProtect: """ if isinstance(view, Blueprint): - self._exempt_blueprints.add(view.name) + self._exempt_blueprints.add(view) return view if isinstance(view, str): diff --git a/venv/Lib/site-packages/flask_wtf/file.py b/venv/Lib/site-packages/flask_wtf/file.py index b216696..a720dff 100644 --- a/venv/Lib/site-packages/flask_wtf/file.py +++ b/venv/Lib/site-packages/flask_wtf/file.py @@ -2,6 +2,7 @@ from collections import abc from werkzeug.datastructures import FileStorage from wtforms import FileField as _FileField +from wtforms import MultipleFileField as _MultipleFileField from wtforms.validators import DataRequired from wtforms.validators import StopValidation from wtforms.validators import ValidationError @@ -20,8 +21,24 @@ class FileField(_FileField): self.raw_data = () +class MultipleFileField(_MultipleFileField): + """Werkzeug-aware subclass of :class:`wtforms.fields.MultipleFileField`. + + .. versionadded:: 1.2.0 + """ + + def process_formdata(self, valuelist): + valuelist = (x for x in valuelist if isinstance(x, FileStorage) and x) + data = list(valuelist) or None + + if data is not None: + self.data = data + else: + self.raw_data = () + + class FileRequired(DataRequired): - """Validates that the data is a Werkzeug + """Validates that the uploaded files(s) is a Werkzeug :class:`~werkzeug.datastructures.FileStorage` object. :param message: error message @@ -30,7 +47,10 @@ class FileRequired(DataRequired): """ def __call__(self, form, field): - if not (isinstance(field.data, FileStorage) and field.data): + field_data = [field.data] if not isinstance(field.data, list) else field.data + if not ( + all(isinstance(x, FileStorage) and x for x in field_data) and field_data + ): raise StopValidation( self.message or field.gettext("This field is required.") ) @@ -40,7 +60,7 @@ file_required = FileRequired class FileAllowed: - """Validates that the uploaded file is allowed by a given list of + """Validates that the uploaded file(s) is allowed by a given list of extensions or a Flask-Uploads :class:`~flaskext.uploads.UploadSet`. :param upload_set: A list of extensions or an @@ -55,34 +75,38 @@ class FileAllowed: self.message = message def __call__(self, form, field): - if not (isinstance(field.data, FileStorage) and field.data): + field_data = [field.data] if not isinstance(field.data, list) else field.data + if not ( + all(isinstance(x, FileStorage) and x for x in field_data) and field_data + ): return - filename = field.data.filename.lower() + filenames = [f.filename.lower() for f in field_data] - if isinstance(self.upload_set, abc.Iterable): - if any(filename.endswith("." + x) for x in self.upload_set): - return + for filename in filenames: + if isinstance(self.upload_set, abc.Iterable): + if any(filename.endswith("." + x) for x in self.upload_set): + continue - raise StopValidation( - self.message - or field.gettext( - "File does not have an approved extension: {extensions}" - ).format(extensions=", ".join(self.upload_set)) - ) + raise StopValidation( + self.message + or field.gettext( + "File does not have an approved extension: {extensions}" + ).format(extensions=", ".join(self.upload_set)) + ) - if not self.upload_set.file_allowed(field.data, filename): - raise StopValidation( - self.message - or field.gettext("File does not have an approved extension.") - ) + if not self.upload_set.file_allowed(field_data, filename): + raise StopValidation( + self.message + or field.gettext("File does not have an approved extension.") + ) file_allowed = FileAllowed class FileSize: - """Validates that the uploaded file is within a minimum and maximum + """Validates that the uploaded file(s) is within a minimum and maximum file size (set in bytes). :param min_size: minimum allowed file size (in bytes). Defaults to 0 bytes. @@ -98,22 +122,26 @@ class FileSize: self.message = message def __call__(self, form, field): - if not (isinstance(field.data, FileStorage) and field.data): + field_data = [field.data] if not isinstance(field.data, list) else field.data + if not ( + all(isinstance(x, FileStorage) and x for x in field_data) and field_data + ): return - file_size = len(field.data.read()) - field.data.seek(0) # reset cursor position to beginning of file + for f in field_data: + file_size = len(f.read()) + f.seek(0) # reset cursor position to beginning of file - if (file_size < self.min_size) or (file_size > self.max_size): - # the file is too small or too big => validation failure - raise ValidationError( - self.message - or field.gettext( - "File must be between {min_size} and {max_size} bytes.".format( - min_size=self.min_size, max_size=self.max_size + if (file_size < self.min_size) or (file_size > self.max_size): + # the file is too small or too big => validation failure + raise ValidationError( + self.message + or field.gettext( + "File must be between {min_size} and {max_size} bytes.".format( + min_size=self.min_size, max_size=self.max_size + ) ) ) - ) file_size = FileSize diff --git a/venv/Lib/site-packages/flask_wtf/recaptcha/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/flask_wtf/recaptcha/__pycache__/__init__.cpython-310.pyc index 55aa85d..ad6c925 100644 Binary files a/venv/Lib/site-packages/flask_wtf/recaptcha/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/flask_wtf/recaptcha/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/flask_wtf/recaptcha/__pycache__/fields.cpython-310.pyc b/venv/Lib/site-packages/flask_wtf/recaptcha/__pycache__/fields.cpython-310.pyc index 17c13e0..d65b318 100644 Binary files a/venv/Lib/site-packages/flask_wtf/recaptcha/__pycache__/fields.cpython-310.pyc and b/venv/Lib/site-packages/flask_wtf/recaptcha/__pycache__/fields.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/flask_wtf/recaptcha/__pycache__/validators.cpython-310.pyc b/venv/Lib/site-packages/flask_wtf/recaptcha/__pycache__/validators.cpython-310.pyc index 176e783..a3ba187 100644 Binary files a/venv/Lib/site-packages/flask_wtf/recaptcha/__pycache__/validators.cpython-310.pyc and b/venv/Lib/site-packages/flask_wtf/recaptcha/__pycache__/validators.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/flask_wtf/recaptcha/__pycache__/widgets.cpython-310.pyc b/venv/Lib/site-packages/flask_wtf/recaptcha/__pycache__/widgets.cpython-310.pyc index c3330e3..6ac4038 100644 Binary files a/venv/Lib/site-packages/flask_wtf/recaptcha/__pycache__/widgets.cpython-310.pyc and b/venv/Lib/site-packages/flask_wtf/recaptcha/__pycache__/widgets.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/flask_wtf/recaptcha/validators.py b/venv/Lib/site-packages/flask_wtf/recaptcha/validators.py index 822e03a..c5cafb3 100644 --- a/venv/Lib/site-packages/flask_wtf/recaptcha/validators.py +++ b/venv/Lib/site-packages/flask_wtf/recaptcha/validators.py @@ -1,9 +1,9 @@ import json from urllib import request as http +from urllib.parse import urlencode from flask import current_app from flask import request -from werkzeug.urls import url_encode from wtforms import ValidationError RECAPTCHA_VERIFY_SERVER_DEFAULT = "https://www.google.com/recaptcha/api/siteverify" @@ -54,7 +54,7 @@ class Recaptcha: if not verify_server: verify_server = RECAPTCHA_VERIFY_SERVER_DEFAULT - data = url_encode( + data = urlencode( {"secret": private_key, "remoteip": remote_addr, "response": response} ) diff --git a/venv/Lib/site-packages/flask_wtf/recaptcha/widgets.py b/venv/Lib/site-packages/flask_wtf/recaptcha/widgets.py index c170929..bfae830 100644 --- a/venv/Lib/site-packages/flask_wtf/recaptcha/widgets.py +++ b/venv/Lib/site-packages/flask_wtf/recaptcha/widgets.py @@ -1,6 +1,7 @@ +from urllib.parse import urlencode + from flask import current_app -from flask import Markup -from werkzeug.urls import url_encode +from markupsafe import Markup RECAPTCHA_SCRIPT_DEFAULT = "https://www.google.com/recaptcha/api.js" RECAPTCHA_DIV_CLASS_DEFAULT = "g-recaptcha" @@ -22,10 +23,10 @@ class RecaptchaWidget: if not script: script = RECAPTCHA_SCRIPT_DEFAULT if params: - script += "?" + url_encode(params) + script += "?" + urlencode(params) attrs = current_app.config.get("RECAPTCHA_DATA_ATTRS", {}) attrs["sitekey"] = public_key - snippet = " ".join(f'data-{k}="{attrs[k]}"' for k in attrs) # noqa: B028 + snippet = " ".join(f'data-{k}="{attrs[k]}"' for k in attrs) # noqa: B028, B907 div_class = current_app.config.get("RECAPTCHA_DIV_CLASS") if not div_class: div_class = RECAPTCHA_DIV_CLASS_DEFAULT diff --git a/venv/Lib/site-packages/sqlalchemy/__init__.py b/venv/Lib/site-packages/sqlalchemy/__init__.py index 37886f7..fbb8d66 100644 --- a/venv/Lib/site-packages/sqlalchemy/__init__.py +++ b/venv/Lib/site-packages/sqlalchemy/__init__.py @@ -269,7 +269,7 @@ from .types import Uuid as Uuid from .types import VARBINARY as VARBINARY from .types import VARCHAR as VARCHAR -__version__ = "2.0.20" +__version__ = "2.0.23" def __go(lcls: Any) -> None: diff --git a/venv/Lib/site-packages/sqlalchemy/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/__pycache__/__init__.cpython-310.pyc index 7abd6a2..0c61a0b 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/__pycache__/events.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/__pycache__/events.cpython-310.pyc index 94c0c9c..53dd1b7 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/__pycache__/events.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/__pycache__/events.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/__pycache__/exc.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/__pycache__/exc.cpython-310.pyc index 23d0534..6fdfe71 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/__pycache__/exc.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/__pycache__/exc.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/__pycache__/inspection.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/__pycache__/inspection.cpython-310.pyc index a87efff..8728d77 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/__pycache__/inspection.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/__pycache__/inspection.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/__pycache__/log.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/__pycache__/log.cpython-310.pyc index 0f3d3fa..dfed636 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/__pycache__/log.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/__pycache__/log.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/__pycache__/schema.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/__pycache__/schema.cpython-310.pyc index b659238..9c33425 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/__pycache__/schema.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/__pycache__/schema.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/__pycache__/types.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/__pycache__/types.cpython-310.pyc index ccebcb9..6c92684 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/__pycache__/types.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/__pycache__/types.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/__init__.cpython-310.pyc index 46d3df8..227d19d 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/pyodbc.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/pyodbc.cpython-310.pyc index ded9ca8..9653688 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/pyodbc.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/pyodbc.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/connectors/pyodbc.py b/venv/Lib/site-packages/sqlalchemy/connectors/pyodbc.py index 669a839..49712a5 100644 --- a/venv/Lib/site-packages/sqlalchemy/connectors/pyodbc.py +++ b/venv/Lib/site-packages/sqlalchemy/connectors/pyodbc.py @@ -227,7 +227,7 @@ class PyODBCConnector(Connector): def get_isolation_level_values( self, dbapi_connection: interfaces.DBAPIConnection ) -> List[IsolationLevel]: - return super().get_isolation_level_values(dbapi_connection) + [ # type: ignore # noqa: E501 + return super().get_isolation_level_values(dbapi_connection) + [ "AUTOCOMMIT" ] diff --git a/venv/Lib/site-packages/sqlalchemy/cyextension/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/cyextension/__pycache__/__init__.cpython-310.pyc index 855d78e..3c284c2 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/cyextension/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/cyextension/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/cyextension/collections.cp310-win_amd64.pyd b/venv/Lib/site-packages/sqlalchemy/cyextension/collections.cp310-win_amd64.pyd index 3bc7cb2..ad60322 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/cyextension/collections.cp310-win_amd64.pyd and b/venv/Lib/site-packages/sqlalchemy/cyextension/collections.cp310-win_amd64.pyd differ diff --git a/venv/Lib/site-packages/sqlalchemy/cyextension/immutabledict.cp310-win_amd64.pyd b/venv/Lib/site-packages/sqlalchemy/cyextension/immutabledict.cp310-win_amd64.pyd index 9d96029..edba81b 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/cyextension/immutabledict.cp310-win_amd64.pyd and b/venv/Lib/site-packages/sqlalchemy/cyextension/immutabledict.cp310-win_amd64.pyd differ diff --git a/venv/Lib/site-packages/sqlalchemy/cyextension/processors.cp310-win_amd64.pyd b/venv/Lib/site-packages/sqlalchemy/cyextension/processors.cp310-win_amd64.pyd index 7bf6716..e85606b 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/cyextension/processors.cp310-win_amd64.pyd and b/venv/Lib/site-packages/sqlalchemy/cyextension/processors.cp310-win_amd64.pyd differ diff --git a/venv/Lib/site-packages/sqlalchemy/cyextension/resultproxy.cp310-win_amd64.pyd b/venv/Lib/site-packages/sqlalchemy/cyextension/resultproxy.cp310-win_amd64.pyd index 27dcb81..67a81bf 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/cyextension/resultproxy.cp310-win_amd64.pyd and b/venv/Lib/site-packages/sqlalchemy/cyextension/resultproxy.cp310-win_amd64.pyd differ diff --git a/venv/Lib/site-packages/sqlalchemy/cyextension/util.cp310-win_amd64.pyd b/venv/Lib/site-packages/sqlalchemy/cyextension/util.cp310-win_amd64.pyd index 0bb4ba7..e33f390 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/cyextension/util.cp310-win_amd64.pyd and b/venv/Lib/site-packages/sqlalchemy/cyextension/util.cp310-win_amd64.pyd differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/__init__.py b/venv/Lib/site-packages/sqlalchemy/dialects/__init__.py index 76b2263..055d087 100644 --- a/venv/Lib/site-packages/sqlalchemy/dialects/__init__.py +++ b/venv/Lib/site-packages/sqlalchemy/dialects/__init__.py @@ -51,7 +51,7 @@ def _auto_fn(name: str) -> Optional[Callable[[], Type[Dialect]]]: if hasattr(module, driver): module = getattr(module, driver) - return lambda: module.dialect # type: ignore + return lambda: module.dialect else: return None diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/__pycache__/__init__.cpython-310.pyc index b5a5178..40d85a8 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/__pycache__/_typing.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/__pycache__/_typing.cpython-310.pyc index cfdaca0..25dec1d 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/__pycache__/_typing.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/__pycache__/_typing.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__init__.py b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__init__.py index 3f70847..6bbb934 100644 --- a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__init__.py +++ b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__init__.py @@ -6,6 +6,7 @@ # the MIT License: https://www.opensource.org/licenses/mit-license.php # mypy: ignore-errors +from . import aioodbc # noqa from . import base # noqa from . import pymssql # noqa from . import pyodbc # noqa diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/__init__.cpython-310.pyc index afbe60f..ff1c2e5 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/base.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/base.cpython-310.pyc index 7787a21..07701b3 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/base.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/base.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/information_schema.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/information_schema.cpython-310.pyc index 6e6135b..efc4992 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/information_schema.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/information_schema.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/json.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/json.cpython-310.pyc index a768849..47fc0e3 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/json.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/json.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/provision.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/provision.cpython-310.pyc index 94147c7..7130233 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/provision.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/provision.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/pymssql.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/pymssql.cpython-310.pyc index 5f5df36..9e3acfd 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/pymssql.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/pymssql.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/pyodbc.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/pyodbc.cpython-310.pyc index 2121b80..2cb3043 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/pyodbc.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/pyodbc.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/base.py b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/base.py index 1f80aae..687de04 100644 --- a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/base.py +++ b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/base.py @@ -1537,28 +1537,22 @@ class MSUUid(sqltypes.Uuid): if self.native_uuid: def process(value): - if value is not None: - value = f"""'{str(value).replace("''", "'")}'""" - return value + return f"""'{str(value).replace("''", "'")}'""" return process else: if self.as_uuid: def process(value): - if value is not None: - value = f"""'{value.hex}'""" - return value + return f"""'{value.hex}'""" return process else: def process(value): - if value is not None: - value = f"""'{ + return f"""'{ value.replace("-", "").replace("'", "''") }'""" - return value return process @@ -1942,6 +1936,7 @@ class MSExecutionContext(default.DefaultExecutionContext): row = self.cursor.fetchall()[0] self._lastrowid = int(row[0]) + self.cursor_fetch_strategy = _cursor._NO_CURSOR_DML elif ( self.compiled is not None and is_sql_compiler(self.compiled) @@ -2057,6 +2052,12 @@ class MSSQLCompiler(compiler.SQLCompiler): def visit_char_length_func(self, fn, **kw): return "LEN%s" % self.function_argspec(fn, **kw) + def visit_aggregate_strings_func(self, fn, **kw): + expr = fn.clauses.clauses[0]._compiler_dispatch(self, **kw) + kw["literal_execute"] = True + delimeter = fn.clauses.clauses[1]._compiler_dispatch(self, **kw) + return f"string_agg({expr}, {delimeter})" + def visit_concat_op_expression_clauselist( self, clauselist, operator, **kw ): @@ -2119,6 +2120,7 @@ class MSSQLCompiler(compiler.SQLCompiler): or ( # limit can use TOP with is by itself. fetch only uses TOP # when it needs to because of PERCENT and/or WITH TIES + # TODO: Why? shouldn't we use TOP always ? select._simple_int_clause(select._fetch_clause) and ( select._fetch_clause_options["percent"] @@ -2379,10 +2381,13 @@ class MSSQLCompiler(compiler.SQLCompiler): return "" def order_by_clause(self, select, **kw): - # MSSQL only allows ORDER BY in subqueries if there is a LIMIT + # MSSQL only allows ORDER BY in subqueries if there is a LIMIT: + # "The ORDER BY clause is invalid in views, inline functions, + # derived tables, subqueries, and common table expressions, + # unless TOP, OFFSET or FOR XML is also specified." if ( self.is_subquery() - and not select._limit + and not self._use_top(select) and ( select._offset is None or not self.dialect._supports_offset_fetch diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/information_schema.py b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/information_schema.py index 5bf81e8..e770313 100644 --- a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/information_schema.py +++ b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/information_schema.py @@ -211,7 +211,7 @@ class NumericSqlVariant(TypeDecorator): cache_ok = True def column_expression(self, colexpr): - return cast(colexpr, Numeric) + return cast(colexpr, Numeric(38, 0)) identity_columns = Table( diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/provision.py b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/provision.py index d01ed07..096ae03 100644 --- a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/provision.py +++ b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/provision.py @@ -26,7 +26,7 @@ def generate_driver_url(url, driver, query_str): new_url = url.set(drivername="%s+%s" % (backend, driver)) - if driver != "pyodbc": + if driver not in ("pyodbc", "aioodbc"): new_url = new_url.set(query="") if query_str: diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/pyodbc.py b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/pyodbc.py index 49d203e..a8f12fd 100644 --- a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/pyodbc.py +++ b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/pyodbc.py @@ -365,6 +365,7 @@ from ... import exc from ... import types as sqltypes from ... import util from ...connectors.pyodbc import PyODBCConnector +from ...engine import cursor as _cursor class _ms_numeric_pyodbc: @@ -585,14 +586,22 @@ class MSExecutionContext_pyodbc(MSExecutionContext): try: # fetchall() ensures the cursor is consumed # without closing it (FreeTDS particularly) - row = self.cursor.fetchall()[0] - break + rows = self.cursor.fetchall() except self.dialect.dbapi.Error: # no way around this - nextset() consumes the previous set # so we need to just keep flipping self.cursor.nextset() + else: + if not rows: + # async adapter drivers just return None here + self.cursor.nextset() + continue + row = rows[0] + break self._lastrowid = int(row[0]) + + self.cursor_fetch_strategy = _cursor._NO_CURSOR_DML else: super().post_exec() diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/__init__.cpython-310.pyc index 161fc65..07d7fb7 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/aiomysql.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/aiomysql.cpython-310.pyc index 0992da8..13b891f 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/aiomysql.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/aiomysql.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/asyncmy.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/asyncmy.cpython-310.pyc index 2b5d1ef..0bf12a2 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/asyncmy.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/asyncmy.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/base.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/base.cpython-310.pyc index bd7fec2..f410482 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/base.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/base.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/cymysql.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/cymysql.cpython-310.pyc index 6da2386..f1ec27c 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/cymysql.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/cymysql.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/dml.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/dml.cpython-310.pyc index 330f144..62c3d66 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/dml.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/dml.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/enumerated.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/enumerated.cpython-310.pyc index 6a0e8ef..fd83eeb 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/enumerated.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/enumerated.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/expression.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/expression.cpython-310.pyc index 2fcceff..7d120f6 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/expression.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/expression.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/json.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/json.cpython-310.pyc index 6a2017a..9eeb115 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/json.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/json.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mariadb.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mariadb.cpython-310.pyc index b6c478d..9a7186c 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mariadb.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mariadb.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mariadbconnector.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mariadbconnector.cpython-310.pyc index cbd9001..49f0970 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mariadbconnector.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mariadbconnector.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mysqlconnector.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mysqlconnector.cpython-310.pyc index c86be1e..f30a7f2 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mysqlconnector.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mysqlconnector.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mysqldb.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mysqldb.cpython-310.pyc index 05f60f8..a2da3b8 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mysqldb.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mysqldb.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/provision.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/provision.cpython-310.pyc index 3140495..6aa0346 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/provision.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/provision.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/pymysql.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/pymysql.cpython-310.pyc index 4889d35..649d667 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/pymysql.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/pymysql.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/pyodbc.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/pyodbc.cpython-310.pyc index 080a61c..ddc0971 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/pyodbc.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/pyodbc.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/reflection.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/reflection.cpython-310.pyc index 5525517..61f6c3a 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/reflection.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/reflection.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/reserved_words.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/reserved_words.cpython-310.pyc index 7873191..aaa1e5d 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/reserved_words.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/reserved_words.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/types.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/types.cpython-310.pyc index a4e5f5f..73bcca9 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/types.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/types.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/aiomysql.py b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/aiomysql.py index 97be625..2a0c6ba 100644 --- a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/aiomysql.py +++ b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/aiomysql.py @@ -37,6 +37,8 @@ from ...util.concurrency import await_only class AsyncAdapt_aiomysql_cursor: + # TODO: base on connectors/asyncio.py + # see #10415 server_side = False __slots__ = ( "_adapt_connection", @@ -139,6 +141,8 @@ class AsyncAdapt_aiomysql_cursor: class AsyncAdapt_aiomysql_ss_cursor(AsyncAdapt_aiomysql_cursor): + # TODO: base on connectors/asyncio.py + # see #10415 __slots__ = () server_side = True @@ -167,6 +171,8 @@ class AsyncAdapt_aiomysql_ss_cursor(AsyncAdapt_aiomysql_cursor): class AsyncAdapt_aiomysql_connection(AdaptedConnection): + # TODO: base on connectors/asyncio.py + # see #10415 await_ = staticmethod(await_only) __slots__ = ("dbapi", "_execute_mutex") @@ -202,6 +208,8 @@ class AsyncAdapt_aiomysql_connection(AdaptedConnection): class AsyncAdaptFallback_aiomysql_connection(AsyncAdapt_aiomysql_connection): + # TODO: base on connectors/asyncio.py + # see #10415 __slots__ = () await_ = staticmethod(await_fallback) diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/asyncmy.py b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/asyncmy.py index 7ef942c..92058d6 100644 --- a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/asyncmy.py +++ b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/asyncmy.py @@ -37,6 +37,8 @@ from ...util.concurrency import await_only class AsyncAdapt_asyncmy_cursor: + # TODO: base on connectors/asyncio.py + # see #10415 server_side = False __slots__ = ( "_adapt_connection", @@ -141,6 +143,8 @@ class AsyncAdapt_asyncmy_cursor: class AsyncAdapt_asyncmy_ss_cursor(AsyncAdapt_asyncmy_cursor): + # TODO: base on connectors/asyncio.py + # see #10415 __slots__ = () server_side = True @@ -171,6 +175,8 @@ class AsyncAdapt_asyncmy_ss_cursor(AsyncAdapt_asyncmy_cursor): class AsyncAdapt_asyncmy_connection(AdaptedConnection): + # TODO: base on connectors/asyncio.py + # see #10415 await_ = staticmethod(await_only) __slots__ = ("dbapi", "_execute_mutex") diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/base.py b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/base.py index 8b0e129..92f9077 100644 --- a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/base.py +++ b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/base.py @@ -999,14 +999,14 @@ output:: ) """ # noqa +from __future__ import annotations from array import array as _array from collections import defaultdict from itertools import compress import re +from typing import cast -from sqlalchemy import literal_column -from sqlalchemy.sql import visitors from . import reflection as _reflection from .enumerated import ENUM from .enumerated import SET @@ -1047,10 +1047,12 @@ from .types import TINYTEXT from .types import VARCHAR from .types import YEAR from ... import exc +from ... import literal_column from ... import log from ... import schema as sa_schema from ... import sql from ... import util +from ...engine import cursor as _cursor from ...engine import default from ...engine import reflection from ...engine.reflection import ReflectionDefaults @@ -1062,7 +1064,10 @@ from ...sql import operators from ...sql import roles from ...sql import sqltypes from ...sql import util as sql_util +from ...sql import visitors from ...sql.compiler import InsertmanyvaluesSentinelOpts +from ...sql.compiler import SQLCompiler +from ...sql.schema import SchemaConst from ...types import BINARY from ...types import BLOB from ...types import BOOLEAN @@ -1071,6 +1076,7 @@ from ...types import UUID from ...types import VARBINARY from ...util import topological + SET_RE = re.compile( r"\s*SET\s+(?:(?:GLOBAL|SESSION)\s+)?\w", re.I | re.UNICODE ) @@ -1164,6 +1170,32 @@ ischema_names = { class MySQLExecutionContext(default.DefaultExecutionContext): + def post_exec(self): + if ( + self.isdelete + and cast(SQLCompiler, self.compiled).effective_returning + and not self.cursor.description + ): + # All MySQL/mariadb drivers appear to not include + # cursor.description for DELETE..RETURNING with no rows if the + # WHERE criteria is a straight "false" condition such as our EMPTY + # IN condition. manufacture an empty result in this case (issue + # #10505) + # + # taken from cx_Oracle implementation + self.cursor_fetch_strategy = ( + _cursor.FullyBufferedCursorFetchStrategy( + self.cursor, + [ + (entry.keyname, None) + for entry in cast( + SQLCompiler, self.compiled + )._result_columns + ], + [], + ) + ) + def create_server_side_cursor(self): if self.dialect.supports_server_side_cursors: return self._dbapi_connection.cursor(self.dialect._sscursor) @@ -1208,6 +1240,12 @@ class MySQLCompiler(compiler.SQLCompiler): ) return f"{clause} WITH ROLLUP" + def visit_aggregate_strings_func(self, fn, **kw): + expr, delimeter = ( + elem._compiler_dispatch(self, **kw) for elem in fn.clauses + ) + return f"group_concat({expr} SEPARATOR {delimeter})" + def visit_sequence(self, seq, **kw): return "nextval(%s)" % self.preparer.format_sequence(seq) @@ -1760,7 +1798,12 @@ class MySQLCompiler(compiler.SQLCompiler): class MySQLDDLCompiler(compiler.DDLCompiler): def get_column_specification(self, column, **kw): """Builds column DDL.""" - + if ( + self.dialect.is_mariadb is True + and column.computed is not None + and column._user_defined_nullable is SchemaConst.NULL_UNSPECIFIED + ): + column.nullable = True colspec = [ self.preparer.format_column(column), self.dialect.type_compiler_instance.process( diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/mariadbconnector.py b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/mariadbconnector.py index 896b332..9730c9b 100644 --- a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/mariadbconnector.py +++ b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/mariadbconnector.py @@ -30,16 +30,46 @@ be ``mysqldb``. ``mariadb+mariadbconnector://`` is required to use this driver. """ # noqa import re +from uuid import UUID as _python_UUID from .base import MySQLCompiler from .base import MySQLDialect from .base import MySQLExecutionContext from ... import sql from ... import util +from ...sql import sqltypes + mariadb_cpy_minimum_version = (1, 0, 1) +class _MariaDBUUID(sqltypes.UUID[sqltypes._UUID_RETURN]): + # work around JIRA issue + # https://jira.mariadb.org/browse/CONPY-270. When that issue is fixed, + # this type can be removed. + def result_processor(self, dialect, coltype): + if self.as_uuid: + + def process(value): + if value is not None: + if hasattr(value, "decode"): + value = value.decode("ascii") + value = _python_UUID(value) + return value + + return process + else: + + def process(value): + if value is not None: + if hasattr(value, "decode"): + value = value.decode("ascii") + value = str(_python_UUID(value)) + return value + + return process + + class MySQLExecutionContext_mariadbconnector(MySQLExecutionContext): _lastrowid = None @@ -50,9 +80,20 @@ class MySQLExecutionContext_mariadbconnector(MySQLExecutionContext): return self._dbapi_connection.cursor(buffered=True) def post_exec(self): + super().post_exec() + + self._rowcount = self.cursor.rowcount + if self.isinsert and self.compiled.postfetch_lastrowid: self._lastrowid = self.cursor.lastrowid + @property + def rowcount(self): + if self._rowcount is not None: + return self._rowcount + else: + return self.cursor.rowcount + def get_lastrowid(self): return self._lastrowid @@ -87,6 +128,10 @@ class MySQLDialect_mariadbconnector(MySQLDialect): supports_server_side_cursors = True + colspecs = util.update_copy( + MySQLDialect.colspecs, {sqltypes.Uuid: _MariaDBUUID} + ) + @util.memoized_property def _dbapi_version(self): if self.dbapi and hasattr(self.dbapi, "__version__"): diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/mysqldb.py b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/mysqldb.py index 0868401..d1cf835 100644 --- a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/mysqldb.py +++ b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/mysqldb.py @@ -168,7 +168,7 @@ class MySQLDialect_mysqldb(MySQLDialect): return on_connect def do_ping(self, dbapi_connection): - dbapi_connection.ping(False) + dbapi_connection.ping() return True def do_executemany(self, cursor, statement, parameters, context=None): diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/pymysql.py b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/pymysql.py index 67ccb17..6567202 100644 --- a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/pymysql.py +++ b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/pymysql.py @@ -74,6 +74,40 @@ class MySQLDialect_pymysql(MySQLDialect_mysqldb): def import_dbapi(cls): return __import__("pymysql") + @langhelpers.memoized_property + def _send_false_to_ping(self): + """determine if pymysql has deprecated, changed the default of, + or removed the 'reconnect' argument of connection.ping(). + + See #10492 and + https://github.com/PyMySQL/mysqlclient/discussions/651#discussioncomment-7308971 + for background. + + """ # noqa: E501 + + try: + Connection = __import__("pymysql.connections").Connection + except (ImportError, AttributeError): + return True + else: + insp = langhelpers.get_callable_argspec(Connection.ping) + try: + reconnect_arg = insp.args[1] + except IndexError: + return False + else: + return reconnect_arg == "reconnect" and ( + not insp.defaults or insp.defaults[0] is not False + ) + + def do_ping(self, dbapi_connection): + if self._send_false_to_ping: + dbapi_connection.ping(False) + else: + dbapi_connection.ping() + + return True + def create_connect_args(self, url, _translate_args=None): if _translate_args is None: _translate_args = dict(username="user") diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/reflection.py b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/reflection.py index ce1b926..c4909fe 100644 --- a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/reflection.py +++ b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/reflection.py @@ -509,7 +509,7 @@ class MySQLTableDefinitionParser: r"\((?P[^\)]+?)\) REFERENCES +" r"(?P%(iq)s[^%(fq)s]+%(fq)s" r"(?:\.%(iq)s[^%(fq)s]+%(fq)s)?) +" - r"\((?P[^\)]+?)\)" + r"\((?P(?:%(iq)s[^%(fq)s]+%(fq)s(?: *, *)?)+)\)" r"(?: +(?PMATCH \w+))?" r"(?: +ON DELETE (?P%(on)s))?" r"(?: +ON UPDATE (?P%(on)s))?" % kw diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__init__.py b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__init__.py index 71aacd4..46a5d0a 100644 --- a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__init__.py +++ b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__init__.py @@ -59,4 +59,5 @@ __all__ = ( "VARCHAR2", "NVARCHAR2", "ROWID", + "REAL", ) diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/__init__.cpython-310.pyc index b34e439..e69eb64 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/base.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/base.cpython-310.pyc index 9a1db77..1cd5569 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/base.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/base.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/cx_oracle.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/cx_oracle.cpython-310.pyc index 288f38c..e63f77a 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/cx_oracle.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/cx_oracle.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/dictionary.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/dictionary.cpython-310.pyc index f0d8d81..7e17204 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/dictionary.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/dictionary.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/oracledb.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/oracledb.cpython-310.pyc index f861a4b..e5d0a23 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/oracledb.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/oracledb.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/provision.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/provision.cpython-310.pyc index 7b8d9a2..b031a2b 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/provision.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/provision.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/types.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/types.cpython-310.pyc index 22c8f1d..c0f1d0d 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/types.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/types.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/base.py b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/base.py index 2215998..d993ef2 100644 --- a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/base.py +++ b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/base.py @@ -1241,6 +1241,9 @@ class OracleCompiler(compiler.SQLCompiler): self.render_literal_value(flags, sqltypes.STRINGTYPE), ) + def visit_aggregate_strings_func(self, fn, **kw): + return "LISTAGG%s" % self.function_argspec(fn, **kw) + class OracleDDLCompiler(compiler.DDLCompiler): def define_constraint_cascades(self, constraint): @@ -1315,8 +1318,9 @@ class OracleDDLCompiler(compiler.DDLCompiler): text = text.replace("NO MINVALUE", "NOMINVALUE") text = text.replace("NO MAXVALUE", "NOMAXVALUE") text = text.replace("NO CYCLE", "NOCYCLE") - text = text.replace("NO ORDER", "NOORDER") - return text + if identity_options.order is not None: + text += " ORDER" if identity_options.order else " NOORDER" + return text.strip() def visit_computed_column(self, generated, **kw): text = "GENERATED ALWAYS AS (%s)" % self.sql_compiler.process( diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/cx_oracle.py b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/cx_oracle.py index da51f35..c595b56 100644 --- a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/cx_oracle.py +++ b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/cx_oracle.py @@ -978,8 +978,8 @@ class OracleDialect_cx_oracle(OracleDialect): driver = "cx_oracle" - colspecs = OracleDialect.colspecs - colspecs.update( + colspecs = util.update_copy( + OracleDialect.colspecs, { sqltypes.TIMESTAMP: _CXOracleTIMESTAMP, sqltypes.Numeric: _OracleNumeric, @@ -1006,7 +1006,7 @@ class OracleDialect_cx_oracle(OracleDialect): sqltypes.Uuid: _OracleUUID, oracle.NCLOB: _OracleUnicodeTextNCLOB, oracle.ROWID: _OracleRowid, - } + }, ) execute_sequence_format = list @@ -1088,9 +1088,9 @@ class OracleDialect_cx_oracle(OracleDialect): int(x) for x in m.group(1, 2, 3) if x is not None ) self.cx_oracle_ver = version - if self.cx_oracle_ver < (7,) and self.cx_oracle_ver > (0, 0, 0): + if self.cx_oracle_ver < (8,) and self.cx_oracle_ver > (0, 0, 0): raise exc.InvalidRequestError( - "cx_Oracle version 7 and above are supported" + "cx_Oracle version 8 and above are supported" ) @classmethod diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/types.py b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/types.py index 62028c7..4f82c43 100644 --- a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/types.py +++ b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/types.py @@ -4,12 +4,22 @@ # This module is part of SQLAlchemy and is released under # the MIT License: https://www.opensource.org/licenses/mit-license.php # mypy: ignore-errors +from __future__ import annotations + +import datetime as dt +from typing import Optional +from typing import Type +from typing import TYPE_CHECKING from ... import exc from ...sql import sqltypes from ...types import NVARCHAR from ...types import VARCHAR +if TYPE_CHECKING: + from ...engine.interfaces import Dialect + from ...sql.type_api import _LiteralProcessorType + class RAW(sqltypes._Binary): __visit_name__ = "RAW" @@ -116,38 +126,36 @@ class LONG(sqltypes.Text): class _OracleDateLiteralRender: def _literal_processor_datetime(self, dialect): def process(value): - if value is not None: - if getattr(value, "microsecond", None): - value = ( - f"""TO_TIMESTAMP""" - f"""('{value.isoformat().replace("T", " ")}', """ - """'YYYY-MM-DD HH24:MI:SS.FF')""" - ) - else: - value = ( - f"""TO_DATE""" - f"""('{value.isoformat().replace("T", " ")}', """ - """'YYYY-MM-DD HH24:MI:SS')""" - ) + if getattr(value, "microsecond", None): + value = ( + f"""TO_TIMESTAMP""" + f"""('{value.isoformat().replace("T", " ")}', """ + """'YYYY-MM-DD HH24:MI:SS.FF')""" + ) + else: + value = ( + f"""TO_DATE""" + f"""('{value.isoformat().replace("T", " ")}', """ + """'YYYY-MM-DD HH24:MI:SS')""" + ) return value return process def _literal_processor_date(self, dialect): def process(value): - if value is not None: - if getattr(value, "microsecond", None): - value = ( - f"""TO_TIMESTAMP""" - f"""('{value.isoformat().split("T")[0]}', """ - """'YYYY-MM-DD')""" - ) - else: - value = ( - f"""TO_DATE""" - f"""('{value.isoformat().split("T")[0]}', """ - """'YYYY-MM-DD')""" - ) + if getattr(value, "microsecond", None): + value = ( + f"""TO_TIMESTAMP""" + f"""('{value.isoformat().split("T")[0]}', """ + """'YYYY-MM-DD')""" + ) + else: + value = ( + f"""TO_DATE""" + f"""('{value.isoformat().split("T")[0]}', """ + """'YYYY-MM-DD')""" + ) return value return process @@ -203,6 +211,15 @@ class INTERVAL(sqltypes.NativeForEmulated, sqltypes._AbstractInterval): second_precision=interval.second_precision, ) + @classmethod + def adapt_emulated_to_native( + cls, interval: sqltypes.Interval, **kw # type: ignore[override] + ): + return INTERVAL( + day_precision=interval.day_precision, + second_precision=interval.second_precision, + ) + @property def _type_affinity(self): return sqltypes.Interval @@ -214,6 +231,18 @@ class INTERVAL(sqltypes.NativeForEmulated, sqltypes._AbstractInterval): day_precision=self.day_precision, ) + @property + def python_type(self) -> Type[dt.timedelta]: + return dt.timedelta + + def literal_processor( + self, dialect: Dialect + ) -> Optional[_LiteralProcessorType[dt.timedelta]]: + def process(value: dt.timedelta) -> str: + return f"NUMTODSINTERVAL({value.total_seconds()}, 'SECOND')" + + return process + class TIMESTAMP(sqltypes.TIMESTAMP): """Oracle implementation of ``TIMESTAMP``, which supports additional diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/__init__.cpython-310.pyc index 3bb3867..b57abad 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/_psycopg_common.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/_psycopg_common.cpython-310.pyc index da5a9ed..d9167e3 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/_psycopg_common.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/_psycopg_common.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/array.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/array.cpython-310.pyc index 84dd94a..57a0f22 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/array.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/array.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/asyncpg.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/asyncpg.cpython-310.pyc index bb8e79f..5376593 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/asyncpg.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/asyncpg.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/base.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/base.cpython-310.pyc index dfc595d..69efa59 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/base.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/base.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/dml.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/dml.cpython-310.pyc index cb63705..858860b 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/dml.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/dml.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/ext.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/ext.cpython-310.pyc index d68a33b..da82076 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/ext.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/ext.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/hstore.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/hstore.cpython-310.pyc index 26877cc..4d14cb7 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/hstore.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/hstore.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/json.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/json.cpython-310.pyc index 859dd8e..29cfdb4 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/json.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/json.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/named_types.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/named_types.cpython-310.pyc index 59dde89..2761fbb 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/named_types.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/named_types.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/operators.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/operators.cpython-310.pyc index 3089206..2136365 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/operators.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/operators.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/pg8000.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/pg8000.cpython-310.pyc index b8617d3..86789c3 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/pg8000.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/pg8000.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/pg_catalog.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/pg_catalog.cpython-310.pyc index ecf1c14..c897e2f 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/pg_catalog.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/pg_catalog.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/provision.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/provision.cpython-310.pyc index 1bbebb5..912f759 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/provision.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/provision.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg.cpython-310.pyc index 4ad616c..4db2abd 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg2.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg2.cpython-310.pyc index 967906e..49644a2 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg2.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg2.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg2cffi.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg2cffi.cpython-310.pyc index 428c223..a657b56 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg2cffi.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg2cffi.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/ranges.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/ranges.cpython-310.pyc index 35098aa..0d54199 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/ranges.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/ranges.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/types.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/types.cpython-310.pyc index 116fd86..a1f3467 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/types.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/types.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py index 1f6c0dc..ca35bf9 100644 --- a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py +++ b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py @@ -205,6 +205,7 @@ from .base import PGExecutionContext from .base import PGIdentifierPreparer from .base import REGCLASS from .base import REGCONFIG +from .types import BIT from .types import BYTEA from .types import CITEXT from ... import exc @@ -237,6 +238,10 @@ class AsyncpgTime(sqltypes.Time): render_bind_cast = True +class AsyncpgBit(BIT): + render_bind_cast = True + + class AsyncpgByteA(BYTEA): render_bind_cast = True @@ -566,6 +571,7 @@ class AsyncAdapt_asyncpg_cursor: async def _executemany(self, operation, seq_of_parameters): adapt_connection = self._adapt_connection + self.description = None async with adapt_connection._execute_mutex: await adapt_connection._check_type_cache_invalidation( self._invalidate_schema_cache_asof @@ -818,10 +824,23 @@ class AsyncAdapt_asyncpg_connection(AdaptedConnection): def ping(self): try: - _ = self.await_(self._connection.fetchrow(";")) + _ = self.await_(self._async_ping()) except Exception as error: self._handle_exception(error) + async def _async_ping(self): + if self._transaction is None and self.isolation_level != "autocommit": + # create a tranasction explicitly to support pgbouncer + # transaction mode. See #10226 + tr = self._connection.transaction() + await tr.start() + try: + await self._connection.fetchrow(";") + finally: + await tr.rollback() + else: + await self._connection.fetchrow(";") + def set_isolation_level(self, level): if self._started: self.rollback() @@ -1002,6 +1021,7 @@ class PGDialect_asyncpg(PGDialect): { sqltypes.String: AsyncpgString, sqltypes.ARRAY: AsyncpgARRAY, + BIT: AsyncpgBit, CITEXT: CITEXT, REGCONFIG: AsyncpgREGCONFIG, sqltypes.Time: AsyncpgTime, diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/base.py b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/base.py index 08fd5d3..b9fd8c8 100644 --- a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/base.py +++ b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/base.py @@ -303,7 +303,7 @@ Setting Alternate Search Paths on Connect ------------------------------------------ The PostgreSQL ``search_path`` variable refers to the list of schema names -that will be implicitly referred towards when a particular table or other +that will be implicitly referenced when a particular table or other object is referenced in a SQL statement. As detailed in the next section :ref:`postgresql_schema_reflection`, SQLAlchemy is generally organized around the concept of keeping this variable at its default value of ``public``, @@ -1376,8 +1376,8 @@ Built-in support for rendering a ``ROW`` may be approximated using Table Types passed to Functions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -PostgreSQL supports passing a table as an argument to a function, which it -refers towards as a "record" type. SQLAlchemy :class:`_sql.FromClause` objects +PostgreSQL supports passing a table as an argument to a function, which is +known as a "record" type. SQLAlchemy :class:`_sql.FromClause` objects such as :class:`_schema.Table` support this special form using the :meth:`_sql.FromClause.table_valued` method, which is comparable to the :meth:`_functions.FunctionElement.table_valued` method except that the collection @@ -1868,6 +1868,9 @@ class PGCompiler(compiler.SQLCompiler): value = value.replace("\\", "\\\\") return value + def visit_aggregate_strings_func(self, fn, **kw): + return "string_agg%s" % self.function_argspec(fn) + def visit_sequence(self, seq, **kw): return "nextval('%s')" % self.preparer.format_sequence(seq) @@ -4114,9 +4117,13 @@ class PGDialect(default.DefaultDialect): @util.memoized_property def _fk_regex_pattern(self): + # optionally quoted token + qtoken = '(?:"[^"]+"|[A-Za-z0-9_]+?)' + # https://www.postgresql.org/docs/current/static/sql-createtable.html return re.compile( - r"FOREIGN KEY \((.*?)\) REFERENCES (?:(.*?)\.)?(.*?)\((.*?)\)" + r"FOREIGN KEY \((.*?)\) " + rf"REFERENCES (?:({qtoken})\.)?({qtoken})\(((?:{qtoken}(?: *, *)?)+)\)" # noqa: E501 r"[\s]?(MATCH (FULL|PARTIAL|SIMPLE)+)?" r"[\s]?(ON UPDATE " r"(CASCADE|RESTRICT|NO ACTION|SET NULL|SET DEFAULT)+)?" diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/psycopg2.py b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/psycopg2.py index 27f63ea..2719f3d 100644 --- a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/psycopg2.py +++ b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/psycopg2.py @@ -254,7 +254,7 @@ equivalent to psycopg2's ``execute_values()`` handler; an overview of this feature and its configuration are at :ref:`engine_insertmanyvalues`. .. versionadded:: 2.0 Replaced psycopg2's ``execute_values()`` fast execution - helper with a native SQLAlchemy mechanism referred towards as + helper with a native SQLAlchemy mechanism known as :ref:`insertmanyvalues `. The psycopg2 dialect retains the ability to use the psycopg2-specific diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/ranges.py b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/ranges.py index 2cd1552..f1c2989 100644 --- a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/ranges.py +++ b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/ranges.py @@ -293,7 +293,7 @@ class Range(Generic[_T]): else: return 0 - def __eq__(self, other: Any) -> bool: # type: ignore[override] # noqa: E501 + def __eq__(self, other: Any) -> bool: """Compare this range to the `other` taking into account bounds inclusivity, returning ``True`` if they are equal. """ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/types.py b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/types.py index 2f49ff1..2cac5d8 100644 --- a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/types.py +++ b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/types.py @@ -18,7 +18,9 @@ from ...sql import type_api from ...util.typing import Literal if TYPE_CHECKING: + from ...engine.interfaces import Dialect from ...sql.operators import OperatorType + from ...sql.type_api import _LiteralProcessorType from ...sql.type_api import TypeEngine _DECIMAL_TYPES = (1231, 1700) @@ -247,6 +249,14 @@ class INTERVAL(type_api.NativeForEmulated, sqltypes._AbstractInterval): def python_type(self) -> Type[dt.timedelta]: return dt.timedelta + def literal_processor( + self, dialect: Dialect + ) -> Optional[_LiteralProcessorType[dt.timedelta]]: + def process(value: dt.timedelta) -> str: + return f"make_interval(secs=>{value.total_seconds()})" + + return process + PGInterval = INTERVAL diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/__init__.cpython-310.pyc index 41b390d..a52209b 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/aiosqlite.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/aiosqlite.cpython-310.pyc index ea451f6..1b6324e 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/aiosqlite.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/aiosqlite.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/base.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/base.cpython-310.pyc index 10cd48b..a9b5f23 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/base.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/base.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/dml.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/dml.cpython-310.pyc index 04d88b6..4c1dc17 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/dml.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/dml.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/json.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/json.cpython-310.pyc index 52a65d6..b8d199f 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/json.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/json.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/provision.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/provision.cpython-310.pyc index 4026b97..0a2faa9 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/provision.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/provision.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/pysqlcipher.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/pysqlcipher.cpython-310.pyc index 798ac6f..78c7c39 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/pysqlcipher.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/pysqlcipher.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/pysqlite.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/pysqlite.cpython-310.pyc index afedc0a..439e983 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/pysqlite.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/pysqlite.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/aiosqlite.py b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/aiosqlite.py index b8011a5..d9438d1 100644 --- a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/aiosqlite.py +++ b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/aiosqlite.py @@ -44,6 +44,36 @@ User-Defined Functions aiosqlite extends pysqlite to support async, so we can create our own user-defined functions (UDFs) in Python and use them directly in SQLite queries as described here: :ref:`pysqlite_udfs`. +.. _aiosqlite_serializable: + +Serializable isolation / Savepoints / Transactional DDL (asyncio version) +------------------------------------------------------------------------- + +Similarly to pysqlite, aiosqlite does not support SAVEPOINT feature. + +The solution is similar to :ref:`pysqlite_serializable`. This is achieved by the event listeners in async:: + + from sqlalchemy import create_engine, event + from sqlalchemy.ext.asyncio import create_async_engine + + engine = create_async_engine("sqlite+aiosqlite:///myfile.db") + + @event.listens_for(engine.sync_engine, "connect") + def do_connect(dbapi_connection, connection_record): + # disable aiosqlite's emitting of the BEGIN statement entirely. + # also stops it from emitting COMMIT before any DDL. + dbapi_connection.isolation_level = None + + @event.listens_for(engine.sync_engine, "begin") + def do_begin(conn): + # emit our own BEGIN + conn.exec_driver_sql("BEGIN") + +.. warning:: When using the above recipe, it is advised to not use the + :paramref:`.Connection.execution_options.isolation_level` setting on + :class:`_engine.Connection` and :func:`_sa.create_engine` + with the SQLite driver, + as this function necessarily will also alter the ".isolation_level" setting. """ # noqa @@ -60,6 +90,9 @@ from ...util.concurrency import await_only class AsyncAdapt_aiosqlite_cursor: + # TODO: base on connectors/asyncio.py + # see #10415 + __slots__ = ( "_adapt_connection", "_connection", @@ -151,6 +184,8 @@ class AsyncAdapt_aiosqlite_cursor: class AsyncAdapt_aiosqlite_ss_cursor(AsyncAdapt_aiosqlite_cursor): + # TODO: base on connectors/asyncio.py + # see #10415 __slots__ = "_cursor" server_side = True diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/base.py b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/base.py index bd6c1df..d4eb3bc 100644 --- a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/base.py +++ b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/base.py @@ -215,7 +215,7 @@ by *not even emitting BEGIN* until the first write operation. SQLite's transactional scope is impacted by unresolved issues in the pysqlite driver, which defers BEGIN statements to a greater degree than is often feasible. See the section :ref:`pysqlite_serializable` - for techniques to work around this behavior. + or :ref:`aiosqlite_serializable` for techniques to work around this behavior. .. seealso:: @@ -273,8 +273,9 @@ won't work at all with pysqlite unless workarounds are taken. .. warning:: SQLite's SAVEPOINT feature is impacted by unresolved - issues in the pysqlite driver, which defers BEGIN statements to a greater - degree than is often feasible. See the section :ref:`pysqlite_serializable` + issues in the pysqlite and aiosqlite drivers, which defer BEGIN statements + to a greater degree than is often feasible. See the sections + :ref:`pysqlite_serializable` and :ref:`aiosqlite_serializable` for techniques to work around this behavior. Transactional DDL @@ -843,7 +844,7 @@ Reflecting internal schema tables ---------------------------------- Reflection methods that return lists of tables will omit so-called -"SQLite internal schema object" names, which are referred towards by SQLite +"SQLite internal schema object" names, which are considered by SQLite as any object name that is prefixed with ``sqlite_``. An example of such an object is the ``sqlite_sequence`` table that's generated when the ``AUTOINCREMENT`` column parameter is used. In order to return @@ -1318,6 +1319,9 @@ class SQLiteCompiler(compiler.SQLCompiler): def visit_char_length_func(self, fn, **kw): return "length%s" % self.function_argspec(fn) + def visit_aggregate_strings_func(self, fn, **kw): + return "group_concat%s" % self.function_argspec(fn) + def visit_cast(self, cast, **kwargs): if self.dialect.supports_cast: return super().visit_cast(cast, **kwargs) @@ -2444,10 +2448,16 @@ class SQLiteDialect(default.DefaultDialect): if table_data is None: # system tables, etc. return + + # note that we already have the FKs from PRAGMA above. This whole + # regexp thing is trying to locate additional detail about the + # FKs, namely the name of the constraint and other options. + # so parsing the columns is really about matching it up to what + # we already have. FK_PATTERN = ( r"(?:CONSTRAINT (\w+) +)?" r"FOREIGN KEY *\( *(.+?) *\) +" - r'REFERENCES +(?:(?:"(.+?)")|([a-z0-9_]+)) *\((.+?)\) *' + r'REFERENCES +(?:(?:"(.+?)")|([a-z0-9_]+)) *\( *((?:(?:"[^"]+"|[a-z0-9_]+) *(?:, *)?)+)\) *' # noqa: E501 r"((?:ON (?:DELETE|UPDATE) " r"(?:SET NULL|SET DEFAULT|CASCADE|RESTRICT|NO ACTION) *)*)" r"((?:NOT +)?DEFERRABLE)?" diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/__init__.cpython-310.pyc index 9fd29a6..55b251d 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_processors.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_processors.cpython-310.pyc index 0669d64..baa3b8e 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_processors.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_processors.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_row.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_row.cpython-310.pyc index 61cba88..6b87d22 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_row.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_row.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_util.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_util.cpython-310.pyc index 9e703d5..bd7893f 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_util.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_util.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/base.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/base.cpython-310.pyc index d9c4a01..4900c3e 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/base.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/base.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/characteristics.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/characteristics.cpython-310.pyc index 8ebdb65..ecbaffa 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/characteristics.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/characteristics.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/create.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/create.cpython-310.pyc index 0da94d5..8bb4639 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/create.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/create.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/cursor.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/cursor.cpython-310.pyc index 3dc253f..97386a1 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/cursor.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/cursor.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/default.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/default.cpython-310.pyc index f4ee539..ea8c0a9 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/default.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/default.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/events.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/events.cpython-310.pyc index b03c82a..013011d 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/events.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/events.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/interfaces.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/interfaces.cpython-310.pyc index ab5e8bf..c4551a7 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/interfaces.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/interfaces.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/mock.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/mock.cpython-310.pyc index 8779ba9..5bbde80 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/mock.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/mock.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/processors.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/processors.cpython-310.pyc index 34c8a21..a340b53 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/processors.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/processors.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/reflection.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/reflection.cpython-310.pyc index 02a932d..f2207fc 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/reflection.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/reflection.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/result.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/result.cpython-310.pyc index d06526d..abda210 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/result.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/result.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/row.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/row.cpython-310.pyc index b37197d..8bed559 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/row.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/row.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/strategies.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/strategies.cpython-310.pyc index c117163..6b1abed 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/strategies.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/strategies.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/url.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/url.cpython-310.pyc index 553ac32..2d2b7d2 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/url.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/url.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/util.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/util.cpython-310.pyc index c582510..4ee81f1 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/util.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/util.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/base.py b/venv/Lib/site-packages/sqlalchemy/engine/base.py index b0cd721..0000e28 100644 --- a/venv/Lib/site-packages/sqlalchemy/engine/base.py +++ b/venv/Lib/site-packages/sqlalchemy/engine/base.py @@ -205,7 +205,11 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]): @property def _schema_translate_map(self) -> Optional[SchemaTranslateMapType]: - return self._execution_options.get("schema_translate_map", None) + schema_translate_map: Optional[ + SchemaTranslateMapType + ] = self._execution_options.get("schema_translate_map", None) + + return schema_translate_map def schema_for_object(self, obj: HasSchemaAttr) -> Optional[str]: """Return the schema name for the given schema item taking into @@ -814,7 +818,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]): The above code is not fundamentally any different in its behavior than the following code which does not use - :meth:`_engine.Connection.begin`; the below style is referred towards + :meth:`_engine.Connection.begin`; the below style is known as "commit as you go" style:: with engine.connect() as conn: diff --git a/venv/Lib/site-packages/sqlalchemy/engine/cursor.py b/venv/Lib/site-packages/sqlalchemy/engine/cursor.py index 246cf6f..45af49a 100644 --- a/venv/Lib/site-packages/sqlalchemy/engine/cursor.py +++ b/venv/Lib/site-packages/sqlalchemy/engine/cursor.py @@ -1995,7 +1995,7 @@ class CursorResult(Result[_T]): * :attr:`_engine.CursorResult.rowcount` is *only* useful in conjunction with an UPDATE or DELETE statement. Contrary to what the Python - DBAPI says, it does *not* return the + DBAPI says, it does *not* reliably return the number of rows available from the results of a SELECT statement as DBAPIs cannot support this functionality when rows are unbuffered. diff --git a/venv/Lib/site-packages/sqlalchemy/engine/default.py b/venv/Lib/site-packages/sqlalchemy/engine/default.py index 4b8dd87..553d8f0 100644 --- a/venv/Lib/site-packages/sqlalchemy/engine/default.py +++ b/venv/Lib/site-packages/sqlalchemy/engine/default.py @@ -71,6 +71,7 @@ if typing.TYPE_CHECKING: from types import ModuleType from .base import Engine + from .cursor import ResultFetchStrategy from .interfaces import _CoreMultiExecuteParams from .interfaces import _CoreSingleExecuteParams from .interfaces import _DBAPICursorDescription @@ -135,7 +136,7 @@ class DefaultDialect(Dialect): # most DBAPIs happy with this for execute(). # not cx_oracle. - execute_sequence_format = tuple # type: ignore + execute_sequence_format = tuple supports_schemas = True supports_views = True @@ -1853,7 +1854,7 @@ class DefaultExecutionContext(ExecutionContext): def _setup_dml_or_text_result(self): compiled = cast(SQLCompiler, self.compiled) - strategy = self.cursor_fetch_strategy + strategy: ResultFetchStrategy = self.cursor_fetch_strategy if self.isinsert: if ( @@ -1882,9 +1883,15 @@ class DefaultExecutionContext(ExecutionContext): strategy = _cursor.BufferedRowCursorFetchStrategy( self.cursor, self.execution_options ) - cursor_description = ( - strategy.alternate_cursor_description or self.cursor.description - ) + + if strategy is _cursor._NO_CURSOR_DML: + cursor_description = None + else: + cursor_description = ( + strategy.alternate_cursor_description + or self.cursor.description + ) + if cursor_description is None: strategy = _cursor._NO_CURSOR_DML elif self._num_sentinel_cols: @@ -2232,7 +2239,7 @@ class DefaultExecutionContext(ExecutionContext): and compile_state._has_multi_parameters ): if column._is_multiparam_column: - index = column.index + 1 # type: ignore + index = column.index + 1 d = {column.original.key: parameters[column.key]} else: d = {column.key: parameters[column.key]} @@ -2304,7 +2311,7 @@ class DefaultExecutionContext(ExecutionContext): param[param_key] = arg elif is_callable: self.current_column = c - param[param_key] = arg(self) # type: ignore + param[param_key] = arg(self) else: val = fallback(c) if val is not None: diff --git a/venv/Lib/site-packages/sqlalchemy/engine/events.py b/venv/Lib/site-packages/sqlalchemy/engine/events.py index 848f397..aac756d 100644 --- a/venv/Lib/site-packages/sqlalchemy/engine/events.py +++ b/venv/Lib/site-packages/sqlalchemy/engine/events.py @@ -131,7 +131,7 @@ class ConnectionEvents(event.Events[ConnectionEventsTarget]): if default_dispatch is None and hasattr( target, "_no_async_engine_events" ): - target._no_async_engine_events() # type: ignore + target._no_async_engine_events() return default_dispatch @@ -640,7 +640,7 @@ class DialectEvents(event.Events[Dialect]): _dispatch_target = Dialect @classmethod - def _listen( # type: ignore + def _listen( cls, event_key: event._EventKey[Dialect], *, diff --git a/venv/Lib/site-packages/sqlalchemy/engine/interfaces.py b/venv/Lib/site-packages/sqlalchemy/engine/interfaces.py index c7db910..ea1f27d 100644 --- a/venv/Lib/site-packages/sqlalchemy/engine/interfaces.py +++ b/venv/Lib/site-packages/sqlalchemy/engine/interfaces.py @@ -521,7 +521,7 @@ class ReflectedIndex(TypedDict): """index name""" column_names: List[Optional[str]] - """column names which the index refers towards. + """column names which the index references. An element of this list is ``None`` if it's an expression and is returned in the ``expressions`` list. """ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/mock.py b/venv/Lib/site-packages/sqlalchemy/engine/mock.py index b80eab5..618ea1d 100644 --- a/venv/Lib/site-packages/sqlalchemy/engine/mock.py +++ b/venv/Lib/site-packages/sqlalchemy/engine/mock.py @@ -126,6 +126,6 @@ def create_mock_engine( dialect_args[k] = kw.pop(k) # create dialect - dialect = dialect_cls(**dialect_args) # type: ignore + dialect = dialect_cls(**dialect_args) return MockConnection(dialect, executor) diff --git a/venv/Lib/site-packages/sqlalchemy/engine/reflection.py b/venv/Lib/site-packages/sqlalchemy/engine/reflection.py index 4035901..6d2a8a2 100644 --- a/venv/Lib/site-packages/sqlalchemy/engine/reflection.py +++ b/venv/Lib/site-packages/sqlalchemy/engine/reflection.py @@ -230,7 +230,7 @@ class Inspector(inspection.Inspectable["Inspector"]): cls, init: Callable[..., Any], bind: Union[Engine, Connection] ) -> Inspector: if hasattr(bind.dialect, "inspector"): - cls = bind.dialect.inspector # type: ignore[attr-defined] + cls = bind.dialect.inspector self = cls.__new__(cls) init(self, bind) @@ -240,7 +240,7 @@ class Inspector(inspection.Inspectable["Inspector"]): if hasattr(bind, "exec_driver_sql"): self._init_connection(bind) # type: ignore[arg-type] else: - self._init_engine(bind) # type: ignore[arg-type] + self._init_engine(bind) def _init_engine(self, engine: Engine) -> None: self.bind = self.engine = engine @@ -1627,9 +1627,7 @@ class Inspector(inspection.Inspectable["Inspector"]): orig_name = col_d["name"] table.metadata.dispatch.column_reflect(self, table, col_d) - table.dispatch.column_reflect( # type: ignore[attr-defined] - self, table, col_d - ) + table.dispatch.column_reflect(self, table, col_d) # fetch name again as column_reflect is allowed to # change it @@ -2038,7 +2036,7 @@ class ReflectionDefaults: @classmethod def pk_constraint(cls) -> ReflectedPrimaryKeyConstraint: - return { # type: ignore # pep-655 not supported + return { "name": None, "constrained_columns": [], } diff --git a/venv/Lib/site-packages/sqlalchemy/engine/result.py b/venv/Lib/site-packages/sqlalchemy/engine/result.py index 1c9cc50..132ae88 100644 --- a/venv/Lib/site-packages/sqlalchemy/engine/result.py +++ b/venv/Lib/site-packages/sqlalchemy/engine/result.py @@ -373,7 +373,7 @@ class SimpleResultMetaData(ResultMetaData): indexes: Sequence[int] new_keys: Sequence[str] extra: Sequence[Any] - indexes, new_keys, extra = zip(*metadata_for_keys) # type: ignore + indexes, new_keys, extra = zip(*metadata_for_keys) if self._translated_indexes: indexes = [self._translated_indexes[idx] for idx in indexes] @@ -459,7 +459,7 @@ class ResultInternal(InPlaceGenerative, Generic[_R]): else: _proc = Row - def process_row( # type: ignore + def process_row( metadata: ResultMetaData, processors: Optional[_ProcessorsType], key_to_index: Mapping[_KeyType, int], diff --git a/venv/Lib/site-packages/sqlalchemy/engine/util.py b/venv/Lib/site-packages/sqlalchemy/engine/util.py index b0a54f9..9b147a7 100644 --- a/venv/Lib/site-packages/sqlalchemy/engine/util.py +++ b/venv/Lib/site-packages/sqlalchemy/engine/util.py @@ -48,7 +48,7 @@ def connection_memoize(key: str) -> Callable[[_C], _C]: connection.info[key] = val = fn(self, connection) return val - return decorated # type: ignore + return decorated class _TConsSubject(Protocol): diff --git a/venv/Lib/site-packages/sqlalchemy/event/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/event/__pycache__/__init__.cpython-310.pyc index 141e007..a22bb6a 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/event/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/event/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/event/__pycache__/api.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/event/__pycache__/api.cpython-310.pyc index 3e204e6..ca4a541 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/event/__pycache__/api.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/event/__pycache__/api.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/event/__pycache__/attr.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/event/__pycache__/attr.cpython-310.pyc index 08a54d8..7ac603a 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/event/__pycache__/attr.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/event/__pycache__/attr.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/event/__pycache__/base.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/event/__pycache__/base.cpython-310.pyc index 5a80055..c92b323 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/event/__pycache__/base.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/event/__pycache__/base.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/event/__pycache__/legacy.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/event/__pycache__/legacy.cpython-310.pyc index 13bd5d2..c21b6ae 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/event/__pycache__/legacy.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/event/__pycache__/legacy.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/event/__pycache__/registry.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/event/__pycache__/registry.cpython-310.pyc index eefd630..177ab42 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/event/__pycache__/registry.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/event/__pycache__/registry.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/event/base.py b/venv/Lib/site-packages/sqlalchemy/event/base.py index 2c32b04..f92b2ed 100644 --- a/venv/Lib/site-packages/sqlalchemy/event/base.py +++ b/venv/Lib/site-packages/sqlalchemy/event/base.py @@ -301,7 +301,7 @@ class _HasEventsDispatch(Generic[_ET]): "Type[_Dispatch[_ET]]", type( "%sDispatch" % classname, - (dispatch_base,), # type: ignore + (dispatch_base,), {"__slots__": event_names}, ), ) @@ -323,7 +323,7 @@ class _HasEventsDispatch(Generic[_ET]): assert dispatch_target_cls is not None if ( hasattr(dispatch_target_cls, "__slots__") - and "_slots_dispatch" in dispatch_target_cls.__slots__ # type: ignore # noqa: E501 + and "_slots_dispatch" in dispatch_target_cls.__slots__ ): dispatch_target_cls.dispatch = slots_dispatcher(cls) else: diff --git a/venv/Lib/site-packages/sqlalchemy/event/registry.py b/venv/Lib/site-packages/sqlalchemy/event/registry.py index 8e4a266..fb2fed8 100644 --- a/venv/Lib/site-packages/sqlalchemy/event/registry.py +++ b/venv/Lib/site-packages/sqlalchemy/event/registry.py @@ -241,7 +241,7 @@ class _EventKey(Generic[_ET]): ): self.target = target self.identifier = identifier - self.fn = fn # type: ignore[assignment] + self.fn = fn if isinstance(fn, types.MethodType): self.fn_key = id(fn.__func__), id(fn.__self__) else: diff --git a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/__init__.cpython-310.pyc index 3040c2e..74e1606 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/associationproxy.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/associationproxy.cpython-310.pyc index 813f684..a89526f 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/associationproxy.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/associationproxy.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/automap.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/automap.cpython-310.pyc index 1c1bcf8..8d490ef 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/automap.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/automap.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/baked.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/baked.cpython-310.pyc index 040bd97..3891847 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/baked.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/baked.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/compiler.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/compiler.cpython-310.pyc index 9978937..2117dfc 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/compiler.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/compiler.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/horizontal_shard.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/horizontal_shard.cpython-310.pyc index 83e9bd5..32b9bb1 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/horizontal_shard.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/horizontal_shard.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/hybrid.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/hybrid.cpython-310.pyc index cd660c7..c585a1b 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/hybrid.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/hybrid.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/indexable.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/indexable.cpython-310.pyc index 3385421..968eb48 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/indexable.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/indexable.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/instrumentation.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/instrumentation.cpython-310.pyc index 423a1e4..219c352 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/instrumentation.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/instrumentation.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/mutable.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/mutable.cpython-310.pyc index d24f6a8..04e1c45 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/mutable.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/mutable.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/orderinglist.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/orderinglist.cpython-310.pyc index cb084aa..84977b3 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/orderinglist.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/orderinglist.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/serializer.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/serializer.cpython-310.pyc index 500ef93..48e8c41 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/serializer.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/serializer.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/associationproxy.py b/venv/Lib/site-packages/sqlalchemy/ext/associationproxy.py index 38755c8..31df134 100644 --- a/venv/Lib/site-packages/sqlalchemy/ext/associationproxy.py +++ b/venv/Lib/site-packages/sqlalchemy/ext/associationproxy.py @@ -1047,7 +1047,7 @@ class AssociationProxyInstance(SQLORMOperations[_T]): target_assoc = self._unwrap_target_assoc_proxy if target_assoc is not None: - inner = target_assoc._criterion_exists( # type: ignore + inner = target_assoc._criterion_exists( criterion=criterion, **kwargs ) return self._comparator._criterion_exists(inner) @@ -1961,7 +1961,7 @@ class _AssociationSet(_AssociationSingleItem[_T], MutableSet[_T]): return set(self).symmetric_difference(__s) def __xor__(self, s: AbstractSet[_S]) -> MutableSet[Union[_T, _S]]: - return self.symmetric_difference(s) # type: ignore + return self.symmetric_difference(s) def symmetric_difference_update(self, other: Iterable[Any]) -> None: want, have = self.symmetric_difference(other), set(self) diff --git a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__init__.py b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__init__.py index ad6cd15..8564db6 100644 --- a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__init__.py +++ b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__init__.py @@ -22,3 +22,4 @@ from .session import async_sessionmaker as async_sessionmaker from .session import AsyncAttrs as AsyncAttrs from .session import AsyncSession as AsyncSession from .session import AsyncSessionTransaction as AsyncSessionTransaction +from .session import close_all_sessions as close_all_sessions diff --git a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/__init__.cpython-310.pyc index 036da91..4c5db43 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/base.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/base.cpython-310.pyc index 3779b0d..1a39db4 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/base.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/base.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/engine.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/engine.cpython-310.pyc index ce2325e..c143ec9 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/engine.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/engine.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/exc.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/exc.cpython-310.pyc index 9d2dbd4..f21d3ae 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/exc.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/exc.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/result.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/result.cpython-310.pyc index 22b39e8..4a2ae49 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/result.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/result.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/scoping.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/scoping.cpython-310.pyc index 88b02c2..255cea3 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/scoping.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/scoping.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/session.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/session.cpython-310.pyc index aeac191..3ec02d7 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/session.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/session.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/base.py b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/base.py index 1fecf60..251f521 100644 --- a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/base.py +++ b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/base.py @@ -58,9 +58,7 @@ class ReversibleProxy(Generic[_PT]): ) proxy_ref = weakref.ref( self, - functools.partial( # type: ignore - ReversibleProxy._target_gced, target_ref - ), + functools.partial(ReversibleProxy._target_gced, target_ref), ) ReversibleProxy._proxy_objects[target_ref] = proxy_ref @@ -70,7 +68,7 @@ class ReversibleProxy(Generic[_PT]): def _target_gced( cls, ref: weakref.ref[_PT], - proxy_ref: Optional[weakref.ref[Self]] = None, + proxy_ref: Optional[weakref.ref[Self]] = None, # noqa: U100 ) -> None: cls._proxy_objects.pop(ref, None) @@ -124,7 +122,7 @@ class StartableContext(Awaitable[_T_co], abc.ABC): return self.start().__await__() async def __aenter__(self) -> _T_co: - return await self.start(is_ctxmanager=True) # type: ignore + return await self.start(is_ctxmanager=True) @abc.abstractmethod async def __aexit__( diff --git a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/engine.py b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/engine.py index deab97f..bf968cc 100644 --- a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/engine.py +++ b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/engine.py @@ -257,7 +257,9 @@ class AsyncConnection( AsyncEngine._retrieve_proxy_for_target(target.engine), target ) - async def start(self, is_ctxmanager: bool = False) -> AsyncConnection: + async def start( + self, is_ctxmanager: bool = False # noqa: U100 + ) -> AsyncConnection: """Start this :class:`_asyncio.AsyncConnection` object's context outside of using a Python ``with:`` block. @@ -1442,7 +1444,9 @@ def _get_sync_engine_or_connection( @inspection._inspects(AsyncConnection) -def _no_insp_for_async_conn_yet(subject: AsyncConnection) -> NoReturn: +def _no_insp_for_async_conn_yet( + subject: AsyncConnection, # noqa: U100 +) -> NoReturn: raise exc.NoInspectionAvailable( "Inspection on an AsyncConnection is currently not supported. " "Please use ``run_sync`` to pass a callable where it's possible " @@ -1452,7 +1456,9 @@ def _no_insp_for_async_conn_yet(subject: AsyncConnection) -> NoReturn: @inspection._inspects(AsyncEngine) -def _no_insp_for_async_engine_xyet(subject: AsyncEngine) -> NoReturn: +def _no_insp_for_async_engine_xyet( + subject: AsyncEngine, # noqa: U100 +) -> NoReturn: raise exc.NoInspectionAvailable( "Inspection on an AsyncEngine is currently not supported. " "Please obtain a connection then use ``conn.run_sync`` to pass a " diff --git a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/result.py b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/result.py index 3dcb1cf..a13e106 100644 --- a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/result.py +++ b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/result.py @@ -60,7 +60,7 @@ class AsyncCommon(FilterResult[_R]): .. versionadded:: 2.0.0b3 """ - return self._real_result.closed # type: ignore + return self._real_result.closed class AsyncResult(_WithKeys, AsyncCommon[Row[_TP]]): diff --git a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/scoping.py b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/scoping.py index b70c336..4c68f53 100644 --- a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/scoping.py +++ b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/scoping.py @@ -77,6 +77,7 @@ _T = TypeVar("_T", bound=Any) "begin", "begin_nested", "close", + "reset", "commit", "connection", "delete", @@ -94,6 +95,8 @@ _T = TypeVar("_T", bound=Any) "rollback", "scalar", "scalars", + "get", + "get_one", "stream", "stream_scalars", ], @@ -108,6 +111,7 @@ _T = TypeVar("_T", bound=Any) "no_autoflush", "info", ], + use_intermediate_variable=["get"], ) class async_scoped_session(Generic[_AS]): """Provides scoped management of :class:`.AsyncSession` objects. @@ -213,49 +217,6 @@ class async_scoped_session(Generic[_AS]): await self.registry().close() self.registry.clear() - async def get( - self, - entity: _EntityBindKey[_O], - ident: _PKIdentityArgument, - *, - options: Optional[Sequence[ORMOption]] = None, - populate_existing: bool = False, - with_for_update: ForUpdateParameter = None, - identity_token: Optional[Any] = None, - execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, - ) -> Optional[_O]: - r"""Return an instance based on the given primary key identifier, - or ``None`` if not found. - - .. container:: class_bases - - Proxied for the :class:`_asyncio.AsyncSession` class on - behalf of the :class:`_asyncio.scoping.async_scoped_session` class. - - .. seealso:: - - :meth:`_orm.Session.get` - main documentation for get - - - - """ # noqa: E501 - - # this was proxied but Mypy is requiring the return type to be - # clarified - - # work around: - # https://github.com/python/typing/discussions/1143 - return_value = await self._proxied.get( - entity, - ident, - options=options, - populate_existing=populate_existing, - with_for_update=with_for_update, - identity_token=identity_token, - execution_options=execution_options, - ) - return return_value - # START PROXY METHODS async_scoped_session # code within this block is **programmatically, @@ -433,6 +394,12 @@ class async_scoped_session(Generic[_AS]): For a general description of ORM begin nested, see :meth:`_orm.Session.begin_nested`. + .. seealso:: + + :ref:`aiosqlite_serializable` - special workarounds required + with the SQLite asyncio driver in order for SAVEPOINT to work + correctly. + """ # noqa: E501 @@ -447,34 +414,45 @@ class async_scoped_session(Generic[_AS]): Proxied for the :class:`_asyncio.AsyncSession` class on behalf of the :class:`_asyncio.scoping.async_scoped_session` class. - This expunges all ORM objects associated with this - :class:`_asyncio.AsyncSession`, ends any transaction in progress and - :term:`releases` any :class:`_asyncio.AsyncConnection` objects which - this :class:`_asyncio.AsyncSession` itself has checked out from - associated :class:`_asyncio.AsyncEngine` objects. The operation then - leaves the :class:`_asyncio.AsyncSession` in a state which it may be - used again. - - .. tip:: - - The :meth:`_asyncio.AsyncSession.close` method **does not prevent - the Session from being used again**. The - :class:`_asyncio.AsyncSession` itself does not actually have a - distinct "closed" state; it merely means the - :class:`_asyncio.AsyncSession` will release all database - connections and ORM objects. - - .. seealso:: + :meth:`_orm.Session.close` - main documentation for + "close" + :ref:`session_closing` - detail on the semantics of - :meth:`_asyncio.AsyncSession.close` + :meth:`_asyncio.AsyncSession.close` and + :meth:`_asyncio.AsyncSession.reset`. """ # noqa: E501 return await self._proxied.close() + async def reset(self) -> None: + r"""Close out the transactional resources and ORM objects used by this + :class:`_orm.Session`, resetting the session to its initial state. + + .. container:: class_bases + + Proxied for the :class:`_asyncio.AsyncSession` class on + behalf of the :class:`_asyncio.scoping.async_scoped_session` class. + + .. versionadded:: 2.0.22 + + .. seealso:: + + :meth:`_orm.Session.reset` - main documentation for + "reset" + + :ref:`session_closing` - detail on the semantics of + :meth:`_asyncio.AsyncSession.close` and + :meth:`_asyncio.AsyncSession.reset`. + + + """ # noqa: E501 + + return await self._proxied.reset() + async def commit(self) -> None: r"""Commit the current transaction in progress. @@ -483,6 +461,11 @@ class async_scoped_session(Generic[_AS]): Proxied for the :class:`_asyncio.AsyncSession` class on behalf of the :class:`_asyncio.scoping.async_scoped_session` class. + .. seealso:: + + :meth:`_orm.Session.commit` - main documentation for + "commit" + """ # noqa: E501 return await self._proxied.commit() @@ -1014,6 +997,11 @@ class async_scoped_session(Generic[_AS]): Proxied for the :class:`_asyncio.AsyncSession` class on behalf of the :class:`_asyncio.scoping.async_scoped_session` class. + .. seealso:: + + :meth:`_orm.Session.rollback` - main documentation for + "rollback" + """ # noqa: E501 return await self._proxied.rollback() @@ -1137,6 +1125,85 @@ class async_scoped_session(Generic[_AS]): **kw, ) + async def get( + self, + entity: _EntityBindKey[_O], + ident: _PKIdentityArgument, + *, + options: Optional[Sequence[ORMOption]] = None, + populate_existing: bool = False, + with_for_update: ForUpdateParameter = None, + identity_token: Optional[Any] = None, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, + ) -> Union[_O, None]: + r"""Return an instance based on the given primary key identifier, + or ``None`` if not found. + + .. container:: class_bases + + Proxied for the :class:`_asyncio.AsyncSession` class on + behalf of the :class:`_asyncio.scoping.async_scoped_session` class. + + .. seealso:: + + :meth:`_orm.Session.get` - main documentation for get + + + + """ # noqa: E501 + + result = await self._proxied.get( + entity, + ident, + options=options, + populate_existing=populate_existing, + with_for_update=with_for_update, + identity_token=identity_token, + execution_options=execution_options, + ) + return result + + async def get_one( + self, + entity: _EntityBindKey[_O], + ident: _PKIdentityArgument, + *, + options: Optional[Sequence[ORMOption]] = None, + populate_existing: bool = False, + with_for_update: ForUpdateParameter = None, + identity_token: Optional[Any] = None, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, + ) -> _O: + r"""Return an instance based on the given primary key identifier, + or raise an exception if not found. + + .. container:: class_bases + + Proxied for the :class:`_asyncio.AsyncSession` class on + behalf of the :class:`_asyncio.scoping.async_scoped_session` class. + + Raises ``sqlalchemy.orm.exc.NoResultFound`` if the query selects + no rows. + + ..versionadded: 2.0.22 + + .. seealso:: + + :meth:`_orm.Session.get_one` - main documentation for get_one + + + """ # noqa: E501 + + return await self._proxied.get_one( + entity, + ident, + options=options, + populate_existing=populate_existing, + with_for_update=with_for_update, + identity_token=identity_token, + execution_options=execution_options, + ) + @overload async def stream( self, @@ -1483,7 +1550,7 @@ class async_scoped_session(Generic[_AS]): return self._proxied.info @classmethod - async def close_all(self) -> None: + async def close_all(cls) -> None: r"""Close all :class:`_asyncio.AsyncSession` sessions. .. container:: class_bases @@ -1491,6 +1558,8 @@ class async_scoped_session(Generic[_AS]): Proxied for the :class:`_asyncio.AsyncSession` class on behalf of the :class:`_asyncio.scoping.async_scoped_session` class. + .. deprecated:: 2.0 The :meth:`.AsyncSession.close_all` method is deprecated and will be removed in a future release. Please refer to :func:`_asyncio.close_all_sessions`. + """ # noqa: E501 return await AsyncSession.close_all() diff --git a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/session.py b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/session.py index da69c4f..30232e5 100644 --- a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/session.py +++ b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/session.py @@ -32,6 +32,7 @@ from .result import _ensure_sync_result from .result import AsyncResult from .result import AsyncScalarResult from ... import util +from ...orm import close_all_sessions as _sync_close_all_sessions from ...orm import object_session from ...orm import Session from ...orm import SessionTransaction @@ -509,7 +510,7 @@ class AsyncSession(ReversibleProxy[Session]): else: execution_options = _EXECUTE_OPTIONS - result = await greenlet_spawn( + return await greenlet_spawn( self.sync_session.scalar, statement, params=params, @@ -517,7 +518,6 @@ class AsyncSession(ReversibleProxy[Session]): bind_arguments=bind_arguments, **kw, ) - return result @overload async def scalars( @@ -588,7 +588,7 @@ class AsyncSession(ReversibleProxy[Session]): with_for_update: ForUpdateParameter = None, identity_token: Optional[Any] = None, execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, - ) -> Optional[_O]: + ) -> Union[_O, None]: """Return an instance based on the given primary key identifier, or ``None`` if not found. @@ -599,9 +599,7 @@ class AsyncSession(ReversibleProxy[Session]): """ - # result_obj = self.sync_session.get(entity, ident) - - result_obj = await greenlet_spawn( + return await greenlet_spawn( cast("Callable[..., _O]", self.sync_session.get), entity, ident, @@ -609,8 +607,44 @@ class AsyncSession(ReversibleProxy[Session]): populate_existing=populate_existing, with_for_update=with_for_update, identity_token=identity_token, + execution_options=execution_options, + ) + + async def get_one( + self, + entity: _EntityBindKey[_O], + ident: _PKIdentityArgument, + *, + options: Optional[Sequence[ORMOption]] = None, + populate_existing: bool = False, + with_for_update: ForUpdateParameter = None, + identity_token: Optional[Any] = None, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, + ) -> _O: + """Return an instance based on the given primary key identifier, + or raise an exception if not found. + + Raises ``sqlalchemy.orm.exc.NoResultFound`` if the query selects + no rows. + + ..versionadded: 2.0.22 + + .. seealso:: + + :meth:`_orm.Session.get_one` - main documentation for get_one + + """ + + return await greenlet_spawn( + cast("Callable[..., _O]", self.sync_session.get_one), + entity, + ident, + options=options, + populate_existing=populate_existing, + with_for_update=with_for_update, + identity_token=identity_token, + execution_options=execution_options, ) - return result_obj @overload async def stream( @@ -946,48 +980,70 @@ class AsyncSession(ReversibleProxy[Session]): For a general description of ORM begin nested, see :meth:`_orm.Session.begin_nested`. + .. seealso:: + + :ref:`aiosqlite_serializable` - special workarounds required + with the SQLite asyncio driver in order for SAVEPOINT to work + correctly. + """ return AsyncSessionTransaction(self, nested=True) async def rollback(self) -> None: - """Rollback the current transaction in progress.""" + """Rollback the current transaction in progress. + + .. seealso:: + + :meth:`_orm.Session.rollback` - main documentation for + "rollback" + """ await greenlet_spawn(self.sync_session.rollback) async def commit(self) -> None: - """Commit the current transaction in progress.""" + """Commit the current transaction in progress. + + .. seealso:: + + :meth:`_orm.Session.commit` - main documentation for + "commit" + """ await greenlet_spawn(self.sync_session.commit) async def close(self) -> None: """Close out the transactional resources and ORM objects used by this :class:`_asyncio.AsyncSession`. - This expunges all ORM objects associated with this - :class:`_asyncio.AsyncSession`, ends any transaction in progress and - :term:`releases` any :class:`_asyncio.AsyncConnection` objects which - this :class:`_asyncio.AsyncSession` itself has checked out from - associated :class:`_asyncio.AsyncEngine` objects. The operation then - leaves the :class:`_asyncio.AsyncSession` in a state which it may be - used again. - - .. tip:: - - The :meth:`_asyncio.AsyncSession.close` method **does not prevent - the Session from being used again**. The - :class:`_asyncio.AsyncSession` itself does not actually have a - distinct "closed" state; it merely means the - :class:`_asyncio.AsyncSession` will release all database - connections and ORM objects. - - .. seealso:: + :meth:`_orm.Session.close` - main documentation for + "close" + :ref:`session_closing` - detail on the semantics of - :meth:`_asyncio.AsyncSession.close` + :meth:`_asyncio.AsyncSession.close` and + :meth:`_asyncio.AsyncSession.reset`. """ await greenlet_spawn(self.sync_session.close) + async def reset(self) -> None: + """Close out the transactional resources and ORM objects used by this + :class:`_orm.Session`, resetting the session to its initial state. + + .. versionadded:: 2.0.22 + + .. seealso:: + + :meth:`_orm.Session.reset` - main documentation for + "reset" + + :ref:`session_closing` - detail on the semantics of + :meth:`_asyncio.AsyncSession.close` and + :meth:`_asyncio.AsyncSession.reset`. + + """ + await greenlet_spawn(self.sync_session.reset) + async def aclose(self) -> None: """A synonym for :meth:`_asyncio.AsyncSession.close`. @@ -1008,9 +1064,15 @@ class AsyncSession(ReversibleProxy[Session]): await greenlet_spawn(self.sync_session.invalidate) @classmethod - async def close_all(self) -> None: + @util.deprecated( + "2.0", + "The :meth:`.AsyncSession.close_all` method is deprecated and will be " + "removed in a future release. Please refer to " + ":func:`_asyncio.close_all_sessions`.", + ) + async def close_all(cls) -> None: """Close all :class:`_asyncio.AsyncSession` sessions.""" - await greenlet_spawn(self.sync_session.close_all) + await close_all_sessions() async def __aenter__(self: _AS) -> _AS: return self @@ -1862,4 +1924,17 @@ def async_session(session: Session) -> Optional[AsyncSession]: return AsyncSession._retrieve_proxy_for_target(session, regenerate=False) +async def close_all_sessions() -> None: + """Close all :class:`_asyncio.AsyncSession` sessions. + + .. versionadded:: 2.0.23 + + .. seealso:: + + :func:`.session.close_all_sessions` + + """ + await greenlet_spawn(_sync_close_all_sessions) + + _instance_state._async_provider = async_session # type: ignore diff --git a/venv/Lib/site-packages/sqlalchemy/ext/declarative/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/declarative/__pycache__/__init__.cpython-310.pyc index a3c7956..a8c603e 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/declarative/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/declarative/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/declarative/__pycache__/extensions.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/declarative/__pycache__/extensions.cpython-310.pyc index e008f2d..65ef13a 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/declarative/__pycache__/extensions.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/declarative/__pycache__/extensions.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/hybrid.py b/venv/Lib/site-packages/sqlalchemy/ext/hybrid.py index 83dfb50..615f166 100644 --- a/venv/Lib/site-packages/sqlalchemy/ext/hybrid.py +++ b/venv/Lib/site-packages/sqlalchemy/ext/hybrid.py @@ -200,7 +200,7 @@ Using ``inplace`` to create pep-484 compliant hybrid properties In the previous section, a :class:`.hybrid_property` decorator is illustrated which includes two separate method-level functions being decorated, both -to produce a single object attribute referred towards as ``Interval.radius``. +to produce a single object attribute referenced as ``Interval.radius``. There are actually several different modifiers we can use for :class:`.hybrid_property` including :meth:`.hybrid_property.expression`, :meth:`.hybrid_property.setter` and :meth:`.hybrid_property.update_expression`. @@ -927,10 +927,10 @@ class _HybridDeleterType(Protocol[_T_co]): ... -class _HybridExprCallableType(Protocol[_T]): +class _HybridExprCallableType(Protocol[_T_co]): def __call__( s, cls: Any - ) -> Union[_HasClauseElement, SQLColumnExpression[_T]]: + ) -> Union[_HasClauseElement, SQLColumnExpression[_T_co]]: ... @@ -1516,7 +1516,7 @@ class ExprComparator(Comparator[_T]): def operate( self, op: OperatorType, *other: Any, **kwargs: Any ) -> ColumnElement[Any]: - return op(self.expression, *other, **kwargs) # type: ignore + return op(self.expression, *other, **kwargs) def reverse_operate( self, op: OperatorType, other: Any, **kwargs: Any diff --git a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/__init__.cpython-310.pyc index 4c6d316..d503929 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/apply.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/apply.cpython-310.pyc index 12afdbb..fd77fbe 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/apply.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/apply.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/decl_class.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/decl_class.cpython-310.pyc index 509b594..2ed1f86 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/decl_class.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/decl_class.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/infer.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/infer.cpython-310.pyc index 1935208..cf55f5f 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/infer.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/infer.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/names.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/names.cpython-310.pyc index 65b8a52..30ce0e3 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/names.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/names.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/plugin.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/plugin.cpython-310.pyc index dfba6a4..0406da6 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/plugin.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/plugin.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/util.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/util.cpython-310.pyc index 8c0cff5..6446432 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/util.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/util.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/mypy/names.py b/venv/Lib/site-packages/sqlalchemy/ext/mypy/names.py index 989f255..ae55ca4 100644 --- a/venv/Lib/site-packages/sqlalchemy/ext/mypy/names.py +++ b/venv/Lib/site-packages/sqlalchemy/ext/mypy/names.py @@ -34,24 +34,23 @@ from mypy.types import UnboundType from ... import util -COLUMN: int = util.symbol("COLUMN") # type: ignore -RELATIONSHIP: int = util.symbol("RELATIONSHIP") # type: ignore -REGISTRY: int = util.symbol("REGISTRY") # type: ignore -COLUMN_PROPERTY: int = util.symbol("COLUMN_PROPERTY") # type: ignore -TYPEENGINE: int = util.symbol("TYPEENGNE") # type: ignore -MAPPED: int = util.symbol("MAPPED") # type: ignore -DECLARATIVE_BASE: int = util.symbol("DECLARATIVE_BASE") # type: ignore -DECLARATIVE_META: int = util.symbol("DECLARATIVE_META") # type: ignore -MAPPED_DECORATOR: int = util.symbol("MAPPED_DECORATOR") # type: ignore -COLUMN_PROPERTY: int = util.symbol("COLUMN_PROPERTY") # type: ignore -SYNONYM_PROPERTY: int = util.symbol("SYNONYM_PROPERTY") # type: ignore -COMPOSITE_PROPERTY: int = util.symbol("COMPOSITE_PROPERTY") # type: ignore -DECLARED_ATTR: int = util.symbol("DECLARED_ATTR") # type: ignore -MAPPER_PROPERTY: int = util.symbol("MAPPER_PROPERTY") # type: ignore -AS_DECLARATIVE: int = util.symbol("AS_DECLARATIVE") # type: ignore -AS_DECLARATIVE_BASE: int = util.symbol("AS_DECLARATIVE_BASE") # type: ignore -DECLARATIVE_MIXIN: int = util.symbol("DECLARATIVE_MIXIN") # type: ignore -QUERY_EXPRESSION: int = util.symbol("QUERY_EXPRESSION") # type: ignore +COLUMN: int = util.symbol("COLUMN") +RELATIONSHIP: int = util.symbol("RELATIONSHIP") +REGISTRY: int = util.symbol("REGISTRY") +COLUMN_PROPERTY: int = util.symbol("COLUMN_PROPERTY") +TYPEENGINE: int = util.symbol("TYPEENGNE") +MAPPED: int = util.symbol("MAPPED") +DECLARATIVE_BASE: int = util.symbol("DECLARATIVE_BASE") +DECLARATIVE_META: int = util.symbol("DECLARATIVE_META") +MAPPED_DECORATOR: int = util.symbol("MAPPED_DECORATOR") +SYNONYM_PROPERTY: int = util.symbol("SYNONYM_PROPERTY") +COMPOSITE_PROPERTY: int = util.symbol("COMPOSITE_PROPERTY") +DECLARED_ATTR: int = util.symbol("DECLARED_ATTR") +MAPPER_PROPERTY: int = util.symbol("MAPPER_PROPERTY") +AS_DECLARATIVE: int = util.symbol("AS_DECLARATIVE") +AS_DECLARATIVE_BASE: int = util.symbol("AS_DECLARATIVE_BASE") +DECLARATIVE_MIXIN: int = util.symbol("DECLARATIVE_MIXIN") +QUERY_EXPRESSION: int = util.symbol("QUERY_EXPRESSION") # names that must succeed with mypy.api.named_type NAMED_TYPE_BUILTINS_OBJECT = "builtins.object" diff --git a/venv/Lib/site-packages/sqlalchemy/ext/mypy/util.py b/venv/Lib/site-packages/sqlalchemy/ext/mypy/util.py index fe44021..238c82a 100644 --- a/venv/Lib/site-packages/sqlalchemy/ext/mypy/util.py +++ b/venv/Lib/site-packages/sqlalchemy/ext/mypy/util.py @@ -173,7 +173,7 @@ def get_mapped_attributes( def format_type(typ_: Type, options: Options) -> str: if mypy_14: - return _mypy_format_type(typ_, options) # type: ignore + return _mypy_format_type(typ_, options) else: return _mypy_format_type(typ_) # type: ignore diff --git a/venv/Lib/site-packages/sqlalchemy/future/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/future/__pycache__/__init__.cpython-310.pyc index da40b1d..6545e80 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/future/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/future/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/future/__pycache__/engine.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/future/__pycache__/engine.cpython-310.pyc index 1b43fd1..8a3198f 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/future/__pycache__/engine.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/future/__pycache__/engine.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/log.py b/venv/Lib/site-packages/sqlalchemy/log.py index f1e2cf1..8de6d18 100644 --- a/venv/Lib/site-packages/sqlalchemy/log.py +++ b/venv/Lib/site-packages/sqlalchemy/log.py @@ -75,10 +75,10 @@ def _qual_logger_name_for_cls(cls: Type[Identified]) -> str: def class_logger(cls: Type[_IT]) -> Type[_IT]: logger = logging.getLogger(_qual_logger_name_for_cls(cls)) - cls._should_log_debug = lambda self: logger.isEnabledFor( # type: ignore[assignment] # noqa: E501 + cls._should_log_debug = lambda self: logger.isEnabledFor( # type: ignore[method-assign] # noqa: E501 logging.DEBUG ) - cls._should_log_info = lambda self: logger.isEnabledFor( # type: ignore[assignment] # noqa: E501 + cls._should_log_info = lambda self: logger.isEnabledFor( # type: ignore[method-assign] # noqa: E501 logging.INFO ) cls.logger = logger diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/__init__.cpython-310.pyc index a57e531..383dc93 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/_orm_constructors.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/_orm_constructors.cpython-310.pyc index 7efd205..9f8af79 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/_orm_constructors.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/_orm_constructors.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/_typing.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/_typing.cpython-310.pyc index 0c992ca..012d4ed 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/_typing.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/_typing.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/attributes.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/attributes.cpython-310.pyc index d3b143d..a2b1e5c 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/attributes.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/attributes.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/base.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/base.cpython-310.pyc index 63a2b34..b914728 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/base.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/base.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/bulk_persistence.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/bulk_persistence.cpython-310.pyc index a6cf3e0..41827d6 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/bulk_persistence.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/bulk_persistence.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/clsregistry.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/clsregistry.cpython-310.pyc index 36b7a7f..c9e6437 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/clsregistry.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/clsregistry.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/collections.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/collections.cpython-310.pyc index f0039ee..e3defd5 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/collections.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/collections.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/context.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/context.cpython-310.pyc index c5c42b2..bb31f3c 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/context.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/context.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/decl_api.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/decl_api.cpython-310.pyc index 2f79cb3..bb7cbf4 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/decl_api.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/decl_api.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/decl_base.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/decl_base.cpython-310.pyc index 7607991..faee449 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/decl_base.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/decl_base.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/dependency.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/dependency.cpython-310.pyc index e2225bd..683b696 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/dependency.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/dependency.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/descriptor_props.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/descriptor_props.cpython-310.pyc index 94ad69f..653b376 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/descriptor_props.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/descriptor_props.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/dynamic.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/dynamic.cpython-310.pyc index aab7679..0eab6c7 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/dynamic.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/dynamic.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/evaluator.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/evaluator.cpython-310.pyc index cf1ff4d..72bef35 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/evaluator.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/evaluator.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/events.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/events.cpython-310.pyc index ee5f9fc..5dbf46e 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/events.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/events.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/exc.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/exc.cpython-310.pyc index 85ba037..c778683 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/exc.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/exc.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/identity.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/identity.cpython-310.pyc index 013773d..90d7b74 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/identity.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/identity.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/instrumentation.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/instrumentation.cpython-310.pyc index 7badac4..90bc833 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/instrumentation.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/instrumentation.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/interfaces.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/interfaces.cpython-310.pyc index c0c8d05..78f31f6 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/interfaces.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/interfaces.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/loading.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/loading.cpython-310.pyc index 8891c25..7f71e06 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/loading.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/loading.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/mapped_collection.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/mapped_collection.cpython-310.pyc index 53395af..46a36cb 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/mapped_collection.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/mapped_collection.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/mapper.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/mapper.cpython-310.pyc index 0aa3a62..1249707 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/mapper.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/mapper.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/path_registry.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/path_registry.cpython-310.pyc index 4374836..18dcdb8 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/path_registry.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/path_registry.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/persistence.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/persistence.cpython-310.pyc index 2818a4b..7e7705c 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/persistence.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/persistence.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/properties.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/properties.cpython-310.pyc index 8e2fc6c..f1d942d 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/properties.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/properties.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/query.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/query.cpython-310.pyc index 798ab45..8b505ea 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/query.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/query.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/relationships.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/relationships.cpython-310.pyc index baf80b3..98f39bb 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/relationships.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/relationships.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/scoping.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/scoping.cpython-310.pyc index 68a78c3..493d18e 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/scoping.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/scoping.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/session.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/session.cpython-310.pyc index 92d797a..d806015 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/session.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/session.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/state.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/state.cpython-310.pyc index 2c01ea8..33eaafc 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/state.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/state.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/state_changes.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/state_changes.cpython-310.pyc index efe2a98..860cd7f 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/state_changes.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/state_changes.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/strategies.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/strategies.cpython-310.pyc index 4747aa7..72d395b 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/strategies.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/strategies.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/strategy_options.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/strategy_options.cpython-310.pyc index 98c68c0..d9abb94 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/strategy_options.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/strategy_options.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/sync.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/sync.cpython-310.pyc index 42d4023..ec41aa0 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/sync.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/sync.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/unitofwork.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/unitofwork.cpython-310.pyc index f954f84..16df85d 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/unitofwork.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/unitofwork.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/util.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/util.cpython-310.pyc index 27ed4f3..5e17461 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/util.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/util.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/writeonly.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/writeonly.cpython-310.pyc index 9568fa7..885d3d0 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/writeonly.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/writeonly.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/_orm_constructors.py b/venv/Lib/site-packages/sqlalchemy/orm/_orm_constructors.py index 9e41874..df36c38 100644 --- a/venv/Lib/site-packages/sqlalchemy/orm/_orm_constructors.py +++ b/venv/Lib/site-packages/sqlalchemy/orm/_orm_constructors.py @@ -114,7 +114,7 @@ def mapped_column( primary_key: Optional[bool] = False, deferred: Union[_NoArg, bool] = _NoArg.NO_ARG, deferred_group: Optional[str] = None, - deferred_raiseload: bool = False, + deferred_raiseload: Optional[bool] = None, use_existing_column: bool = False, name: Optional[str] = None, type_: Optional[_TypeEngineArgument[Any]] = None, @@ -132,7 +132,7 @@ def mapped_column( quote: Optional[bool] = None, system: bool = False, comment: Optional[str] = None, - sort_order: int = 0, + sort_order: Union[_NoArg, int] = _NoArg.NO_ARG, **kw: Any, ) -> MappedColumn[Any]: r"""declare a new ORM-mapped :class:`_schema.Column` construct diff --git a/venv/Lib/site-packages/sqlalchemy/orm/_typing.py b/venv/Lib/site-packages/sqlalchemy/orm/_typing.py index cc4233b..3085351 100644 --- a/venv/Lib/site-packages/sqlalchemy/orm/_typing.py +++ b/venv/Lib/site-packages/sqlalchemy/orm/_typing.py @@ -93,6 +93,7 @@ class _OrmKnownExecutionOptions(_CoreKnownExecutionOptions, total=False): dml_strategy: DMLStrategyArgument is_delete_using: bool is_update_from: bool + render_nulls: bool OrmExecuteOptionsParameter = Union[ @@ -119,7 +120,7 @@ class _LoaderCallable(Protocol): def is_orm_option( opt: ExecutableOption, ) -> TypeGuard[ORMOption]: - return not opt._is_core # type: ignore + return not opt._is_core def is_user_defined_option( diff --git a/venv/Lib/site-packages/sqlalchemy/orm/attributes.py b/venv/Lib/site-packages/sqlalchemy/orm/attributes.py index 6a9766c..1098359 100644 --- a/venv/Lib/site-packages/sqlalchemy/orm/attributes.py +++ b/venv/Lib/site-packages/sqlalchemy/orm/attributes.py @@ -120,6 +120,7 @@ if TYPE_CHECKING: _T = TypeVar("_T") +_T_co = TypeVar("_T_co", bound=Any, covariant=True) _AllPendingType = Sequence[ @@ -132,10 +133,10 @@ _UNKNOWN_ATTR_KEY = object() @inspection._self_inspects class QueryableAttribute( - _DeclarativeMapped[_T], - SQLORMExpression[_T], + _DeclarativeMapped[_T_co], + SQLORMExpression[_T_co], interfaces.InspectionAttr, - interfaces.PropComparator[_T], + interfaces.PropComparator[_T_co], roles.JoinTargetRole, roles.OnClauseRole, sql_base.Immutable, @@ -178,13 +179,13 @@ class QueryableAttribute( is_attribute = True - dispatch: dispatcher[QueryableAttribute[_T]] + dispatch: dispatcher[QueryableAttribute[_T_co]] class_: _ExternalEntityType[Any] key: str parententity: _InternalEntityType[Any] impl: AttributeImpl - comparator: interfaces.PropComparator[_T] + comparator: interfaces.PropComparator[_T_co] _of_type: Optional[_InternalEntityType[Any]] _extra_criteria: Tuple[ColumnElement[bool], ...] _doc: Optional[str] @@ -198,7 +199,7 @@ class QueryableAttribute( class_: _ExternalEntityType[_O], key: str, parententity: _InternalEntityType[_O], - comparator: interfaces.PropComparator[_T], + comparator: interfaces.PropComparator[_T_co], impl: Optional[AttributeImpl] = None, of_type: Optional[_InternalEntityType[Any]] = None, extra_criteria: Tuple[ColumnElement[bool], ...] = (), @@ -314,7 +315,7 @@ class QueryableAttribute( """ - expression: ColumnElement[_T] + expression: ColumnElement[_T_co] """The SQL expression object represented by this :class:`.QueryableAttribute`. @@ -334,7 +335,7 @@ class QueryableAttribute( entity_namespace = self._entity_namespace assert isinstance(entity_namespace, HasCacheKey) - if self.key is _UNKNOWN_ATTR_KEY: # type: ignore[comparison-overlap] + if self.key is _UNKNOWN_ATTR_KEY: annotations = {"entity_namespace": entity_namespace} else: annotations = { @@ -376,7 +377,7 @@ class QueryableAttribute( def _annotations(self) -> _AnnotationDict: return self.__clause_element__()._annotations - def __clause_element__(self) -> ColumnElement[_T]: + def __clause_element__(self) -> ColumnElement[_T_co]: return self.expression @property @@ -443,18 +444,18 @@ class QueryableAttribute( extra_criteria=self._extra_criteria, ) - def label(self, name: Optional[str]) -> Label[_T]: + def label(self, name: Optional[str]) -> Label[_T_co]: return self.__clause_element__().label(name) def operate( self, op: OperatorType, *other: Any, **kwargs: Any ) -> ColumnElement[Any]: - return op(self.comparator, *other, **kwargs) # type: ignore[return-value,no-any-return] # noqa: E501 + return op(self.comparator, *other, **kwargs) # type: ignore[no-any-return] # noqa: E501 def reverse_operate( self, op: OperatorType, other: Any, **kwargs: Any ) -> ColumnElement[Any]: - return op(other, self.comparator, **kwargs) # type: ignore[return-value,no-any-return] # noqa: E501 + return op(other, self.comparator, **kwargs) # type: ignore[no-any-return] # noqa: E501 def hasparent( self, state: InstanceState[Any], optimistic: bool = False @@ -520,16 +521,16 @@ class InstrumentedAttribute(QueryableAttribute[_T]): # InstrumentedAttribute, while still keeping classlevel # __doc__ correct - @util.rw_hybridproperty # type: ignore - def __doc__(self) -> Optional[str]: # type: ignore + @util.rw_hybridproperty + def __doc__(self) -> Optional[str]: return self._doc @__doc__.setter # type: ignore - def __doc__(self, value: Optional[str]) -> None: # type: ignore + def __doc__(self, value: Optional[str]) -> None: self._doc = value @__doc__.classlevel # type: ignore - def __doc__(cls) -> Optional[str]: # type: ignore + def __doc__(cls) -> Optional[str]: return super().__doc__ def __set__(self, instance: object, value: Any) -> None: @@ -790,7 +791,7 @@ class AttributeEventToken: __slots__ = "impl", "op", "parent_token" - def __init__(self, attribute_impl, op): + def __init__(self, attribute_impl: AttributeImpl, op: util.symbol): self.impl = attribute_impl self.op = op self.parent_token = self.impl.parent_token @@ -833,7 +834,7 @@ class AttributeImpl: self, class_: _ExternalEntityType[_O], key: str, - callable_: _LoaderCallable, + callable_: Optional[_LoaderCallable], dispatch: _Dispatch[QueryableAttribute[Any]], trackparent: bool = False, compare_function: Optional[Callable[..., bool]] = None, @@ -1940,7 +1941,7 @@ class CollectionAttributeImpl(HasCollectionAdapter, AttributeImpl): and "None" or iterable.__class__.__name__ ) - wanted = self._duck_typed_as.__name__ # type: ignore + wanted = self._duck_typed_as.__name__ raise TypeError( "Incompatible collection type: %s is not %s-like" % (given, wanted) @@ -2617,7 +2618,7 @@ def register_attribute_impl( # TODO: this appears to be the WriteOnlyAttributeImpl / # DynamicAttributeImpl constructor which is hardcoded impl = cast("Type[WriteOnlyAttributeImpl]", impl_class)( - class_, key, typecallable, dispatch, **kw + class_, key, dispatch, **kw ) elif uselist: impl = CollectionAttributeImpl( diff --git a/venv/Lib/site-packages/sqlalchemy/orm/base.py b/venv/Lib/site-packages/sqlalchemy/orm/base.py index ecb1059..362346c 100644 --- a/venv/Lib/site-packages/sqlalchemy/orm/base.py +++ b/venv/Lib/site-packages/sqlalchemy/orm/base.py @@ -56,6 +56,7 @@ if typing.TYPE_CHECKING: from ..sql.operators import OperatorType _T = TypeVar("_T", bound=Any) +_T_co = TypeVar("_T_co", bound=Any, covariant=True) _O = TypeVar("_O", bound=object) @@ -678,12 +679,12 @@ class InspectionAttrInfo(InspectionAttr): return {} -class SQLORMOperations(SQLCoreOperations[_T], TypingOnly): +class SQLORMOperations(SQLCoreOperations[_T_co], TypingOnly): __slots__ = () if typing.TYPE_CHECKING: - def of_type(self, class_: _EntityType[Any]) -> PropComparator[_T]: + def of_type(self, class_: _EntityType[Any]) -> PropComparator[_T_co]: ... def and_( @@ -706,7 +707,7 @@ class SQLORMOperations(SQLCoreOperations[_T], TypingOnly): ... -class ORMDescriptor(Generic[_T], TypingOnly): +class ORMDescriptor(Generic[_T_co], TypingOnly): """Represent any Python descriptor that provides a SQL expression construct at the class level.""" @@ -717,26 +718,26 @@ class ORMDescriptor(Generic[_T], TypingOnly): @overload def __get__( self, instance: Any, owner: Literal[None] - ) -> ORMDescriptor[_T]: + ) -> ORMDescriptor[_T_co]: ... @overload def __get__( self, instance: Literal[None], owner: Any - ) -> SQLCoreOperations[_T]: + ) -> SQLCoreOperations[_T_co]: ... @overload - def __get__(self, instance: object, owner: Any) -> _T: + def __get__(self, instance: object, owner: Any) -> _T_co: ... def __get__( self, instance: object, owner: Any - ) -> Union[ORMDescriptor[_T], SQLCoreOperations[_T], _T]: + ) -> Union[ORMDescriptor[_T_co], SQLCoreOperations[_T_co], _T_co]: ... -class _MappedAnnotationBase(Generic[_T], TypingOnly): +class _MappedAnnotationBase(Generic[_T_co], TypingOnly): """common class for Mapped and similar ORM container classes. these are classes that can appear on the left side of an ORM declarative @@ -749,7 +750,7 @@ class _MappedAnnotationBase(Generic[_T], TypingOnly): class SQLORMExpression( - SQLORMOperations[_T], SQLColumnExpression[_T], TypingOnly + SQLORMOperations[_T_co], SQLColumnExpression[_T_co], TypingOnly ): """A type that may be used to indicate any ORM-level attribute or object that acts in place of one, in the context of SQL expression @@ -771,9 +772,9 @@ class SQLORMExpression( class Mapped( - SQLORMExpression[_T], - ORMDescriptor[_T], - _MappedAnnotationBase[_T], + SQLORMExpression[_T_co], + ORMDescriptor[_T_co], + _MappedAnnotationBase[_T_co], roles.DDLConstraintColumnRole, ): """Represent an ORM mapped attribute on a mapped class. @@ -819,24 +820,24 @@ class Mapped( @overload def __get__( self, instance: None, owner: Any - ) -> InstrumentedAttribute[_T]: + ) -> InstrumentedAttribute[_T_co]: ... @overload - def __get__(self, instance: object, owner: Any) -> _T: + def __get__(self, instance: object, owner: Any) -> _T_co: ... def __get__( self, instance: Optional[object], owner: Any - ) -> Union[InstrumentedAttribute[_T], _T]: + ) -> Union[InstrumentedAttribute[_T_co], _T_co]: ... @classmethod - def _empty_constructor(cls, arg1: Any) -> Mapped[_T]: + def _empty_constructor(cls, arg1: Any) -> Mapped[_T_co]: ... def __set__( - self, instance: Any, value: Union[SQLCoreOperations[_T], _T] + self, instance: Any, value: Union[SQLCoreOperations[_T_co], _T_co] ) -> None: ... @@ -844,7 +845,7 @@ class Mapped( ... -class _MappedAttribute(Generic[_T], TypingOnly): +class _MappedAttribute(Generic[_T_co], TypingOnly): """Mixin for attributes which should be replaced by mapper-assigned attributes. @@ -853,7 +854,7 @@ class _MappedAttribute(Generic[_T], TypingOnly): __slots__ = () -class _DeclarativeMapped(Mapped[_T], _MappedAttribute[_T]): +class _DeclarativeMapped(Mapped[_T_co], _MappedAttribute[_T_co]): """Mixin for :class:`.MapperProperty` subclasses that allows them to be compatible with ORM-annotated declarative mappings. @@ -878,7 +879,7 @@ class _DeclarativeMapped(Mapped[_T], _MappedAttribute[_T]): return NotImplemented -class DynamicMapped(_MappedAnnotationBase[_T]): +class DynamicMapped(_MappedAnnotationBase[_T_co]): """Represent the ORM mapped attribute type for a "dynamic" relationship. The :class:`_orm.DynamicMapped` type annotation may be used in an @@ -918,23 +919,27 @@ class DynamicMapped(_MappedAnnotationBase[_T]): @overload def __get__( self, instance: None, owner: Any - ) -> InstrumentedAttribute[_T]: + ) -> InstrumentedAttribute[_T_co]: ... @overload - def __get__(self, instance: object, owner: Any) -> AppenderQuery[_T]: + def __get__( + self, instance: object, owner: Any + ) -> AppenderQuery[_T_co]: ... def __get__( self, instance: Optional[object], owner: Any - ) -> Union[InstrumentedAttribute[_T], AppenderQuery[_T]]: + ) -> Union[InstrumentedAttribute[_T_co], AppenderQuery[_T_co]]: ... - def __set__(self, instance: Any, value: typing.Collection[_T]) -> None: + def __set__( + self, instance: Any, value: typing.Collection[_T_co] + ) -> None: ... -class WriteOnlyMapped(_MappedAnnotationBase[_T]): +class WriteOnlyMapped(_MappedAnnotationBase[_T_co]): """Represent the ORM mapped attribute type for a "write only" relationship. The :class:`_orm.WriteOnlyMapped` type annotation may be used in an @@ -970,19 +975,21 @@ class WriteOnlyMapped(_MappedAnnotationBase[_T]): @overload def __get__( self, instance: None, owner: Any - ) -> InstrumentedAttribute[_T]: + ) -> InstrumentedAttribute[_T_co]: ... @overload def __get__( self, instance: object, owner: Any - ) -> WriteOnlyCollection[_T]: + ) -> WriteOnlyCollection[_T_co]: ... def __get__( self, instance: Optional[object], owner: Any - ) -> Union[InstrumentedAttribute[_T], WriteOnlyCollection[_T]]: + ) -> Union[InstrumentedAttribute[_T_co], WriteOnlyCollection[_T_co]]: ... - def __set__(self, instance: Any, value: typing.Collection[_T]) -> None: + def __set__( + self, instance: Any, value: typing.Collection[_T_co] + ) -> None: ... diff --git a/venv/Lib/site-packages/sqlalchemy/orm/bulk_persistence.py b/venv/Lib/site-packages/sqlalchemy/orm/bulk_persistence.py index 6b35c4a..31caedc 100644 --- a/venv/Lib/site-packages/sqlalchemy/orm/bulk_persistence.py +++ b/venv/Lib/site-packages/sqlalchemy/orm/bulk_persistence.py @@ -1158,7 +1158,7 @@ class BulkORMInsert(ORMDMLState, InsertDMLState): execution_options, ) = BulkORMInsert.default_insert_options.from_execution_options( "_sa_orm_insert_options", - {"dml_strategy", "autoflush", "populate_existing"}, + {"dml_strategy", "autoflush", "populate_existing", "render_nulls"}, execution_options, statement._execution_options, ) @@ -1438,7 +1438,6 @@ class BulkORMUpdate(BulkUDCompileState, UpdateDMLState): self._resolved_values = dict(self._resolved_values) new_stmt = statement._clone() - new_stmt.table = mapper.local_table # note if the statement has _multi_values, these # are passed through to the new statement, which will then raise @@ -1499,9 +1498,7 @@ class BulkORMUpdate(BulkUDCompileState, UpdateDMLState): # over and over again. so perhaps if it could be RETURNING just # the elements that were based on a SQL expression and not # a constant. For now it doesn't quite seem worth it - new_stmt = new_stmt.return_defaults( - *(list(mapper.local_table.primary_key)) - ) + new_stmt = new_stmt.return_defaults(*new_stmt.table.primary_key) if toplevel: new_stmt = self._setup_orm_returning( @@ -1860,7 +1857,6 @@ class BulkORMDelete(BulkUDCompileState, DeleteDMLState): ) new_stmt = statement._clone() - new_stmt.table = mapper.local_table new_crit = cls._adjust_for_extra_criteria( self.global_attributes, mapper diff --git a/venv/Lib/site-packages/sqlalchemy/orm/decl_api.py b/venv/Lib/site-packages/sqlalchemy/orm/decl_api.py index e6b67b3..80c85f1 100644 --- a/venv/Lib/site-packages/sqlalchemy/orm/decl_api.py +++ b/venv/Lib/site-packages/sqlalchemy/orm/decl_api.py @@ -253,7 +253,7 @@ class _declared_attr_common: # which seems to help typing tools interpret the fn as a classmethod # for situations where needed if isinstance(fn, classmethod): - fn = fn.__func__ # type: ignore + fn = fn.__func__ self.fget = fn self._cascading = cascading @@ -281,11 +281,11 @@ class _declared_attr_common: "Unmanaged access of declarative attribute %s from " "non-mapped class %s" % (self.fget.__name__, cls.__name__) ) - return self.fget(cls) # type: ignore + return self.fget(cls) elif manager.is_mapped: # the class is mapped, which means we're outside of the declarative # scan setup, just run the function. - return self.fget(cls) # type: ignore + return self.fget(cls) # here, we are inside of the declarative scan. use the registry # that is tracking the values of these attributes. @@ -297,10 +297,10 @@ class _declared_attr_common: reg = declarative_scan.declared_attr_reg if self in reg: - return reg[self] # type: ignore + return reg[self] else: reg[self] = obj = self.fget(cls) - return obj # type: ignore + return obj class _declared_directive(_declared_attr_common, Generic[_T]): @@ -558,12 +558,12 @@ def _setup_declarative_base(cls: Type[Any]) -> None: reg = registry( metadata=metadata, type_annotation_map=type_annotation_map ) - cls.registry = reg # type: ignore + cls.registry = reg - cls._sa_registry = reg # type: ignore + cls._sa_registry = reg if "metadata" not in cls.__dict__: - cls.metadata = cls.registry.metadata # type: ignore + cls.metadata = cls.registry.metadata if getattr(cls, "__init__", object.__init__) is object.__init__: cls.__init__ = cls.registry.constructor @@ -609,7 +609,7 @@ class MappedAsDataclass(metaclass=DCTransformDeclarative): current_transforms: _DataclassArguments if hasattr(cls, "_sa_apply_dc_transforms"): - current = cls._sa_apply_dc_transforms # type: ignore[attr-defined] + current = cls._sa_apply_dc_transforms _ClassScanMapperConfig._assert_dc_arguments(current) @@ -1274,7 +1274,7 @@ class registry: sql_type = sqltypes._type_map_get(pt) # type: ignore # noqa: E501 if sql_type is not None: - sql_type_inst = sqltypes.to_instance(sql_type) # type: ignore + sql_type_inst = sqltypes.to_instance(sql_type) # ... this additional step will reject most # type -> supertype matches, such as if we had @@ -1556,7 +1556,7 @@ class registry: if hasattr(cls, "__class_getitem__"): - def __class_getitem__(cls: Type[_T], key: str) -> Type[_T]: + def __class_getitem__(cls: Type[_T], key: Any) -> Type[_T]: # allow generic classes in py3.9+ return cls diff --git a/venv/Lib/site-packages/sqlalchemy/orm/decl_base.py b/venv/Lib/site-packages/sqlalchemy/orm/decl_base.py index 816c7a8..d5ef3db 100644 --- a/venv/Lib/site-packages/sqlalchemy/orm/decl_base.py +++ b/venv/Lib/site-packages/sqlalchemy/orm/decl_base.py @@ -1434,9 +1434,9 @@ class _ClassScanMapperConfig(_MapperConfig): cls, "_sa_decl_prepare_nocascade", strict=True ) + allow_unmapped_annotations = self.allow_unmapped_annotations expect_annotations_wo_mapped = ( - self.allow_unmapped_annotations - or self.is_dataclass_prior_to_mapping + allow_unmapped_annotations or self.is_dataclass_prior_to_mapping ) look_for_dataclass_things = bool(self.dataclass_setup_arguments) @@ -1531,7 +1531,15 @@ class _ClassScanMapperConfig(_MapperConfig): # Mapped[] etc. were not used. If annotation is None, # do declarative_scan so that the property can raise # for required - if mapped_container is not None or annotation is None: + if ( + mapped_container is not None + or annotation is None + # issue #10516: need to do declarative_scan even with + # a non-Mapped annotation if we are doing + # __allow_unmapped__, for things like col.name + # assignment + or allow_unmapped_annotations + ): try: value.declarative_scan( self, @@ -1609,7 +1617,7 @@ class _ClassScanMapperConfig(_MapperConfig): setattr(cls, k, value) continue - our_stuff[k] = value # type: ignore + our_stuff[k] = value def _extract_declared_columns(self) -> None: our_stuff = self.properties @@ -1979,7 +1987,7 @@ class _DeferredMapperConfig(_ClassScanMapperConfig): # mypy disallows plain property override of variable @property # type: ignore - def cls(self) -> Type[Any]: # type: ignore + def cls(self) -> Type[Any]: return self._cls() # type: ignore @cls.setter @@ -1999,7 +2007,7 @@ class _DeferredMapperConfig(_ClassScanMapperConfig): @classmethod def raise_unmapped_for_cls(cls, class_: Type[Any]) -> NoReturn: if hasattr(class_, "_sa_raise_deferred_config"): - class_._sa_raise_deferred_config() # type: ignore + class_._sa_raise_deferred_config() raise orm_exc.UnmappedClassError( class_, diff --git a/venv/Lib/site-packages/sqlalchemy/orm/descriptor_props.py b/venv/Lib/site-packages/sqlalchemy/orm/descriptor_props.py index e7c9de2..c1fe9de 100644 --- a/venv/Lib/site-packages/sqlalchemy/orm/descriptor_props.py +++ b/venv/Lib/site-packages/sqlalchemy/orm/descriptor_props.py @@ -425,7 +425,7 @@ class CompositeProperty( elif hasattr(self.composite_class, "__composite_values__"): _composite_getters[ self.composite_class - ] = lambda obj: obj.__composite_values__() # type: ignore + ] = lambda obj: obj.__composite_values__() @util.preload_module("sqlalchemy.orm.properties") @util.preload_module("sqlalchemy.orm.decl_base") @@ -628,7 +628,7 @@ class CompositeProperty( proxy_attr = self.parent.class_manager[self.key] proxy_attr.impl.dispatch = proxy_attr.dispatch # type: ignore - proxy_attr.impl.dispatch._active_history = self.active_history # type: ignore # noqa: E501 + proxy_attr.impl.dispatch._active_history = self.active_history # TODO: need a deserialize hook here @@ -806,16 +806,16 @@ class CompositeProperty( def __ne__(self, other: Any) -> ColumnElement[bool]: # type: ignore[override] # noqa: E501 return self._compare(operators.ne, other) - def __lt__(self, other: Any) -> ColumnElement[bool]: # type: ignore[override] # noqa: E501 + def __lt__(self, other: Any) -> ColumnElement[bool]: return self._compare(operators.lt, other) - def __gt__(self, other: Any) -> ColumnElement[bool]: # type: ignore[override] # noqa: E501 + def __gt__(self, other: Any) -> ColumnElement[bool]: return self._compare(operators.gt, other) - def __le__(self, other: Any) -> ColumnElement[bool]: # type: ignore[override] # noqa: E501 + def __le__(self, other: Any) -> ColumnElement[bool]: return self._compare(operators.le, other) - def __ge__(self, other: Any) -> ColumnElement[bool]: # type: ignore[override] # noqa: E501 + def __ge__(self, other: Any) -> ColumnElement[bool]: return self._compare(operators.ge, other) # what might be interesting would be if we create @@ -839,8 +839,8 @@ class CompositeProperty( ] if self._adapt_to_entity: assert self.adapter is not None - comparisons = [self.adapter(x) for x in comparisons] # type: ignore # noqa: E501 - return sql.and_(*comparisons) # type: ignore + comparisons = [self.adapter(x) for x in comparisons] + return sql.and_(*comparisons) def __str__(self) -> str: return str(self.parent.class_.__name__) + "." + self.key diff --git a/venv/Lib/site-packages/sqlalchemy/orm/dynamic.py b/venv/Lib/site-packages/sqlalchemy/orm/dynamic.py index 7514d86..1d0c036 100644 --- a/venv/Lib/site-packages/sqlalchemy/orm/dynamic.py +++ b/venv/Lib/site-packages/sqlalchemy/orm/dynamic.py @@ -4,7 +4,6 @@ # # This module is part of SQLAlchemy and is released under # the MIT License: https://www.opensource.org/licenses/mit-license.php -# mypy: ignore-errors """Dynamic collection API. @@ -23,13 +22,19 @@ from __future__ import annotations from typing import Any from typing import Iterable from typing import Iterator +from typing import List +from typing import Optional +from typing import Tuple +from typing import Type from typing import TYPE_CHECKING from typing import TypeVar +from typing import Union from . import attributes from . import exc as orm_exc from . import relationships from . import util as orm_util +from .base import PassiveFlag from .query import Query from .session import object_session from .writeonly import AbstractCollectionWriter @@ -39,15 +44,28 @@ from .writeonly import WriteOnlyLoader from .. import util from ..engine import result -if TYPE_CHECKING: - from .session import Session +if TYPE_CHECKING: + from . import QueryableAttribute + from .mapper import Mapper + from .relationships import _RelationshipOrderByArg + from .session import Session + from .state import InstanceState + from .util import AliasedClass + from ..event import _Dispatch + from ..sql.elements import ColumnElement _T = TypeVar("_T", bound=Any) -class DynamicCollectionHistory(WriteOnlyHistory): - def __init__(self, attr, state, passive, apply_to=None): +class DynamicCollectionHistory(WriteOnlyHistory[_T]): + def __init__( + self, + attr: DynamicAttributeImpl, + state: InstanceState[_T], + passive: PassiveFlag, + apply_to: Optional[DynamicCollectionHistory[_T]] = None, + ) -> None: if apply_to: coll = AppenderQuery(attr, state).autoflush(False) self.unchanged_items = util.OrderedIdentitySet(coll) @@ -63,21 +81,21 @@ class DynamicCollectionHistory(WriteOnlyHistory): class DynamicAttributeImpl(WriteOnlyAttributeImpl): _supports_dynamic_iteration = True - collection_history_cls = DynamicCollectionHistory + collection_history_cls = DynamicCollectionHistory[Any] + query_class: Type[AppenderMixin[Any]] # type: ignore[assignment] def __init__( self, - class_, - key, - typecallable, - dispatch, - target_mapper, - order_by, - query_class=None, - **kw, - ): + class_: Union[Type[Any], AliasedClass[Any]], + key: str, + dispatch: _Dispatch[QueryableAttribute[Any]], + target_mapper: Mapper[_T], + order_by: _RelationshipOrderByArg, + query_class: Optional[Type[AppenderMixin[_T]]] = None, + **kw: Any, + ) -> None: attributes.AttributeImpl.__init__( - self, class_, key, typecallable, dispatch, **kw + self, class_, key, None, dispatch, **kw ) self.target_mapper = target_mapper if order_by: @@ -102,21 +120,23 @@ class AppenderMixin(AbstractCollectionWriter[_T]): """ - query_class = None + query_class: Optional[Type[Query[_T]]] = None + _order_by_clauses: Tuple[ColumnElement[Any], ...] - def __init__(self, attr, state): - Query.__init__(self, attr.target_mapper, None) + def __init__( + self, attr: DynamicAttributeImpl, state: InstanceState[_T] + ) -> None: + Query.__init__( + self, # type: ignore[arg-type] + attr.target_mapper, + None, + ) super().__init__(attr, state) @property - def session(self) -> Session: + def session(self) -> Optional[Session]: sess = object_session(self.instance) - if ( - sess is not None - and self.autoflush - and sess.autoflush - and self.instance in sess - ): + if sess is not None and sess.autoflush and self.instance in sess: sess.flush() if not orm_util.has_identity(self.instance): return None @@ -127,7 +147,7 @@ class AppenderMixin(AbstractCollectionWriter[_T]): def session(self, session: Session) -> None: self.sess = session - def _iter(self): + def _iter(self) -> Union[result.ScalarResult[_T], result.Result[_T]]: sess = self.session if sess is None: state = attributes.instance_state(self.instance) @@ -141,9 +161,9 @@ class AppenderMixin(AbstractCollectionWriter[_T]): return result.IteratorResult( result.SimpleResultMetaData([self.attr.class_.__name__]), - self.attr._get_collection_history( + self.attr._get_collection_history( # type: ignore[arg-type] attributes.instance_state(self.instance), - attributes.PASSIVE_NO_INITIALIZE, + PassiveFlag.PASSIVE_NO_INITIALIZE, ).added_items, _source_supports_scalars=True, ).scalars() @@ -155,15 +175,15 @@ class AppenderMixin(AbstractCollectionWriter[_T]): def __iter__(self) -> Iterator[_T]: ... - def __getitem__(self, index: Any) -> _T: + def __getitem__(self, index: Any) -> Union[_T, List[_T]]: sess = self.session if sess is None: return self.attr._get_collection_history( attributes.instance_state(self.instance), - attributes.PASSIVE_NO_INITIALIZE, + PassiveFlag.PASSIVE_NO_INITIALIZE, ).indexed(index) else: - return self._generate(sess).__getitem__(index) + return self._generate(sess).__getitem__(index) # type: ignore[no-any-return] # noqa: E501 def count(self) -> int: sess = self.session @@ -171,13 +191,16 @@ class AppenderMixin(AbstractCollectionWriter[_T]): return len( self.attr._get_collection_history( attributes.instance_state(self.instance), - attributes.PASSIVE_NO_INITIALIZE, + PassiveFlag.PASSIVE_NO_INITIALIZE, ).added_items ) else: return self._generate(sess).count() - def _generate(self, sess=None): + def _generate( + self, + sess: Optional[Session] = None, + ) -> Query[_T]: # note we're returning an entirely new Query class instance # here without any assignment capabilities; the class of this # query is determined by the session. @@ -259,7 +282,7 @@ class AppenderMixin(AbstractCollectionWriter[_T]): self._remove_impl(item) -class AppenderQuery(AppenderMixin[_T], Query[_T]): +class AppenderQuery(AppenderMixin[_T], Query[_T]): # type: ignore[misc] """A dynamic query that supports basic collection storage operations. Methods on :class:`.AppenderQuery` include all methods of @@ -270,7 +293,7 @@ class AppenderQuery(AppenderMixin[_T], Query[_T]): """ -def mixin_user_query(cls): +def mixin_user_query(cls: Any) -> type[AppenderMixin[Any]]: """Return a new class with AppenderQuery functionality layered over.""" name = "Appender" + cls.__name__ return type(name, (AppenderMixin, cls), {"query_class": cls}) diff --git a/venv/Lib/site-packages/sqlalchemy/orm/instrumentation.py b/venv/Lib/site-packages/sqlalchemy/orm/instrumentation.py index 1b755a2..b12d80a 100644 --- a/venv/Lib/site-packages/sqlalchemy/orm/instrumentation.py +++ b/venv/Lib/site-packages/sqlalchemy/orm/instrumentation.py @@ -138,7 +138,7 @@ class ClassManager( def deferred_scalar_loader(self): return self.expired_attribute_loader - @deferred_scalar_loader.setter # type: ignore[no-redef] + @deferred_scalar_loader.setter @util.deprecated( "1.4", message="The ClassManager.deferred_scalar_loader attribute is now " @@ -204,7 +204,7 @@ class ClassManager( init_method: Optional[Callable[..., None]] = None, ) -> None: if mapper: - self.mapper = mapper # type: ignore[assignment] + self.mapper = mapper # if registry: registry._add_manager(self) if declarative_scan: @@ -428,7 +428,7 @@ class ClassManager( for key in list(self.originals): self.uninstall_member(key) - self.mapper = None # type: ignore + self.mapper = None self.dispatch = None # type: ignore self.new_init = None self.info.clear() @@ -506,11 +506,11 @@ class ClassManager( # so that mypy sees that __new__ is present. currently # it's bound to Any as there were other problems not having # it that way but these can be revisited - instance = self.class_.__new__(self.class_) # type: ignore + instance = self.class_.__new__(self.class_) if state is None: state = self._state_constructor(instance, self) self._state_setter(instance, state) - return instance # type: ignore[no-any-return] + return instance def setup_instance( self, instance: _O, state: Optional[InstanceState[_O]] = None diff --git a/venv/Lib/site-packages/sqlalchemy/orm/interfaces.py b/venv/Lib/site-packages/sqlalchemy/orm/interfaces.py index 88cafcb..a118b2a 100644 --- a/venv/Lib/site-packages/sqlalchemy/orm/interfaces.py +++ b/venv/Lib/site-packages/sqlalchemy/orm/interfaces.py @@ -107,6 +107,7 @@ if typing.TYPE_CHECKING: _StrategyKey = Tuple[Any, ...] _T = TypeVar("_T", bound=Any) +_T_co = TypeVar("_T_co", bound=Any, covariant=True) _TLS = TypeVar("_TLS", bound="Type[LoaderStrategy]") @@ -653,7 +654,7 @@ class MapperProperty( @inspection._self_inspects -class PropComparator(SQLORMOperations[_T], Generic[_T], ColumnOperators): +class PropComparator(SQLORMOperations[_T_co], Generic[_T_co], ColumnOperators): r"""Defines SQL operations for ORM mapped attributes. SQLAlchemy allows for operators to @@ -740,7 +741,7 @@ class PropComparator(SQLORMOperations[_T], Generic[_T], ColumnOperators): _parententity: _InternalEntityType[Any] _adapt_to_entity: Optional[AliasedInsp[Any]] - prop: RODescriptorReference[MapperProperty[_T]] + prop: RODescriptorReference[MapperProperty[_T_co]] def __init__( self, @@ -922,9 +923,7 @@ class PropComparator(SQLORMOperations[_T], Generic[_T], ColumnOperators): """ - return self.operate( # type: ignore - PropComparator.any_op, criterion, **kwargs - ) + return self.operate(PropComparator.any_op, criterion, **kwargs) def has( self, @@ -946,9 +945,7 @@ class PropComparator(SQLORMOperations[_T], Generic[_T], ColumnOperators): """ - return self.operate( # type: ignore - PropComparator.has_op, criterion, **kwargs - ) + return self.operate(PropComparator.has_op, criterion, **kwargs) class StrategizedProperty(MapperProperty[_T]): diff --git a/venv/Lib/site-packages/sqlalchemy/orm/loading.py b/venv/Lib/site-packages/sqlalchemy/orm/loading.py index e7a0d3e..cae6f0b 100644 --- a/venv/Lib/site-packages/sqlalchemy/orm/loading.py +++ b/venv/Lib/site-packages/sqlalchemy/orm/loading.py @@ -137,40 +137,64 @@ def instances(cursor: CursorResult[Any], context: QueryContext) -> Result[Any]: "Can't use the ORM yield_per feature in conjunction with unique()" ) - def _not_hashable(datatype): - def go(obj): - raise sa_exc.InvalidRequestError( - "Can't apply uniqueness to row tuple containing value of " - "type %r; this datatype produces non-hashable values" - % datatype - ) + def _not_hashable(datatype, *, legacy=False, uncertain=False): + if not legacy: - return go + def go(obj): + if uncertain: + try: + return hash(obj) + except: + pass - if context.load_options._legacy_uniquing: - unique_filters = [ - _no_unique - if context.yield_per - else id - if ( - ent.use_id_for_hash - or ent._non_hashable_value - or ent._null_column_type - ) - else None - for ent in context.compile_state._entities - ] - else: - unique_filters = [ - _no_unique - if context.yield_per - else _not_hashable(ent.column.type) # type: ignore - if (not ent.use_id_for_hash and ent._non_hashable_value) - else id - if ent.use_id_for_hash - else None - for ent in context.compile_state._entities - ] + raise sa_exc.InvalidRequestError( + "Can't apply uniqueness to row tuple containing value of " + f"""type {datatype!r}; {'the values returned appear to be' + if uncertain else 'this datatype produces'} """ + "non-hashable values" + ) + + return go + elif not uncertain: + return id + else: + _use_id = False + + def go(obj): + nonlocal _use_id + + if not _use_id: + try: + return hash(obj) + except: + pass + + # in #10459, we considered using a warning here, however + # as legacy query uses result.unique() in all cases, this + # would lead to too many warning cases. + _use_id = True + + return id(obj) + + return go + + unique_filters = [ + _no_unique + if context.yield_per + else _not_hashable( + ent.column.type, # type: ignore + legacy=context.load_options._legacy_uniquing, + uncertain=ent._null_column_type, + ) + if ( + not ent.use_id_for_hash + and (ent._non_hashable_value or ent._null_column_type) + ) + else id + if ent.use_id_for_hash + else None + for ent in context.compile_state._entities + ] row_metadata = SimpleResultMetaData( labels, extra, _unique_filters=unique_filters @@ -1246,7 +1270,16 @@ def _load_subclass_via_in( orig_query = context.query - options = (enable_opt,) + orig_query._with_options + (disable_opt,) + if path.parent: + enable_opt_lcl = enable_opt._prepend_path(path) + disable_opt_lcl = disable_opt._prepend_path(path) + else: + enable_opt_lcl = enable_opt + disable_opt_lcl = disable_opt + options = ( + (enable_opt_lcl,) + orig_query._with_options + (disable_opt_lcl,) + ) + q2 = q.options(*options) q2._compile_options = context.compile_state.default_compile_options diff --git a/venv/Lib/site-packages/sqlalchemy/orm/mapper.py b/venv/Lib/site-packages/sqlalchemy/orm/mapper.py index e78830e..c66d876 100644 --- a/venv/Lib/site-packages/sqlalchemy/orm/mapper.py +++ b/venv/Lib/site-packages/sqlalchemy/orm/mapper.py @@ -786,7 +786,7 @@ class Mapper( # interim - polymorphic_on is further refined in # _configure_polymorphic_setter - self.polymorphic_on = ( # type: ignore + self.polymorphic_on = ( coercions.expect( # type: ignore roles.ColumnArgumentOrKeyRole, polymorphic_on, @@ -964,8 +964,8 @@ class Mapper( version_id_generator: Optional[Union[Literal[False], Callable[[Any], Any]]] local_table: FromClause - """The immediate :class:`_expression.FromClause` which this - :class:`_orm.Mapper` refers towards. + """The immediate :class:`_expression.FromClause` to which this + :class:`_orm.Mapper` refers. Typically is an instance of :class:`_schema.Table`, may be any :class:`.FromClause`. @@ -1400,7 +1400,7 @@ class Mapper( self.with_polymorphic = None if self.with_polymorphic and self.with_polymorphic[1] is not None: - self.with_polymorphic = ( # type: ignore + self.with_polymorphic = ( self.with_polymorphic[0], coercions.expect( roles.StrictFromClauseRole, @@ -1504,7 +1504,7 @@ class Mapper( manager = instrumentation.register_class( self.class_, mapper=self, - expired_attribute_loader=util.partial( # type: ignore + expired_attribute_loader=util.partial( loading.load_scalar_attributes, self ), # finalize flag means instrument the __init__ method @@ -1610,7 +1610,7 @@ class Mapper( if isinstance(c, str) else c for c in ( - coercions.expect( # type: ignore + coercions.expect( roles.DDLConstraintColumnRole, coerce_pk, argname="primary_key", @@ -4097,7 +4097,7 @@ class _OptGetColumnsNotAvailable(Exception): pass -def configure_mappers(): +def configure_mappers() -> None: """Initialize the inter-mapper relationships of all mappers that have been constructed thus far across all :class:`_orm.registry` collections. diff --git a/venv/Lib/site-packages/sqlalchemy/orm/path_registry.py b/venv/Lib/site-packages/sqlalchemy/orm/path_registry.py index 2cd8a14..354552a 100644 --- a/venv/Lib/site-packages/sqlalchemy/orm/path_registry.py +++ b/venv/Lib/site-packages/sqlalchemy/orm/path_registry.py @@ -57,9 +57,9 @@ else: _SerializedPath = List[Any] - +_StrPathToken = str _PathElementType = Union[ - str, "_InternalEntityType[Any]", "MapperProperty[Any]" + _StrPathToken, "_InternalEntityType[Any]", "MapperProperty[Any]" ] # the representation is in fact @@ -70,6 +70,8 @@ _PathElementType = Union[ # chopped at odd intervals as well so this is less flexible _PathRepresentation = Tuple[_PathElementType, ...] +# NOTE: these names are weird since the array is 0-indexed, +# the "_Odd" entries are at 0, 2, 4, etc _OddPathRepresentation = Sequence["_InternalEntityType[Any]"] _EvenPathRepresentation = Sequence[Union["MapperProperty[Any]", str]] @@ -154,6 +156,9 @@ class PathRegistry(HasCacheKey): def _path_for_compare(self) -> Optional[_PathRepresentation]: return self.path + def odd_element(self, index: int) -> _InternalEntityType[Any]: + return self.path[index] # type: ignore + def set(self, attributes: Dict[Any, Any], key: Any, value: Any) -> None: log.debug("set '%s' on path '%s' to '%s'", key, self, value) attributes[(key, self.natural_path)] = value @@ -180,7 +185,7 @@ class PathRegistry(HasCacheKey): return id(self) @overload - def __getitem__(self, entity: str) -> TokenRegistry: + def __getitem__(self, entity: _StrPathToken) -> TokenRegistry: ... @overload @@ -204,7 +209,11 @@ class PathRegistry(HasCacheKey): def __getitem__( self, entity: Union[ - str, int, slice, _InternalEntityType[Any], MapperProperty[Any] + _StrPathToken, + int, + slice, + _InternalEntityType[Any], + MapperProperty[Any], ], ) -> Union[ TokenRegistry, @@ -355,7 +364,7 @@ class CreatesToken(PathRegistry): is_aliased_class: bool is_root: bool - def token(self, token: str) -> TokenRegistry: + def token(self, token: _StrPathToken) -> TokenRegistry: if token.endswith(f":{_WILDCARD_TOKEN}"): return TokenRegistry(self, token) elif token.endswith(f":{_DEFAULT_TOKEN}"): @@ -385,7 +394,7 @@ class RootRegistry(CreatesToken): ) -> Union[TokenRegistry, AbstractEntityRegistry]: if entity in PathToken._intern: if TYPE_CHECKING: - assert isinstance(entity, str) + assert isinstance(entity, _StrPathToken) return TokenRegistry(self, PathToken._intern[entity]) else: try: @@ -433,10 +442,10 @@ class TokenRegistry(PathRegistry): inherit_cache = True - token: str + token: _StrPathToken parent: CreatesToken - def __init__(self, parent: CreatesToken, token: str): + def __init__(self, parent: CreatesToken, token: _StrPathToken): token = PathToken.intern(token) self.token = token @@ -619,7 +628,7 @@ class PropRegistry(PathRegistry): self._wildcard_path_loader_key = ( "loader", - parent.natural_path + self.prop._wildcard_token, # type: ignore + parent.natural_path + self.prop._wildcard_token, ) self._default_path_loader_key = self.prop._default_path_loader_key self._loader_key = ("loader", self.natural_path) @@ -721,7 +730,7 @@ class AbstractEntityRegistry(CreatesToken): @property def root_entity(self) -> _InternalEntityType[Any]: - return cast("_InternalEntityType[Any]", self.path[0]) + return self.odd_element(0) @property def entity_path(self) -> PathRegistry: diff --git a/venv/Lib/site-packages/sqlalchemy/orm/persistence.py b/venv/Lib/site-packages/sqlalchemy/orm/persistence.py index 31fbdf3..6729b47 100644 --- a/venv/Lib/site-packages/sqlalchemy/orm/persistence.py +++ b/venv/Lib/site-packages/sqlalchemy/orm/persistence.py @@ -1082,7 +1082,7 @@ def _emit_insert_statements( records = list(records) if returning_is_required_anyway or ( - not hasvalue and len(records) > 1 + table.implicit_returning and not hasvalue and len(records) > 1 ): if ( deterministic_results_reqd diff --git a/venv/Lib/site-packages/sqlalchemy/orm/properties.py b/venv/Lib/site-packages/sqlalchemy/orm/properties.py index 4df5175..4bb396e 100644 --- a/venv/Lib/site-packages/sqlalchemy/orm/properties.py +++ b/venv/Lib/site-packages/sqlalchemy/orm/properties.py @@ -25,6 +25,7 @@ from typing import Tuple from typing import Type from typing import TYPE_CHECKING from typing import TypeVar +from typing import Union from . import attributes from . import strategy_options @@ -446,7 +447,7 @@ class ColumnProperty( try: return ce.info # type: ignore except AttributeError: - return self.prop.info # type: ignore + return self.prop.info def _memoized_attr_expressions(self) -> Sequence[NamedColumn[Any]]: """The full sequence of columns referenced by this @@ -475,13 +476,13 @@ class ColumnProperty( def operate( self, op: OperatorType, *other: Any, **kwargs: Any ) -> ColumnElement[Any]: - return op(self.__clause_element__(), *other, **kwargs) # type: ignore[return-value,no-any-return] # noqa: E501 + return op(self.__clause_element__(), *other, **kwargs) # type: ignore[no-any-return] # noqa: E501 def reverse_operate( self, op: OperatorType, other: Any, **kwargs: Any ) -> ColumnElement[Any]: col = self.__clause_element__() - return op(col._bind_param(op, other), col, **kwargs) # type: ignore[return-value,no-any-return] # noqa: E501 + return op(col._bind_param(op, other), col, **kwargs) # type: ignore[no-any-return] # noqa: E501 def __str__(self) -> str: if not self.parent or not self.key: @@ -542,7 +543,7 @@ class MappedColumn( "_use_existing_column", ) - deferred: bool + deferred: Union[_NoArg, bool] deferred_raiseload: bool deferred_group: Optional[str] @@ -557,17 +558,15 @@ class MappedColumn( self._use_existing_column = kw.pop("use_existing_column", False) - self._has_dataclass_arguments = False - - if attr_opts is not None and attr_opts != _DEFAULT_ATTRIBUTE_OPTIONS: - if attr_opts.dataclasses_default_factory is not _NoArg.NO_ARG: - self._has_dataclass_arguments = True - - elif ( - attr_opts.dataclasses_init is not _NoArg.NO_ARG - or attr_opts.dataclasses_repr is not _NoArg.NO_ARG - ): - self._has_dataclass_arguments = True + self._has_dataclass_arguments = ( + attr_opts is not None + and attr_opts != _DEFAULT_ATTRIBUTE_OPTIONS + and any( + attr_opts[i] is not _NoArg.NO_ARG + for i, attr in enumerate(attr_opts._fields) + if attr != "dataclasses_default" + ) + ) insert_default = kw.pop("insert_default", _NoArg.NO_ARG) self._has_insert_default = insert_default is not _NoArg.NO_ARG @@ -580,12 +579,9 @@ class MappedColumn( self.deferred_group = kw.pop("deferred_group", None) self.deferred_raiseload = kw.pop("deferred_raiseload", None) self.deferred = kw.pop("deferred", _NoArg.NO_ARG) - if self.deferred is _NoArg.NO_ARG: - self.deferred = bool( - self.deferred_group or self.deferred_raiseload - ) self.active_history = kw.pop("active_history", False) - self._sort_order = kw.pop("sort_order", 0) + + self._sort_order = kw.pop("sort_order", _NoArg.NO_ARG) self.column = cast("Column[_T]", Column(*arg, **kw)) self.foreign_keys = self.column.foreign_keys self._has_nullable = "nullable" in kw and kw.get("nullable") not in ( @@ -617,10 +613,16 @@ class MappedColumn( @property def mapper_property_to_assign(self) -> Optional[MapperProperty[_T]]: - if self.deferred or self.active_history: + effective_deferred = self.deferred + if effective_deferred is _NoArg.NO_ARG: + effective_deferred = bool( + self.deferred_group or self.deferred_raiseload + ) + + if effective_deferred or self.active_history: return ColumnProperty( self.column, - deferred=self.deferred, + deferred=effective_deferred, group=self.deferred_group, raiseload=self.deferred_raiseload, attribute_options=self._attribute_options, @@ -631,7 +633,14 @@ class MappedColumn( @property def columns_to_assign(self) -> List[Tuple[Column[Any], int]]: - return [(self.column, self._sort_order)] + return [ + ( + self.column, + self._sort_order + if self._sort_order is not _NoArg.NO_ARG + else 0, + ) + ] def __clause_element__(self) -> Column[_T]: return self.column @@ -639,13 +648,13 @@ class MappedColumn( def operate( self, op: OperatorType, *other: Any, **kwargs: Any ) -> ColumnElement[Any]: - return op(self.__clause_element__(), *other, **kwargs) # type: ignore[return-value,no-any-return] # noqa: E501 + return op(self.__clause_element__(), *other, **kwargs) # type: ignore[no-any-return] # noqa: E501 def reverse_operate( self, op: OperatorType, other: Any, **kwargs: Any ) -> ColumnElement[Any]: col = self.__clause_element__() - return op(col._bind_param(op, other), col, **kwargs) # type: ignore[return-value,no-any-return] # noqa: E501 + return op(col._bind_param(op, other), col, **kwargs) # type: ignore[no-any-return] # noqa: E501 def found_in_pep593_annotated(self) -> Any: # return a blank mapped_column(). This mapped_column()'s @@ -779,6 +788,65 @@ class MappedColumn( use_args_from.column._merge(self.column) sqltype = self.column.type + if ( + use_args_from.deferred is not _NoArg.NO_ARG + and self.deferred is _NoArg.NO_ARG + ): + self.deferred = use_args_from.deferred + + if ( + use_args_from.deferred_group is not None + and self.deferred_group is None + ): + self.deferred_group = use_args_from.deferred_group + + if ( + use_args_from.deferred_raiseload is not None + and self.deferred_raiseload is None + ): + self.deferred_raiseload = use_args_from.deferred_raiseload + + if ( + use_args_from._use_existing_column + and not self._use_existing_column + ): + self._use_existing_column = True + + if use_args_from.active_history: + self.active_history = use_args_from.active_history + + if ( + use_args_from._sort_order is not None + and self._sort_order is _NoArg.NO_ARG + ): + self._sort_order = use_args_from._sort_order + + if ( + use_args_from.column.key is not None + or use_args_from.column.name is not None + ): + util.warn_deprecated( + "Can't use the 'key' or 'name' arguments in " + "Annotated with mapped_column(); this will be ignored", + "2.0.22", + ) + + if use_args_from._has_dataclass_arguments: + for idx, arg in enumerate( + use_args_from._attribute_options._fields + ): + if ( + use_args_from._attribute_options[idx] + is not _NoArg.NO_ARG + ): + arg = arg.replace("dataclasses_", "") + util.warn_deprecated( + f"Argument '{arg}' is a dataclass argument and " + "cannot be specified within a mapped_column() " + "bundled inside of an Annotated object", + "2.0.22", + ) + if sqltype._isnull and not self.column.foreign_keys: new_sqltype = None diff --git a/venv/Lib/site-packages/sqlalchemy/orm/query.py b/venv/Lib/site-packages/sqlalchemy/orm/query.py index 14e75fa..5da7ee9 100644 --- a/venv/Lib/site-packages/sqlalchemy/orm/query.py +++ b/venv/Lib/site-packages/sqlalchemy/orm/query.py @@ -235,7 +235,9 @@ class Query( def __init__( self, - entities: Sequence[_ColumnsClauseArgument[Any]], + entities: Union[ + _ColumnsClauseArgument[Any], Sequence[_ColumnsClauseArgument[Any]] + ], session: Optional[Session] = None, ): """Construct a :class:`_query.Query` directly. @@ -274,11 +276,14 @@ class Query( self._set_entities(entities) def _set_propagate_attrs(self, values: Mapping[str, Any]) -> Self: - self._propagate_attrs = util.immutabledict(values) # type: ignore + self._propagate_attrs = util.immutabledict(values) return self def _set_entities( - self, entities: Iterable[_ColumnsClauseArgument[Any]] + self, + entities: Union[ + _ColumnsClauseArgument[Any], Iterable[_ColumnsClauseArgument[Any]] + ], ) -> None: self._raw_columns = [ coercions.expect( @@ -478,7 +483,7 @@ class Query( return self def _clone(self, **kw: Any) -> Self: - return self._generate() # type: ignore + return self._generate() def _get_select_statement_only(self) -> Select[_T]: if self._statement is not None: @@ -1450,7 +1455,7 @@ class Query( q._set_entities(columns) if not q.load_options._yield_per: q.load_options += {"_yield_per": 10} - return iter(q) # type: ignore + return iter(q) @util.deprecated( "1.4", diff --git a/venv/Lib/site-packages/sqlalchemy/orm/relationships.py b/venv/Lib/site-packages/sqlalchemy/orm/relationships.py index d3a8da0..7ea30d7 100644 --- a/venv/Lib/site-packages/sqlalchemy/orm/relationships.py +++ b/venv/Lib/site-packages/sqlalchemy/orm/relationships.py @@ -271,6 +271,9 @@ class _RelationshipArg(Generic[_T1, _T2]): self.resolved = attr_value +_RelationshipOrderByArg = Union[Literal[False], Tuple[ColumnElement[Any], ...]] + + class _RelationshipArgs(NamedTuple): """stores user-passed parameters that are resolved at mapper configuration time. @@ -289,10 +292,7 @@ class _RelationshipArgs(NamedTuple): Optional[_RelationshipJoinConditionArgument], Optional[ColumnElement[Any]], ] - order_by: _RelationshipArg[ - _ORMOrderByArgument, - Union[Literal[None, False], Tuple[ColumnElement[Any], ...]], - ] + order_by: _RelationshipArg[_ORMOrderByArgument, _RelationshipOrderByArg] foreign_keys: _RelationshipArg[ Optional[_ORMColCollectionArgument], Set[ColumnElement[Any]] ] @@ -341,7 +341,7 @@ class RelationshipProperty( secondaryjoin: Optional[ColumnElement[bool]] secondary: Optional[FromClause] _join_condition: JoinCondition - order_by: Union[Literal[False], Tuple[ColumnElement[Any], ...]] + order_by: _RelationshipOrderByArg _user_defined_foreign_keys: Set[ColumnElement[Any]] _calculated_foreign_keys: Set[ColumnElement[Any]] @@ -1614,7 +1614,8 @@ class RelationshipProperty( @util.memoized_property def entity(self) -> _InternalEntityType[_T]: """Return the target mapped entity, which is an inspect() of the - class or aliased class that is referred towards. + class or aliased class that is referenced by this + :class:`.RelationshipProperty`. """ self.parent._check_configure() @@ -1764,7 +1765,7 @@ class RelationshipProperty( argument = de_optionalize_union_types(argument) if hasattr(argument, "__origin__"): - arg_origin = argument.__origin__ # type: ignore + arg_origin = argument.__origin__ if isinstance(arg_origin, type) and issubclass( arg_origin, abc.Collection ): @@ -1786,7 +1787,7 @@ class RelationshipProperty( if argument.__args__: # type: ignore if isinstance(arg_origin, type) and issubclass( - arg_origin, typing.Mapping # type: ignore + arg_origin, typing.Mapping ): type_arg = argument.__args__[-1] # type: ignore else: @@ -1804,7 +1805,7 @@ class RelationshipProperty( f"Generic alias {argument} requires an argument" ) elif hasattr(argument, "__forward_arg__"): - argument = argument.__forward_arg__ # type: ignore + argument = argument.__forward_arg__ argument = resolve_name_to_real_class_name( argument, originating_module @@ -1874,7 +1875,7 @@ class RelationshipProperty( % (self.key, type(resolved_argument)) ) - self.entity = entity # type: ignore + self.entity = entity self.target = self.entity.persist_selectable def _setup_join_conditions(self) -> None: @@ -1990,7 +1991,7 @@ class RelationshipProperty( 'and not on the "many" side of a many-to-one or many-to-many ' "relationship. " "To force this relationship to allow a particular " - '"%(relatedcls)s" object to be referred towards by only ' + '"%(relatedcls)s" object to be referenced by only ' 'a single "%(clsname)s" object at a time via the ' "%(rel)s relationship, which " "would allow " diff --git a/venv/Lib/site-packages/sqlalchemy/orm/scoping.py b/venv/Lib/site-packages/sqlalchemy/orm/scoping.py index fc144d9..ab632bd 100644 --- a/venv/Lib/site-packages/sqlalchemy/orm/scoping.py +++ b/venv/Lib/site-packages/sqlalchemy/orm/scoping.py @@ -108,6 +108,7 @@ __all__ = ["scoped_session"] "begin", "begin_nested", "close", + "reset", "commit", "connection", "delete", @@ -118,6 +119,7 @@ __all__ = ["scoped_session"] "expunge_all", "flush", "get", + "get_one", "get_bind", "is_modified", "bulk_save_objects", @@ -466,7 +468,8 @@ class scoped_session(Generic[_S]): :ref:`pysqlite_serializable` - special workarounds required with the SQLite driver in order for SAVEPOINT to work - correctly. + correctly. For asyncio use cases, see the section + :ref:`aiosqlite_serializable`. """ # noqa: E501 @@ -491,12 +494,17 @@ class scoped_session(Generic[_S]): .. tip:: - The :meth:`_orm.Session.close` method **does not prevent the - Session from being used again**. The :class:`_orm.Session` itself - does not actually have a distinct "closed" state; it merely means + In the default running mode the :meth:`_orm.Session.close` + method **does not prevent the Session from being used again**. + The :class:`_orm.Session` itself does not actually have a + distinct "closed" state; it merely means the :class:`_orm.Session` will release all database connections and ORM objects. + Setting the parameter :paramref:`_orm.Session.close_resets_only` + to ``False`` will instead make the ``close`` final, meaning that + any further action on the session will be forbidden. + .. versionchanged:: 1.4 The :meth:`.Session.close` method does not immediately create a new :class:`.SessionTransaction` object; instead, the new :class:`.SessionTransaction` is created only if @@ -505,13 +513,49 @@ class scoped_session(Generic[_S]): .. seealso:: :ref:`session_closing` - detail on the semantics of - :meth:`_orm.Session.close` + :meth:`_orm.Session.close` and :meth:`_orm.Session.reset`. + + :meth:`_orm.Session.reset` - a similar method that behaves like + ``close()`` with the parameter + :paramref:`_orm.Session.close_resets_only` set to ``True``. """ # noqa: E501 return self._proxied.close() + def reset(self) -> None: + r"""Close out the transactional resources and ORM objects used by this + :class:`_orm.Session`, resetting the session to its initial state. + + .. container:: class_bases + + Proxied for the :class:`_orm.Session` class on + behalf of the :class:`_orm.scoping.scoped_session` class. + + This method provides for same "reset-only" behavior that the + :meth:_orm.Session.close method has provided historically, where the + state of the :class:`_orm.Session` is reset as though the object were + brand new, and ready to be used again. + The method may then be useful for :class:`_orm.Session` objects + which set :paramref:`_orm.Session.close_resets_only` to ``False``, + so that "reset only" behavior is still available from this method. + + .. versionadded:: 2.0.22 + + .. seealso:: + + :ref:`session_closing` - detail on the semantics of + :meth:`_orm.Session.close` and :meth:`_orm.Session.reset`. + + :meth:`_orm.Session.close` - a similar method will additionally + prevent re-use of the Session when the parameter + :paramref:`_orm.Session.close_resets_only` is set to ``False``. + + """ # noqa: E501 + + return self._proxied.reset() + def commit(self) -> None: r"""Flush pending changes and commit the current transaction. @@ -1028,6 +1072,56 @@ class scoped_session(Generic[_S]): bind_arguments=bind_arguments, ) + def get_one( + self, + entity: _EntityBindKey[_O], + ident: _PKIdentityArgument, + *, + options: Optional[Sequence[ORMOption]] = None, + populate_existing: bool = False, + with_for_update: ForUpdateParameter = None, + identity_token: Optional[Any] = None, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, + bind_arguments: Optional[_BindArguments] = None, + ) -> _O: + r"""Return exactly one instance based on the given primary key + identifier, or raise an exception if not found. + + .. container:: class_bases + + Proxied for the :class:`_orm.Session` class on + behalf of the :class:`_orm.scoping.scoped_session` class. + + Raises ``sqlalchemy.orm.exc.NoResultFound`` if the query + selects no rows. + + For a detailed documentation of the arguments see the + method :meth:`.Session.get`. + + .. versionadded:: 2.0.22 + + :return: The object instance. + + .. seealso:: + + :meth:`.Session.get` - equivalent method that instead + returns ``None`` if no row was found with the provided primary + key + + + """ # noqa: E501 + + return self._proxied.get_one( + entity, + ident, + options=options, + populate_existing=populate_existing, + with_for_update=with_for_update, + identity_token=identity_token, + execution_options=execution_options, + bind_arguments=bind_arguments, + ) + def get_bind( self, mapper: Optional[_EntityBindKey[_O]] = None, diff --git a/venv/Lib/site-packages/sqlalchemy/orm/session.py b/venv/Lib/site-packages/sqlalchemy/orm/session.py index e5eb503..d861981 100644 --- a/venv/Lib/site-packages/sqlalchemy/orm/session.py +++ b/venv/Lib/site-packages/sqlalchemy/orm/session.py @@ -83,6 +83,7 @@ from ..sql import roles from ..sql import Select from ..sql import TableClause from ..sql import visitors +from ..sql.base import _NoArg from ..sql.base import CompileState from ..sql.schema import Table from ..sql.selectable import ForUpdateArg @@ -510,7 +511,8 @@ class ORMExecuteState(util.MemoizedSlots): """ - return self.bind_arguments.get("mapper", None) + mp: Optional[Mapper[Any]] = self.bind_arguments.get("mapper", None) + return mp @property def all_mappers(self) -> Sequence[Mapper[Any]]: @@ -718,9 +720,14 @@ class ORMExecuteState(util.MemoizedSlots): "This ORM execution is not against a SELECT statement " "so there are no load options." ) - return self.execution_options.get( + + lo: Union[ + context.QueryContext.default_load_options, + Type[context.QueryContext.default_load_options], + ] = self.execution_options.get( "_sa_orm_load_options", context.QueryContext.default_load_options ) + return lo @property def update_delete_options( @@ -737,10 +744,14 @@ class ORMExecuteState(util.MemoizedSlots): "This ORM execution is not against an UPDATE or DELETE " "statement so there are no update options." ) - return self.execution_options.get( + uo: Union[ + bulk_persistence.BulkUDCompileState.default_update_options, + Type[bulk_persistence.BulkUDCompileState.default_update_options], + ] = self.execution_options.get( "_sa_orm_update_options", bulk_persistence.BulkUDCompileState.default_update_options, ) + return uo @property def _non_compile_orm_options(self) -> Sequence[ORMOption]: @@ -881,6 +892,12 @@ class SessionTransaction(_StateChange, TransactionalContext): self.nested = nested = origin is SessionTransactionOrigin.BEGIN_NESTED self.origin = origin + if session._close_state is _SessionCloseState.CLOSED: + raise sa_exc.InvalidRequestError( + "This Session has been permanently closed and is unable " + "to handle any more transaction requests." + ) + if nested: if not parent: raise sa_exc.InvalidRequestError( @@ -1372,6 +1389,12 @@ class SessionTransaction(_StateChange, TransactionalContext): return self._state not in (COMMITTED, CLOSED) +class _SessionCloseState(Enum): + ACTIVE = 1 + CLOSED = 2 + CLOSE_IS_RESET = 3 + + class Session(_SessionClassMethods, EventTarget): """Manages persistence operations for ORM-mapped objects. @@ -1416,6 +1439,7 @@ class Session(_SessionClassMethods, EventTarget): twophase: bool join_transaction_mode: JoinTransactionMode _query_cls: Type[Query[Any]] + _close_state: _SessionCloseState def __init__( self, @@ -1432,6 +1456,7 @@ class Session(_SessionClassMethods, EventTarget): query_cls: Optional[Type[Query[Any]]] = None, autocommit: Literal[False] = False, join_transaction_mode: JoinTransactionMode = "conditional_savepoint", + close_resets_only: Union[bool, _NoArg] = _NoArg.NO_ARG, ): r"""Construct a new :class:`_orm.Session`. @@ -1607,8 +1632,9 @@ class Session(_SessionClassMethods, EventTarget): .. tip:: When using SQLite, the SQLite driver included through Python 3.11 does not handle SAVEPOINTs correctly in all cases - without workarounds. See the section - :ref:`pysqlite_serializable` for details on current workarounds. + without workarounds. See the sections + :ref:`pysqlite_serializable` and :ref:`aiosqlite_serializable` + for details on current workarounds. * ``"control_fully"`` - the :class:`_orm.Session` will take control of the given transaction as its own; @@ -1639,6 +1665,18 @@ class Session(_SessionClassMethods, EventTarget): .. versionadded:: 2.0.0rc1 + :param close_resets_only: Defaults to ``True``. Determines if + the session should reset itself after calling ``.close()`` + or should pass in a no longer usable state, disabling re-use. + + .. versionadded:: 2.0.22 added flag ``close_resets_only``. + A future SQLAlchemy version may change the default value of + this flag to ``False``. + + .. seealso:: + + :ref:`session_closing` - Detail on the semantics of + :meth:`_orm.Session.close` and :meth:`_orm.Session.reset`. """ # noqa @@ -1671,6 +1709,13 @@ class Session(_SessionClassMethods, EventTarget): self.autoflush = autoflush self.expire_on_commit = expire_on_commit self.enable_baked_queries = enable_baked_queries + + # the idea is that at some point NO_ARG will warn that in the future + # the default will switch to close_resets_only=False. + if close_resets_only or close_resets_only is _NoArg.NO_ARG: + self._close_state = _SessionCloseState.CLOSE_IS_RESET + else: + self._close_state = _SessionCloseState.ACTIVE if ( join_transaction_mode and join_transaction_mode @@ -1858,7 +1903,8 @@ class Session(_SessionClassMethods, EventTarget): :ref:`pysqlite_serializable` - special workarounds required with the SQLite driver in order for SAVEPOINT to work - correctly. + correctly. For asyncio use cases, see the section + :ref:`aiosqlite_serializable`. """ return self.begin(nested=True) @@ -2393,12 +2439,17 @@ class Session(_SessionClassMethods, EventTarget): .. tip:: - The :meth:`_orm.Session.close` method **does not prevent the - Session from being used again**. The :class:`_orm.Session` itself - does not actually have a distinct "closed" state; it merely means + In the default running mode the :meth:`_orm.Session.close` + method **does not prevent the Session from being used again**. + The :class:`_orm.Session` itself does not actually have a + distinct "closed" state; it merely means the :class:`_orm.Session` will release all database connections and ORM objects. + Setting the parameter :paramref:`_orm.Session.close_resets_only` + to ``False`` will instead make the ``close`` final, meaning that + any further action on the session will be forbidden. + .. versionchanged:: 1.4 The :meth:`.Session.close` method does not immediately create a new :class:`.SessionTransaction` object; instead, the new :class:`.SessionTransaction` is created only if @@ -2407,11 +2458,40 @@ class Session(_SessionClassMethods, EventTarget): .. seealso:: :ref:`session_closing` - detail on the semantics of - :meth:`_orm.Session.close` + :meth:`_orm.Session.close` and :meth:`_orm.Session.reset`. + + :meth:`_orm.Session.reset` - a similar method that behaves like + ``close()`` with the parameter + :paramref:`_orm.Session.close_resets_only` set to ``True``. """ self._close_impl(invalidate=False) + def reset(self) -> None: + """Close out the transactional resources and ORM objects used by this + :class:`_orm.Session`, resetting the session to its initial state. + + This method provides for same "reset-only" behavior that the + :meth:_orm.Session.close method has provided historically, where the + state of the :class:`_orm.Session` is reset as though the object were + brand new, and ready to be used again. + The method may then be useful for :class:`_orm.Session` objects + which set :paramref:`_orm.Session.close_resets_only` to ``False``, + so that "reset only" behavior is still available from this method. + + .. versionadded:: 2.0.22 + + .. seealso:: + + :ref:`session_closing` - detail on the semantics of + :meth:`_orm.Session.close` and :meth:`_orm.Session.reset`. + + :meth:`_orm.Session.close` - a similar method will additionally + prevent re-use of the Session when the parameter + :paramref:`_orm.Session.close_resets_only` is set to ``False``. + """ + self._close_impl(invalidate=False, is_reset=True) + def invalidate(self) -> None: """Close this Session, using connection invalidation. @@ -2448,7 +2528,9 @@ class Session(_SessionClassMethods, EventTarget): """ self._close_impl(invalidate=True) - def _close_impl(self, invalidate: bool) -> None: + def _close_impl(self, invalidate: bool, is_reset: bool = False) -> None: + if not is_reset and self._close_state is _SessionCloseState.ACTIVE: + self._close_state = _SessionCloseState.CLOSED self.expunge_all() if self._transaction is not None: for transaction in self._transaction._iterate_self_and_parents(): @@ -3580,6 +3662,57 @@ class Session(_SessionClassMethods, EventTarget): bind_arguments=bind_arguments, ) + def get_one( + self, + entity: _EntityBindKey[_O], + ident: _PKIdentityArgument, + *, + options: Optional[Sequence[ORMOption]] = None, + populate_existing: bool = False, + with_for_update: ForUpdateParameter = None, + identity_token: Optional[Any] = None, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, + bind_arguments: Optional[_BindArguments] = None, + ) -> _O: + """Return exactly one instance based on the given primary key + identifier, or raise an exception if not found. + + Raises ``sqlalchemy.orm.exc.NoResultFound`` if the query + selects no rows. + + For a detailed documentation of the arguments see the + method :meth:`.Session.get`. + + .. versionadded:: 2.0.22 + + :return: The object instance. + + .. seealso:: + + :meth:`.Session.get` - equivalent method that instead + returns ``None`` if no row was found with the provided primary + key + + """ + + instance = self.get( + entity, + ident, + options=options, + populate_existing=populate_existing, + with_for_update=with_for_update, + identity_token=identity_token, + execution_options=execution_options, + bind_arguments=bind_arguments, + ) + + if instance is None: + raise sa_exc.NoResultFound( + "No row was found when one was required" + ) + + return instance + def _get_impl( self, entity: _EntityBindKey[_O], diff --git a/venv/Lib/site-packages/sqlalchemy/orm/state.py b/venv/Lib/site-packages/sqlalchemy/orm/state.py index b1ae198..d9e1f85 100644 --- a/venv/Lib/site-packages/sqlalchemy/orm/state.py +++ b/venv/Lib/site-packages/sqlalchemy/orm/state.py @@ -617,8 +617,8 @@ class InstanceState(interfaces.InspectionAttrInfo, Generic[_O]): self.class_ = state_dict["class_"] self.committed_state = state_dict.get("committed_state", {}) - self._pending_mutations = state_dict.get("_pending_mutations", {}) # type: ignore # noqa E501 - self.parents = state_dict.get("parents", {}) # type: ignore + self._pending_mutations = state_dict.get("_pending_mutations", {}) + self.parents = state_dict.get("parents", {}) self.modified = state_dict.get("modified", False) self.expired = state_dict.get("expired", False) if "info" in state_dict: diff --git a/venv/Lib/site-packages/sqlalchemy/orm/strategies.py b/venv/Lib/site-packages/sqlalchemy/orm/strategies.py index a0e0929..1e58f40 100644 --- a/venv/Lib/site-packages/sqlalchemy/orm/strategies.py +++ b/venv/Lib/site-packages/sqlalchemy/orm/strategies.py @@ -306,8 +306,9 @@ class ExpressionColumnLoader(ColumnLoader): **kwargs, ): columns = None - if loadopt and "expression" in loadopt.local_opts: - columns = [loadopt.local_opts["expression"]] + if loadopt and loadopt._extra_criteria: + columns = loadopt._extra_criteria + elif self._have_default_expression: columns = self.parent_property.columns @@ -343,8 +344,8 @@ class ExpressionColumnLoader(ColumnLoader): ): # look through list of columns represented here # to see which, if any, is present in the row. - if loadopt and "expression" in loadopt.local_opts: - columns = [loadopt.local_opts["expression"]] + if loadopt and loadopt._extra_criteria: + columns = loadopt._extra_criteria for col in columns: if adapter: diff --git a/venv/Lib/site-packages/sqlalchemy/orm/strategy_options.py b/venv/Lib/site-packages/sqlalchemy/orm/strategy_options.py index d59fbb7..6c81e8f 100644 --- a/venv/Lib/site-packages/sqlalchemy/orm/strategy_options.py +++ b/venv/Lib/site-packages/sqlalchemy/orm/strategy_options.py @@ -34,6 +34,7 @@ from .attributes import QueryableAttribute from .base import InspectionAttr from .interfaces import LoaderOption from .path_registry import _DEFAULT_TOKEN +from .path_registry import _StrPathToken from .path_registry import _WILDCARD_TOKEN from .path_registry import AbstractEntityRegistry from .path_registry import path_is_property @@ -77,7 +78,7 @@ if typing.TYPE_CHECKING: from ..sql.cache_key import CacheKey -_AttrType = Union[str, "QueryableAttribute[Any]"] +_AttrType = Union[Literal["*"], "QueryableAttribute[Any]"] _WildcardKeyType = Literal["relationship", "column"] _StrategySpec = Dict[str, Any] @@ -541,7 +542,12 @@ class _AbstractLoad(traversals.GenerativeOnTraversal, LoaderOption): ) def defaultload(self, attr: _AttrType) -> Self: - """Indicate an attribute should load using its default loader style. + """Indicate an attribute should load using its predefined loader style. + + The behavior of this loading option is to not change the current + loading style of the attribute, meaning that the previously configured + one is used or, if no previous style was selected, the default + loading will be used. This method is used to link to other loader options further into a chain of attributes without altering the loader style of the links @@ -741,7 +747,7 @@ class _AbstractLoad(traversals.GenerativeOnTraversal, LoaderOption): ) return self._set_column_strategy( - (key,), {"query_expression": True}, opts={"expression": expression} + (key,), {"query_expression": True}, extra_criteria=(expression,) ) def selectin_polymorphic(self, classes: Iterable[Type[Any]]) -> Self: @@ -813,6 +819,7 @@ class _AbstractLoad(traversals.GenerativeOnTraversal, LoaderOption): attrs: Tuple[_AttrType, ...], strategy: Optional[_StrategySpec], opts: Optional[_OptsType] = None, + extra_criteria: Optional[Tuple[Any, ...]] = None, ) -> Self: strategy_key = self._coerce_strat(strategy) @@ -822,6 +829,7 @@ class _AbstractLoad(traversals.GenerativeOnTraversal, LoaderOption): _COLUMN_TOKEN, opts=opts, attr_group=attrs, + extra_criteria=extra_criteria, ) return self @@ -878,6 +886,7 @@ class _AbstractLoad(traversals.GenerativeOnTraversal, LoaderOption): attr_group: Optional[_AttrGroupType] = None, propagate_to_loaders: bool = True, reconcile_to_other: Optional[bool] = None, + extra_criteria: Optional[Tuple[Any, ...]] = None, ) -> Self: raise NotImplementedError() @@ -977,6 +986,7 @@ class Load(_AbstractLoad): __slots__ = ( "path", "context", + "additional_source_entities", ) _traverse_internals = [ @@ -986,11 +996,16 @@ class Load(_AbstractLoad): visitors.InternalTraversal.dp_has_cache_key_list, ), ("propagate_to_loaders", visitors.InternalTraversal.dp_boolean), + ( + "additional_source_entities", + visitors.InternalTraversal.dp_has_cache_key_list, + ), ] _cache_key_traversal = None path: PathRegistry context: Tuple[_LoadElement, ...] + additional_source_entities: Tuple[_InternalEntityType[Any], ...] def __init__(self, entity: _EntityType[Any]): insp = cast("Union[Mapper[Any], AliasedInsp[Any]]", inspect(entity)) @@ -999,16 +1014,20 @@ class Load(_AbstractLoad): self.path = insp._path_registry self.context = () self.propagate_to_loaders = False + self.additional_source_entities = () def __str__(self) -> str: return f"Load({self.path[0]})" @classmethod - def _construct_for_existing_path(cls, path: PathRegistry) -> Load: + def _construct_for_existing_path( + cls, path: AbstractEntityRegistry + ) -> Load: load = cls.__new__(cls) load.path = path load.context = () load.propagate_to_loaders = False + load.additional_source_entities = () return load def _adapt_cached_option_to_uncached_option( @@ -1016,6 +1035,13 @@ class Load(_AbstractLoad): ) -> ORMOption: return self._adjust_for_extra_criteria(context) + def _prepend_path(self, path: PathRegistry) -> Load: + cloned = self._clone() + cloned.context = tuple( + element._prepend_path(path) for element in self.context + ) + return cloned + def _adjust_for_extra_criteria(self, context: QueryContext) -> Load: """Apply the current bound parameters in a QueryContext to all occurrences "extra_criteria" stored within this ``Load`` object, @@ -1029,16 +1055,10 @@ class Load(_AbstractLoad): found_crit = False def process(opt: _LoadElement) -> _LoadElement: - if not opt._extra_criteria: - return opt - nonlocal orig_cache_key, replacement_cache_key, found_crit found_crit = True - # avoid generating cache keys for the queries if we don't - # actually have any extra_criteria options, which is the - # common case if orig_cache_key is None or replacement_cache_key is None: orig_cache_key = orig_query._generate_cache_key() replacement_cache_key = context.query._generate_cache_key() @@ -1052,8 +1072,12 @@ class Load(_AbstractLoad): ) for crit in opt._extra_criteria ) + return opt + # avoid generating cache keys for the queries if we don't + # actually have any extra_criteria options, which is the + # common case new_context = tuple( process(value._clone()) if value._extra_criteria else value for value in self.context @@ -1116,9 +1140,12 @@ class Load(_AbstractLoad): assert cloned.propagate_to_loaders == self.propagate_to_loaders - if not orm_util._entity_corresponds_to_use_path_impl( - cast("_InternalEntityType[Any]", parent.path[-1]), - cast("_InternalEntityType[Any]", cloned.path[0]), + if not any( + orm_util._entity_corresponds_to_use_path_impl( + elem, cloned.path.odd_element(0) + ) + for elem in (parent.path.odd_element(-1),) + + parent.additional_source_entities ): if len(cloned.path) > 1: attrname = cloned.path[1] @@ -1137,6 +1164,9 @@ class Load(_AbstractLoad): if cloned.context: parent.context += cloned.context + parent.additional_source_entities += ( + cloned.additional_source_entities + ) @_generative def options(self, *opts: _AbstractLoad) -> Self: @@ -1191,6 +1221,7 @@ class Load(_AbstractLoad): attr_group: Optional[_AttrGroupType] = None, propagate_to_loaders: bool = True, reconcile_to_other: Optional[bool] = None, + extra_criteria: Optional[Tuple[Any, ...]] = None, ) -> Self: # for individual strategy that needs to propagate, set the whole # Load container to also propagate, so that it shows up in @@ -1224,9 +1255,14 @@ class Load(_AbstractLoad): propagate_to_loaders, attr_group=attr_group, reconcile_to_other=reconcile_to_other, + extra_criteria=extra_criteria, ) if load_element: self.context += (load_element,) + assert opts is not None + self.additional_source_entities += cast( + "Tuple[_InternalEntityType[Any]]", opts["entities"] + ) else: for attr in attrs: @@ -1240,6 +1276,7 @@ class Load(_AbstractLoad): propagate_to_loaders, attr_group=attr_group, reconcile_to_other=reconcile_to_other, + extra_criteria=extra_criteria, ) else: load_element = _AttributeStrategyLoad.create( @@ -1251,6 +1288,7 @@ class Load(_AbstractLoad): propagate_to_loaders, attr_group=attr_group, reconcile_to_other=reconcile_to_other, + extra_criteria=extra_criteria, ) if load_element: @@ -1314,6 +1352,7 @@ class _WildcardLoad(_AbstractLoad): attr_group=None, propagate_to_loaders=True, reconcile_to_other=None, + extra_criteria=None, ): assert attrs is not None attr = attrs[0] @@ -1330,6 +1369,8 @@ class _WildcardLoad(_AbstractLoad): if opts: self.local_opts = util.immutabledict(opts) + assert extra_criteria is None + def options(self, *opts: _AbstractLoad) -> Self: raise NotImplementedError("Star option does not support sub-options") @@ -1616,7 +1657,9 @@ class _LoadElement( return effective_path - def _init_path(self, path, attr, wildcard_key, attr_group, raiseerr): + def _init_path( + self, path, attr, wildcard_key, attr_group, raiseerr, extra_criteria + ): """Apply ORM attributes and/or wildcard to an existing path, producing a new path. @@ -1668,7 +1711,7 @@ class _LoadElement( def create( cls, path: PathRegistry, - attr: Optional[_AttrType], + attr: Union[_AttrType, _StrPathToken, None], strategy: Optional[_StrategyKey], wildcard_key: Optional[_WildcardKeyType], local_opts: Optional[_OptsType], @@ -1676,6 +1719,7 @@ class _LoadElement( raiseerr: bool = True, attr_group: Optional[_AttrGroupType] = None, reconcile_to_other: Optional[bool] = None, + extra_criteria: Optional[Tuple[Any, ...]] = None, ) -> _LoadElement: """Create a new :class:`._LoadElement` object.""" @@ -1695,7 +1739,9 @@ class _LoadElement( else: opt._reconcile_to_other = None - path = opt._init_path(path, attr, wildcard_key, attr_group, raiseerr) + path = opt._init_path( + path, attr, wildcard_key, attr_group, raiseerr, extra_criteria + ) if not path: return None # type: ignore @@ -1714,9 +1760,7 @@ class _LoadElement( return cloned - def _prepend_path_from( - self, parent: Union[Load, _LoadElement] - ) -> _LoadElement: + def _prepend_path_from(self, parent: Load) -> _LoadElement: """adjust the path of this :class:`._LoadElement` to be a subpath of that of the given parent :class:`_orm.Load` object's path. @@ -1725,22 +1769,30 @@ class _LoadElement( which is in turn part of the :meth:`_orm.Load.options` method. """ + + if not any( + orm_util._entity_corresponds_to_use_path_impl( + elem, + self.path.odd_element(0), + ) + for elem in (parent.path.odd_element(-1),) + + parent.additional_source_entities + ): + raise sa_exc.ArgumentError( + f'Attribute "{self.path[1]}" does not link ' + f'from element "{parent.path[-1]}".' + ) + + return self._prepend_path(parent.path) + + def _prepend_path(self, path: PathRegistry) -> _LoadElement: cloned = self._clone() assert cloned.strategy == self.strategy assert cloned.local_opts == self.local_opts assert cloned.is_class_strategy == self.is_class_strategy - if not orm_util._entity_corresponds_to_use_path_impl( - cast("_InternalEntityType[Any]", parent.path[-1]), - cast("_InternalEntityType[Any]", cloned.path[0]), - ): - raise sa_exc.ArgumentError( - f'Attribute "{cloned.path[1]}" does not link ' - f'from element "{parent.path[-1]}".' - ) - - cloned.path = PathRegistry.coerce(parent.path[0:-1] + cloned.path[:]) + cloned.path = PathRegistry.coerce(path[0:-1] + cloned.path[:]) return cloned @@ -1789,7 +1841,7 @@ class _LoadElement( replacement.local_opts = replacement.local_opts.union( existing.local_opts ) - replacement._extra_criteria += replacement._extra_criteria + replacement._extra_criteria += existing._extra_criteria return replacement elif replacement.path.is_token: # use 'last one wins' logic for wildcard options. this is also @@ -1831,7 +1883,9 @@ class _AttributeStrategyLoad(_LoadElement): is_class_strategy = False is_token_strategy = False - def _init_path(self, path, attr, wildcard_key, attr_group, raiseerr): + def _init_path( + self, path, attr, wildcard_key, attr_group, raiseerr, extra_criteria + ): assert attr is not None self._of_type = None self._path_with_polymorphic_path = None @@ -1877,7 +1931,11 @@ class _AttributeStrategyLoad(_LoadElement): # from an attribute. This appears to have been an artifact of how # _UnboundLoad / Load interacted together, which was opaque and # poorly defined. - self._extra_criteria = attr._extra_criteria + if extra_criteria: + assert not attr._extra_criteria + self._extra_criteria = extra_criteria + else: + self._extra_criteria = attr._extra_criteria if getattr(attr, "_of_type", None): ac = attr._of_type @@ -2070,7 +2128,9 @@ class _TokenStrategyLoad(_LoadElement): is_class_strategy = False is_token_strategy = True - def _init_path(self, path, attr, wildcard_key, attr_group, raiseerr): + def _init_path( + self, path, attr, wildcard_key, attr_group, raiseerr, extra_criteria + ): # assert isinstance(attr, str) or attr is None if attr is not None: default_token = attr.endswith(_DEFAULT_TOKEN) @@ -2156,7 +2216,9 @@ class _ClassStrategyLoad(_LoadElement): __visit_name__ = "class_strategy_load_element" - def _init_path(self, path, attr, wildcard_key, attr_group, raiseerr): + def _init_path( + self, path, attr, wildcard_key, attr_group, raiseerr, extra_criteria + ): return path def _prepare_for_compile_state( @@ -2447,7 +2509,9 @@ def _raise_for_does_not_link(path, attrname, parent_entity): ( " Did you mean to use " f'"{path[-2]}' - f'.of_type({parent_entity_str})"?' + f'.of_type({parent_entity_str})" or "loadopt.options(' + f"selectin_polymorphic({path[-2].mapper.class_.__name__}, " + f'[{parent_entity_str}]), ...)" ?' if not path_is_of_type and not path[-1].is_aliased_class and orm_util._entity_corresponds_to( diff --git a/venv/Lib/site-packages/sqlalchemy/orm/util.py b/venv/Lib/site-packages/sqlalchemy/orm/util.py index 4371e61..ea2f1a1 100644 --- a/venv/Lib/site-packages/sqlalchemy/orm/util.py +++ b/venv/Lib/site-packages/sqlalchemy/orm/util.py @@ -45,6 +45,7 @@ from .base import _never_set as _never_set # noqa: F401 from .base import _none_set as _none_set # noqa: F401 from .base import attribute_str as attribute_str # noqa: F401 from .base import class_mapper as class_mapper +from .base import DynamicMapped from .base import InspectionAttr as InspectionAttr from .base import instance_str as instance_str # noqa: F401 from .base import Mapped @@ -55,6 +56,7 @@ from .base import ORMDescriptor from .base import state_attribute_str as state_attribute_str # noqa: F401 from .base import state_class_str as state_class_str # noqa: F401 from .base import state_str as state_str # noqa: F401 +from .base import WriteOnlyMapped from .interfaces import CriteriaOption from .interfaces import MapperProperty as MapperProperty from .interfaces import ORMColumnsClauseRole @@ -100,6 +102,7 @@ if typing.TYPE_CHECKING: from .context import _MapperEntity from .context import ORMCompileState from .mapper import Mapper + from .path_registry import AbstractEntityRegistry from .query import Query from .relationships import RelationshipProperty from ..engine import Row @@ -137,7 +140,14 @@ all_cascades = frozenset( _de_stringify_partial = functools.partial( - functools.partial, locals_=util.immutabledict({"Mapped": Mapped}) + functools.partial, + locals_=util.immutabledict( + { + "Mapped": Mapped, + "WriteOnlyMapped": WriteOnlyMapped, + "DynamicMapped": DynamicMapped, + } + ), ) # partial is practically useless as we have to write out the whole @@ -935,7 +945,7 @@ class AliasedInsp( """the AliasedClass that refers to this AliasedInsp""" _target: Union[Type[_O], AliasedClass[_O]] - """the thing referred towards by the AliasedClass/AliasedInsp. + """the thing referenced by the AliasedClass/AliasedInsp. In the vast majority of cases, this is the mapped class. However it may also be another AliasedClass (alias of alias). @@ -1124,7 +1134,7 @@ class AliasedInsp( return self.mapper.class_ @property - def _path_registry(self) -> PathRegistry: + def _path_registry(self) -> AbstractEntityRegistry: if self._use_mapper_path: return self.mapper._path_registry else: @@ -1204,7 +1214,7 @@ class AliasedInsp( # IMO mypy should see this one also as returning the same type # we put into it, but it's not return ( - self._adapter.traverse(expr) # type: ignore + self._adapter.traverse(expr) ._annotate(d) ._set_propagate_attrs( {"compile_state_plugin": "orm", "plugin_subject": self} @@ -1397,7 +1407,7 @@ class LoaderCriteriaOption(CriteriaOption): self.deferred_where_criteria = True self.where_criteria = lambdas.DeferredLambdaElement( - where_criteria, # type: ignore + where_criteria, roles.WhereHavingRole, lambda_args=(_WrapUserEntity(wrap_entity),), opts=lambdas.LambdaOptions( @@ -1620,12 +1630,18 @@ class Bundle( ) @property - def mapper(self) -> Mapper[Any]: - return self.exprs[0]._annotations.get("parentmapper", None) + def mapper(self) -> Optional[Mapper[Any]]: + mp: Optional[Mapper[Any]] = self.exprs[0]._annotations.get( + "parentmapper", None + ) + return mp @property - def entity(self) -> _InternalEntityType[Any]: - return self.exprs[0]._annotations.get("parententity", None) + def entity(self) -> Optional[_InternalEntityType[Any]]: + ie: Optional[_InternalEntityType[Any]] = self.exprs[ + 0 + ]._annotations.get("parententity", None) + return ie @property def entity_namespace( @@ -1827,8 +1843,8 @@ class _ORMJoin(expression.Join): prop = None on_selectable = None + left_selectable = left_info.selectable if prop: - left_selectable = left_info.selectable adapt_from: Optional[FromClause] if sql_util.clause_is_present(on_selectable, left_selectable): adapt_from = on_selectable @@ -1865,25 +1881,25 @@ class _ORMJoin(expression.Join): self._target_adapter = target_adapter - # we don't use the normal coercions logic for _ORMJoin - # (probably should), so do some gymnastics to get the entity. - # logic here is for #8721, which was a major bug in 1.4 - # for almost two years, not reported/fixed until 1.4.43 (!) - if is_selectable(left_info): - parententity = left_selectable._annotations.get( - "parententity", None - ) - elif insp_is_mapper(left_info) or insp_is_aliased_class(left_info): - parententity = left_info - else: - parententity = None + # we don't use the normal coercions logic for _ORMJoin + # (probably should), so do some gymnastics to get the entity. + # logic here is for #8721, which was a major bug in 1.4 + # for almost two years, not reported/fixed until 1.4.43 (!) + if is_selectable(left_info): + parententity = left_selectable._annotations.get( + "parententity", None + ) + elif insp_is_mapper(left_info) or insp_is_aliased_class(left_info): + parententity = left_info + else: + parententity = None - if parententity is not None: - self._annotations = self._annotations.union( - {"parententity": parententity} - ) + if parententity is not None: + self._annotations = self._annotations.union( + {"parententity": parententity} + ) - augment_onclause = onclause is None and _extra_criteria + augment_onclause = bool(_extra_criteria) and not prop expression.Join.__init__(self, left, right, onclause, isouter, full) assert self.onclause is not None @@ -2169,9 +2185,9 @@ def _getitem(iterable_query: Query[Any], item: Any) -> Any: res = iterable_query.slice(start, stop) if step is not None: - return list(res)[None : None : item.step] # type: ignore + return list(res)[None : None : item.step] else: - return list(res) # type: ignore + return list(res) else: if item == -1: _no_negative_indexes() @@ -2234,14 +2250,17 @@ def _cleanup_mapped_str_annotation( "outside of TYPE_CHECKING blocks" ) from ne - try: - if issubclass(obj, _MappedAnnotationBase): - real_symbol = obj.__name__ - else: + if obj is typing.ClassVar: + real_symbol = "ClassVar" + else: + try: + if issubclass(obj, _MappedAnnotationBase): + real_symbol = obj.__name__ + else: + return annotation + except TypeError: + # avoid isinstance(obj, type) check, just catch TypeError return annotation - except TypeError: - # avoid isinstance(obj, type) check, just catch TypeError - return annotation # note: if one of the codepaths above didn't define real_symbol and # then didn't return, real_symbol raises UnboundLocalError @@ -2380,9 +2399,9 @@ def _extract_mapped_subtype( else: return annotated, None - if len(annotated.__args__) != 1: # type: ignore + if len(annotated.__args__) != 1: raise sa_exc.ArgumentError( "Expected sub-type for Mapped[] annotation" ) - return annotated.__args__[0], annotated.__origin__ # type: ignore + return annotated.__args__[0], annotated.__origin__ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/writeonly.py b/venv/Lib/site-packages/sqlalchemy/orm/writeonly.py index 0f24583..416a039 100644 --- a/venv/Lib/site-packages/sqlalchemy/orm/writeonly.py +++ b/venv/Lib/site-packages/sqlalchemy/orm/writeonly.py @@ -4,8 +4,6 @@ # # This module is part of SQLAlchemy and is released under # the MIT License: https://www.opensource.org/licenses/mit-license.php -# mypy: ignore-errors - """Write-only collection API. @@ -21,12 +19,17 @@ object must be executed each time. from __future__ import annotations from typing import Any +from typing import Collection +from typing import Dict from typing import Generic from typing import Iterable +from typing import Iterator +from typing import List from typing import NoReturn from typing import Optional from typing import overload from typing import Tuple +from typing import Type from typing import TYPE_CHECKING from typing import TypeVar from typing import Union @@ -36,9 +39,10 @@ from . import attributes from . import interfaces from . import relationships from . import strategies +from .base import NEVER_SET from .base import object_mapper from .base import PassiveFlag -from .relationships import RelationshipDirection +from .base import RelationshipDirection from .. import exc from .. import inspect from .. import log @@ -53,22 +57,38 @@ from ..sql.dml import Update from ..util.typing import Literal if TYPE_CHECKING: + from . import QueryableAttribute from ._typing import _InstanceDict - from .attributes import _AdaptedCollectionProtocol from .attributes import AttributeEventToken - from .attributes import CollectionAdapter from .base import LoaderCallableStatus + from .collections import _AdaptedCollectionProtocol + from .collections import CollectionAdapter + from .mapper import Mapper + from .relationships import _RelationshipOrderByArg from .state import InstanceState + from .util import AliasedClass + from ..event import _Dispatch + from ..sql.selectable import FromClause from ..sql.selectable import Select - _T = TypeVar("_T", bound=Any) -class WriteOnlyHistory: +class WriteOnlyHistory(Generic[_T]): """Overrides AttributeHistory to receive append/remove events directly.""" - def __init__(self, attr, state, passive, apply_to=None): + unchanged_items: util.OrderedIdentitySet + added_items: util.OrderedIdentitySet + deleted_items: util.OrderedIdentitySet + _reconcile_collection: bool + + def __init__( + self, + attr: WriteOnlyAttributeImpl, + state: InstanceState[_T], + passive: PassiveFlag, + apply_to: Optional[WriteOnlyHistory[_T]] = None, + ) -> None: if apply_to: if passive & PassiveFlag.SQL_OK: raise exc.InvalidRequestError( @@ -90,18 +110,18 @@ class WriteOnlyHistory: self._reconcile_collection = False @property - def added_plus_unchanged(self): + def added_plus_unchanged(self) -> List[_T]: return list(self.added_items.union(self.unchanged_items)) @property - def all_items(self): + def all_items(self) -> List[_T]: return list( self.added_items.union(self.unchanged_items).union( self.deleted_items ) ) - def as_history(self): + def as_history(self) -> attributes.History: if self._reconcile_collection: added = self.added_items.difference(self.unchanged_items) deleted = self.deleted_items.intersection(self.unchanged_items) @@ -114,13 +134,13 @@ class WriteOnlyHistory: ) return attributes.History(list(added), list(unchanged), list(deleted)) - def indexed(self, index): + def indexed(self, index: Union[int, slice]) -> Union[List[_T], _T]: return list(self.added_items)[index] - def add_added(self, value): + def add_added(self, value: _T) -> None: self.added_items.add(value) - def add_removed(self, value): + def add_removed(self, value: _T) -> None: if value in self.added_items: self.added_items.remove(value) else: @@ -130,35 +150,41 @@ class WriteOnlyHistory: class WriteOnlyAttributeImpl( attributes.HasCollectionAdapter, attributes.AttributeImpl ): - uses_objects = True - default_accepts_scalar_loader = False - supports_population = False - _supports_dynamic_iteration = False - collection = False - dynamic = True - order_by = () - collection_history_cls = WriteOnlyHistory + uses_objects: bool = True + default_accepts_scalar_loader: bool = False + supports_population: bool = False + _supports_dynamic_iteration: bool = False + collection: bool = False + dynamic: bool = True + order_by: _RelationshipOrderByArg = () + collection_history_cls: Type[WriteOnlyHistory[Any]] = WriteOnlyHistory + + query_class: Type[WriteOnlyCollection[Any]] def __init__( self, - class_, - key, - typecallable, - dispatch, - target_mapper, - order_by, - **kw, + class_: Union[Type[Any], AliasedClass[Any]], + key: str, + dispatch: _Dispatch[QueryableAttribute[Any]], + target_mapper: Mapper[_T], + order_by: _RelationshipOrderByArg, + **kw: Any, ): - super().__init__(class_, key, typecallable, dispatch, **kw) + super().__init__(class_, key, None, dispatch, **kw) self.target_mapper = target_mapper self.query_class = WriteOnlyCollection if order_by: self.order_by = tuple(order_by) - def get(self, state, dict_, passive=attributes.PASSIVE_OFF): - if not passive & attributes.SQL_OK: + def get( + self, + state: InstanceState[Any], + dict_: _InstanceDict, + passive: PassiveFlag = PassiveFlag.PASSIVE_OFF, + ) -> Union[util.OrderedIdentitySet, WriteOnlyCollection[Any]]: + if not passive & PassiveFlag.SQL_OK: return self._get_collection_history( - state, attributes.PASSIVE_NO_INITIALIZE + state, PassiveFlag.PASSIVE_NO_INITIALIZE ).added_items else: return self.query_class(self, state) @@ -204,24 +230,34 @@ class WriteOnlyAttributeImpl( ) -> Union[ Literal[LoaderCallableStatus.PASSIVE_NO_RESULT], CollectionAdapter ]: - if not passive & attributes.SQL_OK: + data: Collection[Any] + if not passive & PassiveFlag.SQL_OK: data = self._get_collection_history(state, passive).added_items else: history = self._get_collection_history(state, passive) data = history.added_plus_unchanged - return DynamicCollectionAdapter(data) # type: ignore + return DynamicCollectionAdapter(data) # type: ignore[return-value] @util.memoized_property - def _append_token(self): + def _append_token( # type:ignore[override] + self, + ) -> attributes.AttributeEventToken: return attributes.AttributeEventToken(self, attributes.OP_APPEND) @util.memoized_property - def _remove_token(self): + def _remove_token( # type:ignore[override] + self, + ) -> attributes.AttributeEventToken: return attributes.AttributeEventToken(self, attributes.OP_REMOVE) def fire_append_event( - self, state, dict_, value, initiator, collection_history=None - ): + self, + state: InstanceState[Any], + dict_: _InstanceDict, + value: Any, + initiator: Optional[AttributeEventToken], + collection_history: Optional[WriteOnlyHistory[Any]] = None, + ) -> None: if collection_history is None: collection_history = self._modified_event(state, dict_) @@ -234,8 +270,13 @@ class WriteOnlyAttributeImpl( self.sethasparent(attributes.instance_state(value), state, True) def fire_remove_event( - self, state, dict_, value, initiator, collection_history=None - ): + self, + state: InstanceState[Any], + dict_: _InstanceDict, + value: Any, + initiator: Optional[AttributeEventToken], + collection_history: Optional[WriteOnlyHistory[Any]] = None, + ) -> None: if collection_history is None: collection_history = self._modified_event(state, dict_) @@ -247,18 +288,20 @@ class WriteOnlyAttributeImpl( for fn in self.dispatch.remove: fn(state, value, initiator or self._remove_token) - def _modified_event(self, state, dict_): + def _modified_event( + self, state: InstanceState[Any], dict_: _InstanceDict + ) -> WriteOnlyHistory[Any]: if self.key not in state.committed_state: state.committed_state[self.key] = self.collection_history_cls( self, state, PassiveFlag.PASSIVE_NO_FETCH ) - state._modified_event(dict_, self, attributes.NEVER_SET) + state._modified_event(dict_, self, NEVER_SET) # this is a hack to allow the entities.ComparableEntity fixture # to work dict_[self.key] = True - return state.committed_state[self.key] + return state.committed_state[self.key] # type: ignore[no-any-return] def set( self, @@ -321,25 +364,38 @@ class WriteOnlyAttributeImpl( collection_history=collection_history, ) - def delete(self, *args, **kwargs): + def delete(self, *args: Any, **kwargs: Any) -> NoReturn: raise NotImplementedError() - def set_committed_value(self, state, dict_, value): + def set_committed_value( + self, state: InstanceState[Any], dict_: _InstanceDict, value: Any + ) -> NoReturn: raise NotImplementedError( "Dynamic attributes don't support collection population." ) - def get_history(self, state, dict_, passive=attributes.PASSIVE_NO_FETCH): + def get_history( + self, + state: InstanceState[Any], + dict_: _InstanceDict, + passive: PassiveFlag = PassiveFlag.PASSIVE_NO_FETCH, + ) -> attributes.History: c = self._get_collection_history(state, passive) return c.as_history() def get_all_pending( - self, state, dict_, passive=attributes.PASSIVE_NO_INITIALIZE - ): + self, + state: InstanceState[Any], + dict_: _InstanceDict, + passive: PassiveFlag = PassiveFlag.PASSIVE_NO_INITIALIZE, + ) -> List[Tuple[InstanceState[Any], Any]]: c = self._get_collection_history(state, passive) return [(attributes.instance_state(x), x) for x in c.all_items] - def _get_collection_history(self, state, passive): + def _get_collection_history( + self, state: InstanceState[Any], passive: PassiveFlag + ) -> WriteOnlyHistory[Any]: + c: WriteOnlyHistory[Any] if self.key in state.committed_state: c = state.committed_state[self.key] else: @@ -347,7 +403,7 @@ class WriteOnlyAttributeImpl( self, state, PassiveFlag.PASSIVE_NO_FETCH ) - if state.has_identity and (passive & attributes.INIT_OK): + if state.has_identity and (passive & PassiveFlag.INIT_OK): return self.collection_history_cls( self, state, passive, apply_to=c ) @@ -356,34 +412,34 @@ class WriteOnlyAttributeImpl( def append( self, - state, - dict_, - value, - initiator, - passive=attributes.PASSIVE_NO_FETCH, - ): + state: InstanceState[Any], + dict_: _InstanceDict, + value: Any, + initiator: Optional[AttributeEventToken], + passive: PassiveFlag = PassiveFlag.PASSIVE_NO_FETCH, + ) -> None: if initiator is not self: self.fire_append_event(state, dict_, value, initiator) def remove( self, - state, - dict_, - value, - initiator, - passive=attributes.PASSIVE_NO_FETCH, - ): + state: InstanceState[Any], + dict_: _InstanceDict, + value: Any, + initiator: Optional[AttributeEventToken], + passive: PassiveFlag = PassiveFlag.PASSIVE_NO_FETCH, + ) -> None: if initiator is not self: self.fire_remove_event(state, dict_, value, initiator) def pop( self, - state, - dict_, - value, - initiator, - passive=attributes.PASSIVE_NO_FETCH, - ): + state: InstanceState[Any], + dict_: _InstanceDict, + value: Any, + initiator: Optional[AttributeEventToken], + passive: PassiveFlag = PassiveFlag.PASSIVE_NO_FETCH, + ) -> None: self.remove(state, dict_, value, initiator, passive=passive) @@ -392,7 +448,7 @@ class WriteOnlyAttributeImpl( class WriteOnlyLoader(strategies.AbstractRelationshipLoader, log.Identified): impl_class = WriteOnlyAttributeImpl - def init_class_attribute(self, mapper): + def init_class_attribute(self, mapper: Mapper[Any]) -> None: self.is_class_level = True if not self.uselist or self.parent_property.direction not in ( interfaces.ONETOMANY, @@ -404,7 +460,7 @@ class WriteOnlyLoader(strategies.AbstractRelationshipLoader, log.Identified): "uselist=False." % self.parent_property ) - strategies._register_attribute( + strategies._register_attribute( # type: ignore[no-untyped-call] self.parent_property, mapper, useobject=True, @@ -418,19 +474,21 @@ class WriteOnlyLoader(strategies.AbstractRelationshipLoader, log.Identified): class DynamicCollectionAdapter: """simplified CollectionAdapter for internal API consistency""" - def __init__(self, data): + data: Collection[Any] + + def __init__(self, data: Collection[Any]): self.data = data - def __iter__(self): + def __iter__(self) -> Iterator[Any]: return iter(self.data) - def _reset_empty(self): + def _reset_empty(self) -> None: pass - def __len__(self): + def __len__(self) -> int: return len(self.data) - def __bool__(self): + def __bool__(self) -> bool: return True @@ -443,8 +501,14 @@ class AbstractCollectionWriter(Generic[_T]): if not TYPE_CHECKING: __slots__ = () - def __init__(self, attr, state): - self.instance = instance = state.obj() + instance: _T + _from_obj: Tuple[FromClause, ...] + + def __init__(self, attr: WriteOnlyAttributeImpl, state: InstanceState[_T]): + instance = state.obj() + if TYPE_CHECKING: + assert instance + self.instance = instance self.attr = attr mapper = object_mapper(instance) @@ -535,7 +599,7 @@ class WriteOnlyCollection(AbstractCollectionWriter[_T]): stmt = stmt.order_by(*self._order_by_clauses) return stmt - def insert(self) -> Insert[_T]: + def insert(self) -> Insert: """For one-to-many collections, produce a :class:`_dml.Insert` which will insert new rows in terms of this this instance-local :class:`_orm.WriteOnlyCollection`. @@ -561,7 +625,7 @@ class WriteOnlyCollection(AbstractCollectionWriter[_T]): "INSERT along with add_all()." ) - dict_ = {} + dict_: Dict[str, Any] = {} for l, r in prop.synchronize_pairs: fn = prop._get_attr_w_warn_on_none( @@ -575,14 +639,14 @@ class WriteOnlyCollection(AbstractCollectionWriter[_T]): return insert(self.attr.target_mapper).values(**dict_) - def update(self) -> Update[_T]: + def update(self) -> Update: """Produce a :class:`_dml.Update` which will refer to rows in terms of this instance-local :class:`_orm.WriteOnlyCollection`. """ return update(self.attr.target_mapper).where(*self._where_criteria) - def delete(self) -> Delete[_T]: + def delete(self) -> Delete: """Produce a :class:`_dml.Delete` which will refer to rows in terms of this instance-local :class:`_orm.WriteOnlyCollection`. diff --git a/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/__init__.cpython-310.pyc index 8a90129..839aa10 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/base.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/base.cpython-310.pyc index a9bb76b..91ec997 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/base.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/base.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/events.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/events.cpython-310.pyc index 1fd8ef3..499ce98 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/events.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/events.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/impl.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/impl.cpython-310.pyc index 8ffe186..0f5453d 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/impl.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/impl.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/pool/base.py b/venv/Lib/site-packages/sqlalchemy/pool/base.py index 7f542ae..90ed32e 100644 --- a/venv/Lib/site-packages/sqlalchemy/pool/base.py +++ b/venv/Lib/site-packages/sqlalchemy/pool/base.py @@ -323,13 +323,13 @@ class Pool(log.Identified, event.EventTarget): # mypy seems to get super confused assigning functions to # attributes - self._invoke_creator = self._should_wrap_creator(creator) # type: ignore # noqa: E501 + self._invoke_creator = self._should_wrap_creator(creator) @_creator.deleter def _creator(self) -> None: # needed for mock testing del self._creator_arg - del self._invoke_creator # type: ignore[misc] + del self._invoke_creator def _should_wrap_creator( self, creator: Union[_CreatorFnType, _CreatorWRecFnType] @@ -835,7 +835,7 @@ class _ConnectionRecord(ConnectionPoolEntry): # time and invalidation for the logic below to work reliably. if self.dbapi_connection is None: - self.info.clear() # type: ignore # our info is always present + self.info.clear() self.__connect() elif ( self.__pool._recycle > -1 @@ -863,7 +863,7 @@ class _ConnectionRecord(ConnectionPoolEntry): if recycle: self.__close(terminate=True) - self.info.clear() # type: ignore # our info is always present + self.info.clear() self.__connect() @@ -1040,7 +1040,9 @@ def _finalize_fairy( # test/engine/test_pool.py::PoolEventsTest::test_checkin_event_gc[True] # which actually started failing when pytest warnings plugin was # turned on, due to util.warn() above - fairy.dbapi_connection = fairy._connection_record = None # type: ignore + if fairy is not None: + fairy.dbapi_connection = None # type: ignore + fairy._connection_record = None del dbapi_connection del connection_record del fairy diff --git a/venv/Lib/site-packages/sqlalchemy/pool/events.py b/venv/Lib/site-packages/sqlalchemy/pool/events.py index 8366b7b..762418b 100644 --- a/venv/Lib/site-packages/sqlalchemy/pool/events.py +++ b/venv/Lib/site-packages/sqlalchemy/pool/events.py @@ -82,7 +82,7 @@ class PoolEvents(event.Events[Pool]): return None @classmethod - def _listen( # type: ignore[override] # would rather keep **kw + def _listen( cls, event_key: event._EventKey[Pool], **kw: Any, diff --git a/venv/Lib/site-packages/sqlalchemy/pool/impl.py b/venv/Lib/site-packages/sqlalchemy/pool/impl.py index 84849ed..af4f788 100644 --- a/venv/Lib/site-packages/sqlalchemy/pool/impl.py +++ b/venv/Lib/site-packages/sqlalchemy/pool/impl.py @@ -386,7 +386,7 @@ class SingletonThreadPool(Pool): def _do_return_conn(self, record: ConnectionPoolEntry) -> None: try: - del self._fairy.current # type: ignore + del self._fairy.current except AttributeError: pass diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/__init__.cpython-310.pyc index fc4443a..551a998 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_dml_constructors.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_dml_constructors.cpython-310.pyc index ebcfc7b..6e774c6 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_dml_constructors.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_dml_constructors.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_elements_constructors.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_elements_constructors.cpython-310.pyc index 9656ddf..bf1d829 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_elements_constructors.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_elements_constructors.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_orm_types.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_orm_types.cpython-310.pyc index 5285864..be2cec7 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_orm_types.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_orm_types.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_py_util.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_py_util.cpython-310.pyc index 9457749..a8b647f 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_py_util.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_py_util.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_selectable_constructors.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_selectable_constructors.cpython-310.pyc index 174703e..4469e9b 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_selectable_constructors.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_selectable_constructors.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_typing.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_typing.cpython-310.pyc index 047dac6..d27782a 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_typing.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_typing.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/annotation.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/annotation.cpython-310.pyc index da3ee36..c4f549b 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/annotation.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/annotation.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/base.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/base.cpython-310.pyc index cf166e1..ccdbbdd 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/base.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/base.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/cache_key.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/cache_key.cpython-310.pyc index 416eab5..3490d1e 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/cache_key.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/cache_key.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/coercions.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/coercions.cpython-310.pyc index 225c73f..f9f7727 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/coercions.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/coercions.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/compiler.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/compiler.cpython-310.pyc index 060bf66..5c91bfa 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/compiler.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/compiler.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/crud.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/crud.cpython-310.pyc index 9356501..c49c9f1 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/crud.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/crud.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/ddl.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/ddl.cpython-310.pyc index 4ae1a0f..6525bab 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/ddl.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/ddl.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/default_comparator.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/default_comparator.cpython-310.pyc index 38ffc24..f96dab7 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/default_comparator.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/default_comparator.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/dml.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/dml.cpython-310.pyc index 74061c4..a681a2e 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/dml.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/dml.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/elements.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/elements.cpython-310.pyc index 27107dd..0f1d609 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/elements.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/elements.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/events.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/events.cpython-310.pyc index ffcde64..213119b 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/events.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/events.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/expression.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/expression.cpython-310.pyc index 1fb7b39..8d218c1 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/expression.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/expression.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/functions.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/functions.cpython-310.pyc index c1455f6..6921474 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/functions.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/functions.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/lambdas.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/lambdas.cpython-310.pyc index a02afe4..6356838 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/lambdas.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/lambdas.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/naming.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/naming.cpython-310.pyc index dbb1b70..9fc8dc2 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/naming.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/naming.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/operators.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/operators.cpython-310.pyc index 1a41e03..e6443c8 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/operators.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/operators.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/roles.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/roles.cpython-310.pyc index 6928663..6a7598a 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/roles.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/roles.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/schema.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/schema.cpython-310.pyc index def936c..fecd655 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/schema.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/schema.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/selectable.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/selectable.cpython-310.pyc index 721f2f7..c528952 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/selectable.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/selectable.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/sqltypes.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/sqltypes.cpython-310.pyc index 2e2c31d..95fa42f 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/sqltypes.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/sqltypes.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/traversals.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/traversals.cpython-310.pyc index 1faa26a..4c84127 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/traversals.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/traversals.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/type_api.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/type_api.cpython-310.pyc index 928e2d1..987d22c 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/type_api.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/type_api.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/util.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/util.cpython-310.pyc index 9137100..87b2177 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/util.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/util.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/visitors.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/visitors.cpython-310.pyc index b996616..c964f81 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/visitors.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/visitors.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/_typing.py b/venv/Lib/site-packages/sqlalchemy/sql/_typing.py index a08a770..c9e1830 100644 --- a/venv/Lib/site-packages/sqlalchemy/sql/_typing.py +++ b/venv/Lib/site-packages/sqlalchemy/sql/_typing.py @@ -411,7 +411,7 @@ def Nullable( .. versionadded:: 2.0.20 """ - return val # type: ignore + return val @overload diff --git a/venv/Lib/site-packages/sqlalchemy/sql/annotation.py b/venv/Lib/site-packages/sqlalchemy/sql/annotation.py index 4ccde59..08ff47d 100644 --- a/venv/Lib/site-packages/sqlalchemy/sql/annotation.py +++ b/venv/Lib/site-packages/sqlalchemy/sql/annotation.py @@ -300,7 +300,7 @@ class Annotated(SupportsAnnotations): def _annotate(self, values: _AnnotationDict) -> Self: _values = self._annotations.union(values) - new = self._with_annotations(_values) # type: ignore + new = self._with_annotations(_values) return new def _with_annotations(self, values: _AnnotationDict) -> Self: diff --git a/venv/Lib/site-packages/sqlalchemy/sql/base.py b/venv/Lib/site-packages/sqlalchemy/sql/base.py index 913ab43..104c595 100644 --- a/venv/Lib/site-packages/sqlalchemy/sql/base.py +++ b/venv/Lib/site-packages/sqlalchemy/sql/base.py @@ -273,7 +273,7 @@ def _generative(fn: _Fn) -> _Fn: """ - @util.decorator # type: ignore + @util.decorator def _generative( fn: _Fn, self: _SelfGenerativeType, *args: Any, **kw: Any ) -> _SelfGenerativeType: @@ -299,7 +299,7 @@ def _exclusive_against(*names: str, **kw: Any) -> Callable[[_Fn], _Fn]: for name in names ] - @util.decorator # type: ignore + @util.decorator def check(fn, *args, **kw): # make pylance happy by not including "self" in the argument # list @@ -315,7 +315,7 @@ def _exclusive_against(*names: str, **kw: Any) -> Callable[[_Fn], _Fn]: raise exc.InvalidRequestError(msg) return fn(self, *args, **kw) - return check # type: ignore + return check def _clone(element, **kw): @@ -1176,6 +1176,7 @@ class Executable(roles.StatementRole): autoflush: bool = False, synchronize_session: SynchronizeSessionArgument = ..., dml_strategy: DMLStrategyArgument = ..., + render_nulls: bool = ..., is_delete_using: bool = ..., is_update_from: bool = ..., **opt: Any, diff --git a/venv/Lib/site-packages/sqlalchemy/sql/cache_key.py b/venv/Lib/site-packages/sqlalchemy/sql/cache_key.py index 8c21be1..500e3e4 100644 --- a/venv/Lib/site-packages/sqlalchemy/sql/cache_key.py +++ b/venv/Lib/site-packages/sqlalchemy/sql/cache_key.py @@ -546,6 +546,9 @@ class CacheKey(NamedTuple): def _apply_params_to_element( self, original_cache_key: CacheKey, target_element: ClauseElement ) -> ClauseElement: + if target_element._is_immutable: + return target_element + translate = { k.key: v.value for k, v in zip(original_cache_key.bindparams, self.bindparams) diff --git a/venv/Lib/site-packages/sqlalchemy/sql/compiler.py b/venv/Lib/site-packages/sqlalchemy/sql/compiler.py index 2304bde..cb6899c 100644 --- a/venv/Lib/site-packages/sqlalchemy/sql/compiler.py +++ b/venv/Lib/site-packages/sqlalchemy/sql/compiler.py @@ -2080,14 +2080,12 @@ class SQLCompiler(Compiled): if parameter in self.literal_execute_params: if escaped_name not in replacement_expressions: - value = parameters.pop(escaped_name) - - replacement_expressions[ - escaped_name - ] = self.render_literal_bindparam( - parameter, - render_literal_value=value, - ) + replacement_expressions[ + escaped_name + ] = self.render_literal_bindparam( + parameter, + render_literal_value=parameters.pop(escaped_name), + ) continue if parameter in self.post_compile_params: @@ -2742,6 +2740,7 @@ class SQLCompiler(Compiled): except KeyError as err: raise exc.UnsupportedCompilationError(self, operator_) from err else: + kw["_in_operator_expression"] = True return self._generate_delimited_list( clauselist.clauses, opstring, **kw ) @@ -3370,9 +3369,9 @@ class SQLCompiler(Compiled): def _generate_generic_binary( self, binary, opstring, eager_grouping=False, **kw ): - _in_binary = kw.get("_in_binary", False) + _in_operator_expression = kw.get("_in_operator_expression", False) - kw["_in_binary"] = True + kw["_in_operator_expression"] = True kw["_binary_op"] = binary.operator text = ( binary.left._compiler_dispatch( @@ -3384,7 +3383,7 @@ class SQLCompiler(Compiled): ) ) - if _in_binary and eager_grouping: + if _in_operator_expression and eager_grouping: text = "(%s)" % text return text @@ -3767,6 +3766,12 @@ class SQLCompiler(Compiled): """ + if value is None and not type_.should_evaluate_none: + # issue #10535 - handle NULL in the compiler without placing + # this onto each type, except for "evaluate None" types + # (e.g. JSON) + return self.process(elements.Null._instance()) + processor = type_._cached_literal_processor(self.dialect) if processor: try: @@ -4089,7 +4094,7 @@ class SQLCompiler(Compiled): from_linter.froms[cte._de_clone()] = cte_name if not is_new_cte and embedded_in_current_named_cte: - return self.preparer.format_alias(cte, cte_name) # type: ignore[no-any-return] # noqa: E501 + return self.preparer.format_alias(cte, cte_name) if cte_pre_alias_name: text = self.preparer.format_alias(cte, cte_pre_alias_name) @@ -6688,8 +6693,6 @@ class DDLCompiler(Compiled): text.append("NO MAXVALUE") if identity_options.cache is not None: text.append("CACHE %d" % identity_options.cache) - if identity_options.order is not None: - text.append("ORDER" if identity_options.order else "NO ORDER") if identity_options.cycle is not None: text.append("CYCLE" if identity_options.cycle else "NO CYCLE") return " ".join(text) diff --git a/venv/Lib/site-packages/sqlalchemy/sql/crud.py b/venv/Lib/site-packages/sqlalchemy/sql/crud.py index 4191069..e51403e 100644 --- a/venv/Lib/site-packages/sqlalchemy/sql/crud.py +++ b/venv/Lib/site-packages/sqlalchemy/sql/crud.py @@ -491,10 +491,10 @@ def _key_getters_for_crud_column( key: Union[ColumnClause[Any], str] ) -> Union[str, Tuple[str, str]]: str_key = c_key_role(key) - if hasattr(key, "table") and key.table in _et: # type: ignore + if hasattr(key, "table") and key.table in _et: return (key.table.name, str_key) # type: ignore else: - return str_key # type: ignore + return str_key def _getattr_col_key( col: ColumnClause[Any], @@ -513,7 +513,7 @@ def _key_getters_for_crud_column( return col.key else: - _column_as_key = functools.partial( # type: ignore + _column_as_key = functools.partial( coercions.expect_as_key, roles.DMLColumnRole ) _getattr_col_key = _col_bind_name = operator.attrgetter("key") # type: ignore # noqa: E501 @@ -647,6 +647,9 @@ def _scan_cols( compiler_implicit_returning = compiler.implicit_returning + # TODO - see TODO(return_defaults_columns) below + # cols_in_params = set() + for c in cols: # scan through every column in the target table @@ -672,6 +675,9 @@ def _scan_cols( kw, ) + # TODO - see TODO(return_defaults_columns) below + # cols_in_params.add(c) + elif isinsert: # no parameter is present and it's an insert. @@ -764,6 +770,19 @@ def _scan_cols( if c in remaining_supplemental ) + # TODO(return_defaults_columns): there can still be more columns in + # _return_defaults_columns in the case that they are from something like an + # aliased of the table. we can add them here, however this breaks other ORM + # things. so this is for another day. see + # test/orm/dml/test_update_delete_where.py -> test_update_from_alias + + # if stmt._return_defaults_columns: + # compiler_implicit_returning.extend( + # set(stmt._return_defaults_columns) + # .difference(compiler_implicit_returning) + # .difference(cols_in_params) + # ) + return (use_insertmanyvalues, use_sentinel_columns) @@ -1559,7 +1578,11 @@ def _get_returning_modifiers(compiler, stmt, compile_state, toplevel): should_implicit_return_defaults = ( implicit_returning and stmt._return_defaults ) - explicit_returning = should_implicit_return_defaults or stmt._returning + explicit_returning = ( + should_implicit_return_defaults + or stmt._returning + or stmt._supplemental_returning + ) use_insertmanyvalues = ( toplevel and compiler.for_executemany diff --git a/venv/Lib/site-packages/sqlalchemy/sql/ddl.py b/venv/Lib/site-packages/sqlalchemy/sql/ddl.py index 09cc54d..06bbcae 100644 --- a/venv/Lib/site-packages/sqlalchemy/sql/ddl.py +++ b/venv/Lib/site-packages/sqlalchemy/sql/ddl.py @@ -403,17 +403,14 @@ class DDL(ExecutableDDLElement): self.context = context or {} def __repr__(self): + parts = [repr(self.statement)] + if self.context: + parts.append(f"context={self.context}") + return "<%s@%s; %s>" % ( type(self).__name__, id(self), - ", ".join( - [repr(self.statement)] - + [ - "%s=%r" % (key, getattr(self, key)) - for key in ("on", "context") - if getattr(self, key) - ] - ), + ", ".join(parts), ) @@ -470,7 +467,7 @@ class CreateSchema(_CreateBase): __visit_name__ = "create_schema" - stringify_dialect = "default" # type: ignore + stringify_dialect = "default" def __init__( self, @@ -491,7 +488,7 @@ class DropSchema(_DropBase): __visit_name__ = "drop_schema" - stringify_dialect = "default" # type: ignore + stringify_dialect = "default" def __init__( self, diff --git a/venv/Lib/site-packages/sqlalchemy/sql/dml.py b/venv/Lib/site-packages/sqlalchemy/sql/dml.py index 4047ba4..4ca6ed3 100644 --- a/venv/Lib/site-packages/sqlalchemy/sql/dml.py +++ b/venv/Lib/site-packages/sqlalchemy/sql/dml.py @@ -211,7 +211,11 @@ class DMLState(CompileState): primary_table = all_tables[0] seen = {primary_table} - for crit in statement._where_criteria: + consider = statement._where_criteria + if self._dict_parameters: + consider += tuple(self._dict_parameters.values()) + + for crit in consider: for item in _from_objects(crit): if not seen.intersection(item._cloned_set): froms.append(item) @@ -563,7 +567,8 @@ class UpdateBase( 3. :meth:`.UpdateBase.return_defaults` can be called against any backend. Backends that don't support RETURNING will skip the usage - of the feature, rather than raising an exception. The return value + of the feature, rather than raising an exception, *unless* + ``supplemental_cols`` is passed. The return value of :attr:`_engine.CursorResult.returned_defaults` will be ``None`` for backends that don't support RETURNING or for which the target :class:`.Table` sets :paramref:`.Table.implicit_returning` to diff --git a/venv/Lib/site-packages/sqlalchemy/sql/elements.py b/venv/Lib/site-packages/sqlalchemy/sql/elements.py index a6b4c8a..90ee100 100644 --- a/venv/Lib/site-packages/sqlalchemy/sql/elements.py +++ b/venv/Lib/site-packages/sqlalchemy/sql/elements.py @@ -117,6 +117,7 @@ _NUMERIC = Union[float, Decimal] _NUMBER = Union[float, int, Decimal] _T = TypeVar("_T", bound="Any") +_T_co = TypeVar("_T_co", bound=Any, covariant=True) _OPT = TypeVar("_OPT", bound="Any") _NT = TypeVar("_NT", bound="_NUMERIC") @@ -804,7 +805,7 @@ class CompilerColumnElement( # SQLCoreOperations should be suiting the ExpressionElementRole # and ColumnsClauseRole. however the MRO issues become too elaborate # at the moment. -class SQLCoreOperations(Generic[_T], ColumnOperators, TypingOnly): +class SQLCoreOperations(Generic[_T_co], ColumnOperators, TypingOnly): __slots__ = () # annotations for comparison methods @@ -873,7 +874,7 @@ class SQLCoreOperations(Generic[_T], ColumnOperators, TypingOnly): def __or__(self, other: Any) -> BooleanClauseList: ... - def __invert__(self) -> ColumnElement[_T]: + def __invert__(self) -> ColumnElement[_T_co]: ... def __lt__(self, other: Any) -> ColumnElement[bool]: @@ -882,6 +883,13 @@ class SQLCoreOperations(Generic[_T], ColumnOperators, TypingOnly): def __le__(self, other: Any) -> ColumnElement[bool]: ... + # declare also that this class has an hash method otherwise + # it may be assumed to be None by type checkers since the + # object defines __eq__ and python sets it to None in that case: + # https://docs.python.org/3/reference/datamodel.html#object.__hash__ + def __hash__(self) -> int: + ... + def __eq__(self, other: Any) -> ColumnElement[bool]: # type: ignore[override] # noqa: E501 ... @@ -900,7 +908,7 @@ class SQLCoreOperations(Generic[_T], ColumnOperators, TypingOnly): def __ge__(self, other: Any) -> ColumnElement[bool]: ... - def __neg__(self) -> UnaryExpression[_T]: + def __neg__(self) -> UnaryExpression[_T_co]: ... def __contains__(self, other: Any) -> ColumnElement[bool]: @@ -961,7 +969,7 @@ class SQLCoreOperations(Generic[_T], ColumnOperators, TypingOnly): def bitwise_and(self, other: Any) -> BinaryExpression[Any]: ... - def bitwise_not(self) -> UnaryExpression[_T]: + def bitwise_not(self) -> UnaryExpression[_T_co]: ... def bitwise_lshift(self, other: Any) -> BinaryExpression[Any]: @@ -1074,22 +1082,22 @@ class SQLCoreOperations(Generic[_T], ColumnOperators, TypingOnly): ) -> ColumnElement[str]: ... - def desc(self) -> UnaryExpression[_T]: + def desc(self) -> UnaryExpression[_T_co]: ... - def asc(self) -> UnaryExpression[_T]: + def asc(self) -> UnaryExpression[_T_co]: ... - def nulls_first(self) -> UnaryExpression[_T]: + def nulls_first(self) -> UnaryExpression[_T_co]: ... - def nullsfirst(self) -> UnaryExpression[_T]: + def nullsfirst(self) -> UnaryExpression[_T_co]: ... - def nulls_last(self) -> UnaryExpression[_T]: + def nulls_last(self) -> UnaryExpression[_T_co]: ... - def nullslast(self) -> UnaryExpression[_T]: + def nullslast(self) -> UnaryExpression[_T_co]: ... def collate(self, collation: str) -> CollationClause: @@ -1100,7 +1108,7 @@ class SQLCoreOperations(Generic[_T], ColumnOperators, TypingOnly): ) -> BinaryExpression[bool]: ... - def distinct(self: _SQO[_T]) -> UnaryExpression[_T]: + def distinct(self: _SQO[_T_co]) -> UnaryExpression[_T_co]: ... def any_(self) -> CollectionAggregate[Any]: @@ -1128,19 +1136,11 @@ class SQLCoreOperations(Generic[_T], ColumnOperators, TypingOnly): ) -> ColumnElement[str]: ... - @overload - def __add__(self, other: Any) -> ColumnElement[Any]: - ... - def __add__(self, other: Any) -> ColumnElement[Any]: ... @overload - def __radd__(self: _SQO[_NT], other: Any) -> ColumnElement[_NT]: - ... - - @overload - def __radd__(self: _SQO[int], other: Any) -> ColumnElement[int]: + def __radd__(self: _SQO[_NMT], other: Any) -> ColumnElement[_NMT]: ... @overload @@ -1282,7 +1282,7 @@ class SQLCoreOperations(Generic[_T], ColumnOperators, TypingOnly): class SQLColumnExpression( - SQLCoreOperations[_T], roles.ExpressionElementRole[_T], TypingOnly + SQLCoreOperations[_T_co], roles.ExpressionElementRole[_T_co], TypingOnly ): """A type that may be used to indicate any SQL column element or object that acts in place of one. @@ -1613,12 +1613,12 @@ class ColumnElement( *other: Any, **kwargs: Any, ) -> ColumnElement[Any]: - return op(self.comparator, *other, **kwargs) # type: ignore[return-value,no-any-return] # noqa: E501 + return op(self.comparator, *other, **kwargs) # type: ignore[no-any-return] # noqa: E501 def reverse_operate( self, op: operators.OperatorType, other: Any, **kwargs: Any ) -> ColumnElement[Any]: - return op(other, self.comparator, **kwargs) # type: ignore[return-value,no-any-return] # noqa: E501 + return op(other, self.comparator, **kwargs) # type: ignore[no-any-return] # noqa: E501 def _bind_param( self, @@ -3132,7 +3132,7 @@ class BooleanClauseList(ExpressionClauseList[bool]): }, *args)'.""", version="1.4", ) - return cls._construct_raw(operator) # type: ignore[no-any-return] + return cls._construct_raw(operator) lcc, convert_clauses = cls._process_clauses_for_boolean( operator, @@ -3162,7 +3162,7 @@ class BooleanClauseList(ExpressionClauseList[bool]): assert lcc # just one element. return it as a single boolean element, # not a list and discard the operator. - return convert_clauses[0] # type: ignore[no-any-return] # noqa: E501 + return convert_clauses[0] @classmethod def _construct_for_whereclause( @@ -4182,7 +4182,7 @@ class Over(ColumnElement[_T]): element: ColumnElement[_T] """The underlying expression object to which this :class:`.Over` - object refers towards.""" + object refers.""" range_: Optional[typing_Tuple[int, int]] diff --git a/venv/Lib/site-packages/sqlalchemy/sql/functions.py b/venv/Lib/site-packages/sqlalchemy/sql/functions.py index 30e280c..fc23e9d 100644 --- a/venv/Lib/site-packages/sqlalchemy/sql/functions.py +++ b/venv/Lib/site-packages/sqlalchemy/sql/functions.py @@ -916,6 +916,10 @@ class _FunctionGenerator: # code within this block is **programmatically, # statically generated** by tools/generate_sql_functions.py + @property + def aggregate_strings(self) -> Type[aggregate_strings]: + ... + @property def ansifunction(self) -> Type[AnsiFunction[Any]]: ... @@ -1795,3 +1799,30 @@ class grouping_sets(GenericFunction[_T]): """ _has_args = True inherit_cache = True + + +class aggregate_strings(GenericFunction[str]): + """Implement a generic string aggregation function. + + This function will concatenate non-null values into a string and + separate the values by a delimiter. + + This function is compiled on a per-backend basis, into functions + such as ``group_concat()``, ``string_agg()``, or ``LISTAGG()``. + + e.g. Example usage with delimiter '.':: + + stmt = select(func.aggregate_strings(table.c.str_col, ".")) + + The return type of this function is :class:`.String`. + + .. versionadded: 2.0.21 + + """ + + type = sqltypes.String() + _has_args = True + inherit_cache = True + + def __init__(self, clause, separator): + super().__init__(clause, separator) diff --git a/venv/Lib/site-packages/sqlalchemy/sql/lambdas.py b/venv/Lib/site-packages/sqlalchemy/sql/lambdas.py index 455649c..7aef605 100644 --- a/venv/Lib/site-packages/sqlalchemy/sql/lambdas.py +++ b/venv/Lib/site-packages/sqlalchemy/sql/lambdas.py @@ -718,7 +718,7 @@ class LinkedLambdaElement(StatementLambdaElement): opts: Union[Type[LambdaOptions], LambdaOptions], ): self.opts = opts - self.fn = fn # type: ignore[assignment] + self.fn = fn self.parent_lambda = parent_lambda self.tracker_key = parent_lambda.tracker_key + (fn.__code__,) diff --git a/venv/Lib/site-packages/sqlalchemy/sql/operators.py b/venv/Lib/site-packages/sqlalchemy/sql/operators.py index dbd593e..6402d0f 100644 --- a/venv/Lib/site-packages/sqlalchemy/sql/operators.py +++ b/venv/Lib/site-packages/sqlalchemy/sql/operators.py @@ -307,7 +307,7 @@ class Operators: ) def against(other: Any) -> Operators: - return operator(self, other) # type: ignore + return operator(self, other) return against @@ -569,8 +569,16 @@ class ColumnOperators(Operators): """ return self.operate(le, other) - # TODO: not sure why we have this - __hash__ = Operators.__hash__ # type: ignore + # ColumnOperators defines an __eq__ so it must explicitly declare also + # an hash or it's set to None by python: + # https://docs.python.org/3/reference/datamodel.html#object.__hash__ + if TYPE_CHECKING: + + def __hash__(self) -> int: + ... + + else: + __hash__ = Operators.__hash__ def __eq__(self, other: Any) -> ColumnOperators: # type: ignore[override] """Implement the ``==`` operator. @@ -2533,8 +2541,8 @@ _PRECEDENCE: Dict[OperatorType, int] = { bitwise_and_op: 7, bitwise_lshift_op: 7, bitwise_rshift_op: 7, - concat_op: 6, filter_op: 6, + concat_op: 5, match_op: 5, not_match_op: 5, regexp_match_op: 5, diff --git a/venv/Lib/site-packages/sqlalchemy/sql/roles.py b/venv/Lib/site-packages/sqlalchemy/sql/roles.py index f8aac70..6f29922 100644 --- a/venv/Lib/site-packages/sqlalchemy/sql/roles.py +++ b/venv/Lib/site-packages/sqlalchemy/sql/roles.py @@ -23,6 +23,7 @@ if TYPE_CHECKING: from .selectable import Subquery _T = TypeVar("_T", bound=Any) +_T_co = TypeVar("_T_co", bound=Any, covariant=True) class SQLRole: @@ -110,7 +111,7 @@ class ColumnsClauseRole(AllowsLambdaRole, UsesInspection, ColumnListRole): raise NotImplementedError() -class TypedColumnsClauseRole(Generic[_T], SQLRole): +class TypedColumnsClauseRole(Generic[_T_co], SQLRole): """element-typed form of ColumnsClauseRole""" __slots__ = () @@ -162,7 +163,7 @@ class WhereHavingRole(OnClauseRole): _role_name = "SQL expression for WHERE/HAVING role" -class ExpressionElementRole(TypedColumnsClauseRole[_T]): +class ExpressionElementRole(TypedColumnsClauseRole[_T_co]): # note when using generics for ExpressionElementRole, # the generic type needs to be in # sqlalchemy.sql.coercions._impl_lookup mapping also. diff --git a/venv/Lib/site-packages/sqlalchemy/sql/schema.py b/venv/Lib/site-packages/sqlalchemy/sql/schema.py index 008ae2c..c464d7e 100644 --- a/venv/Lib/site-packages/sqlalchemy/sql/schema.py +++ b/venv/Lib/site-packages/sqlalchemy/sql/schema.py @@ -50,7 +50,6 @@ from typing import overload from typing import Sequence as _typing_Sequence from typing import Set from typing import Tuple -from typing import Type from typing import TYPE_CHECKING from typing import TypeVar from typing import Union @@ -1433,7 +1432,7 @@ class Table( elif schema is None: actual_schema = metadata.schema else: - actual_schema = schema # type: ignore + actual_schema = schema key = _get_table_key(name, actual_schema) if key in metadata.tables: util.warn( @@ -2452,14 +2451,8 @@ class Column(DialectKWArgs, SchemaItem, ColumnClause[_T]): # Constraint objects plus non-constraint-bound ForeignKey objects args: List[SchemaItem] = [ - c._copy(**kw) - for c in self.constraints - if not c._type_bound # type: ignore - ] + [ - c._copy(**kw) # type: ignore - for c in self.foreign_keys - if not c.constraint - ] + c._copy(**kw) for c in self.constraints if not c._type_bound + ] + [c._copy(**kw) for c in self.foreign_keys if not c.constraint] # ticket #5276 column_kwargs = {} @@ -2529,6 +2522,15 @@ class Column(DialectKWArgs, SchemaItem, ColumnClause[_T]): if self.primary_key: other.primary_key = True + if self.autoincrement != "auto" and other.autoincrement == "auto": + other.autoincrement = self.autoincrement + + if self.system: + other.system = self.system + + if self.info: + other.info.update(self.info) + type_ = self.type if not type_._isnull and other.type._isnull: if isinstance(type_, SchemaEventTarget): @@ -2574,6 +2576,12 @@ class Column(DialectKWArgs, SchemaItem, ColumnClause[_T]): if self.index and not other.index: other.index = True + if self.doc and other.doc is None: + other.doc = self.doc + + if self.comment and other.comment is None: + other.comment = self.comment + if self.unique and not other.unique: other.unique = True @@ -3973,7 +3981,7 @@ class FetchedValue(SchemaEventTarget): if for_update == self.for_update: return self else: - return self._clone(for_update) # type: ignore + return self._clone(for_update) def _copy(self) -> FetchedValue: return FetchedValue(self.for_update) @@ -4151,7 +4159,7 @@ class Constraint(DialectKWArgs, HasConditionalDDL, SchemaItem): "and will be removed in a future release.", ) def copy(self, **kw: Any) -> Self: - return self._copy(**kw) # type: ignore + return self._copy(**kw) def _copy(self, **kw: Any) -> Self: raise NotImplementedError() @@ -5286,35 +5294,31 @@ class Index( ) -_AllConstraints = Union[ - Index, - UniqueConstraint, - CheckConstraint, - ForeignKeyConstraint, - PrimaryKeyConstraint, -] - -_NamingSchemaCallable = Callable[[_AllConstraints, Table], str] +_NamingSchemaCallable = Callable[[Constraint, Table], str] +_NamingSchemaDirective = Union[str, _NamingSchemaCallable] class _NamingSchemaTD(TypedDict, total=False): - fk: Union[str, _NamingSchemaCallable] - pk: Union[str, _NamingSchemaCallable] - ix: Union[str, _NamingSchemaCallable] - ck: Union[str, _NamingSchemaCallable] - uq: Union[str, _NamingSchemaCallable] + fk: _NamingSchemaDirective + pk: _NamingSchemaDirective + ix: _NamingSchemaDirective + ck: _NamingSchemaDirective + uq: _NamingSchemaDirective _NamingSchemaParameter = Union[ + # it seems like the TypedDict here is useful for pylance typeahead, + # and not much else _NamingSchemaTD, - Mapping[ - Union[Type[_AllConstraints], str], Union[str, _NamingSchemaCallable] - ], + # there is no form that allows Union[Type[Any], str] to work in all + # cases, including breaking out Mapping[] entries for each combination + # even, therefore keys must be `Any` (see #10264) + Mapping[Any, _NamingSchemaDirective], ] DEFAULT_NAMING_CONVENTION: _NamingSchemaParameter = util.immutabledict( - {"ix": "ix_%(column_0_label)s"} # type: ignore[arg-type] + {"ix": "ix_%(column_0_label)s"} ) @@ -5522,7 +5526,7 @@ class MetaData(HasSchemaAttr): def _remove_table(self, name: str, schema: Optional[str]) -> None: key = _get_table_key(name, schema) - removed = dict.pop(self.tables, key, None) # type: ignore + removed = dict.pop(self.tables, key, None) if removed is not None: for fk in removed.foreign_keys: fk._remove_from_metadata(self) @@ -5622,7 +5626,9 @@ class MetaData(HasSchemaAttr): bind: Union[Engine, Connection], schema: Optional[str] = None, views: bool = False, - only: Optional[_typing_Sequence[str]] = None, + only: Union[ + _typing_Sequence[str], Callable[[str, MetaData], bool], None + ] = None, extend_existing: bool = False, autoload_replace: bool = True, resolve_fks: bool = True, diff --git a/venv/Lib/site-packages/sqlalchemy/sql/selectable.py b/venv/Lib/site-packages/sqlalchemy/sql/selectable.py index b13c532..91b939e 100644 --- a/venv/Lib/site-packages/sqlalchemy/sql/selectable.py +++ b/venv/Lib/site-packages/sqlalchemy/sql/selectable.py @@ -323,9 +323,7 @@ class Selectable(ReturnsRows): object, returning a copy of this :class:`_expression.FromClause`. """ - return util.preloaded.sql_util.ClauseAdapter(alias).traverse( # type: ignore # noqa: E501 - self - ) + return util.preloaded.sql_util.ClauseAdapter(alias).traverse(self) def corresponding_column( self, column: KeyedColumnElement[Any], require_embedded: bool = False @@ -1420,7 +1418,7 @@ class Join(roles.DMLTableRole, FromClause): continue for fk in sorted( b.foreign_keys, - key=lambda fk: fk.parent._creation_order, # type: ignore + key=lambda fk: fk.parent._creation_order, ): if ( consider_as_foreign_keys is not None @@ -1441,7 +1439,7 @@ class Join(roles.DMLTableRole, FromClause): if left is not b: for fk in sorted( left.foreign_keys, - key=lambda fk: fk.parent._creation_order, # type: ignore + key=lambda fk: fk.parent._creation_order, ): if ( consider_as_foreign_keys is not None @@ -2436,7 +2434,7 @@ class HasCTE(roles.HasCTERole, SelectsRows): SELECT t.c1, t.c2 FROM t - Above, the "anon_1" CTE is not referred towards in the SELECT + Above, the "anon_1" CTE is not referenced in the SELECT statement, however still accomplishes the task of running an INSERT statement. @@ -3151,7 +3149,7 @@ class Values(roles.InElementRole, Generative, LateralFromClause): __visit_name__ = "values" - _data: Tuple[List[Tuple[Any, ...]], ...] = () + _data: Tuple[Sequence[Tuple[Any, ...]], ...] = () _unnamed: bool _traverse_internals: _TraverseInternalsType = [ @@ -3169,6 +3167,7 @@ class Values(roles.InElementRole, Generative, LateralFromClause): ): super().__init__() self._column_args = columns + if name is None: self._unnamed = True self.name = _anonymous_label.safe_construct(id(self), "anon") @@ -3234,7 +3233,7 @@ class Values(roles.InElementRole, Generative, LateralFromClause): return self @_generative - def data(self, values: List[Tuple[Any, ...]]) -> Self: + def data(self, values: Sequence[Tuple[Any, ...]]) -> Self: """Return a new :class:`_expression.Values` construct, adding the given data to the data list. @@ -3262,6 +3261,13 @@ class Values(roles.InElementRole, Generative, LateralFromClause): def _populate_column_collection(self) -> None: for c in self._column_args: + if c.table is not None and c.table is not self: + _, c = c._make_proxy(self) + else: + # if the column was used in other contexts, ensure + # no memoizations of other FROM clauses. + # see test_values.py -> test_auto_proxy_select_direct_col + c._reset_memoizations() self._columns.add(c) c.table = self @@ -3294,7 +3300,7 @@ class ScalarValues(roles.InElementRole, GroupedElement, ColumnElement[Any]): def __init__( self, columns: Sequence[ColumnClause[Any]], - data: Tuple[List[Tuple[Any, ...]], ...], + data: Tuple[Sequence[Tuple[Any, ...]], ...], literal_binds: bool, ): super().__init__() @@ -4744,7 +4750,7 @@ class SelectState(util.MemoizedSlots, CompileState): Dict[str, ColumnElement[Any]], ]: with_cols: Dict[str, ColumnElement[Any]] = { - c._tq_label or c.key: c # type: ignore + c._tq_label or c.key: c for c in self.statement._all_selected_columns if c._allow_label_resolve } @@ -5012,7 +5018,7 @@ class _MemoizedSelectEntities( c.__dict__ = {k: v for k, v in self.__dict__.items()} c._is_clone_of = self.__dict__.get("_is_clone_of", self) - return c # type: ignore + return c @classmethod def _generate_for_statement(cls, select_stmt: Select[Any]) -> None: @@ -6720,7 +6726,7 @@ class Exists(UnaryExpression[bool]): ) return e - def select_from(self, *froms: FromClause) -> Self: + def select_from(self, *froms: _FromClauseArgument) -> Self: """Return a new :class:`_expression.Exists` construct, applying the given expression to the :meth:`_expression.Select.select_from` diff --git a/venv/Lib/site-packages/sqlalchemy/sql/sqltypes.py b/venv/Lib/site-packages/sqlalchemy/sql/sqltypes.py index 2ed4c8b..ddee776 100644 --- a/venv/Lib/site-packages/sqlalchemy/sql/sqltypes.py +++ b/venv/Lib/site-packages/sqlalchemy/sql/sqltypes.py @@ -608,14 +608,21 @@ class Numeric(HasExpressionLookup, TypeEngine[_N]): class Float(Numeric[_N]): - """Type representing floating point types, such as ``FLOAT`` or ``REAL``. This type returns Python ``float`` objects by default, unless the - :paramref:`.Float.asdecimal` flag is set to True, in which case they + :paramref:`.Float.asdecimal` flag is set to ``True``, in which case they are coerced to ``decimal.Decimal`` objects. - + When a :paramref:`.Float.precision` is not provided in a + :class:`_types.Float` type some backend may compile this type as + an 8 bytes / 64 bit float datatype. To use a 4 bytes / 32 bit float + datatype a precision <= 24 can usually be provided or the + :class:`_types.REAL` type can be used. + This is known to be the case in the PostgreSQL and MSSQL dialects + that render the type as ``FLOAT`` that's in both an alias of + ``DOUBLE PRECISION``. Other third party dialects may have similar + behavior. """ __visit_name__ = "float" @@ -733,16 +740,12 @@ class _RenderISO8601NoT: if _portion is not None: def process(value): - if value is not None: - value = f"""'{value.isoformat().split("T")[_portion]}'""" - return value + return f"""'{value.isoformat().split("T")[_portion]}'""" else: def process(value): - if value is not None: - value = f"""'{value.isoformat().replace("T", " ")}'""" - return value + return f"""'{value.isoformat().replace("T", " ")}'""" return process @@ -1395,7 +1398,10 @@ class Enum(String, SchemaType, Emulated, TypeEngine[Union[str, enum.Enum]]): compliant enumerated type, which should then return a list of string values to be persisted. This allows for alternate usages such as using the string value of an enum to be persisted to the database - instead of its name. + instead of its name. The callable must return the values to be + persisted in the same order as iterating through the Enum's + ``__member__`` attribute. For example + ``lambda x: [i.value for i in x]``. .. versionadded:: 1.2.3 @@ -1451,7 +1457,11 @@ class Enum(String, SchemaType, Emulated, TypeEngine[Union[str, enum.Enum]]): self._default_length = length = 0 if length_arg is not NO_ARG: - if not _disable_warnings and length_arg < length: + if ( + not _disable_warnings + and length_arg is not None + and length_arg < length + ): raise ValueError( "When provided, length must be larger or equal" " than the length of the longest enum value. %s < %s" @@ -1658,14 +1668,14 @@ class Enum(String, SchemaType, Emulated, TypeEngine[Union[str, enum.Enum]]): ) def as_generic(self, allow_nulltype=False): - if hasattr(self, "enums"): + try: args = self.enums - else: + except AttributeError: raise NotImplementedError( "TypeEngine.as_generic() heuristic " "is undefined for types that inherit Enum but do not have " "an `enums` attribute." - ) + ) from None return util.constructor_copy( self, self._generic_type_affinity, *args, _disable_warnings=True @@ -2038,8 +2048,8 @@ class Interval(Emulated, _AbstractInterval, TypeDecorator[dt.timedelta]): """A type for ``datetime.timedelta()`` objects. The Interval type deals with ``datetime.timedelta`` objects. In - PostgreSQL, the native ``INTERVAL`` type is used; for others, the - value is stored as a date which is relative to the "epoch" + PostgreSQL and Oracle, the native ``INTERVAL`` type is used; for others, + the value is stored as a date which is relative to the "epoch" (Jan. 1, 1970). Note that the ``Interval`` type does not currently provide date arithmetic @@ -2470,6 +2480,9 @@ class JSON(Indexable, TypeEngine[Any]): value = int_processor(value) elif string_processor and isinstance(value, str): value = string_processor(value) + else: + raise NotImplementedError() + return value return process @@ -3692,28 +3705,20 @@ class Uuid(Emulated, TypeEngine[_UUID_RETURN]): if not self.as_uuid: def process(value): - if value is not None: - value = ( - f"""'{value.replace("-", "").replace("'", "''")}'""" - ) - return value + return f"""'{value.replace("-", "").replace("'", "''")}'""" return process else: if character_based_uuid: def process(value): - if value is not None: - value = f"""'{value.hex}'""" - return value + return f"""'{value.hex}'""" return process else: def process(value): - if value is not None: - value = f"""'{str(value).replace("'", "''")}'""" - return value + return f"""'{str(value).replace("'", "''")}'""" return process diff --git a/venv/Lib/site-packages/sqlalchemy/sql/traversals.py b/venv/Lib/site-packages/sqlalchemy/sql/traversals.py index 5c782f1..5758dff 100644 --- a/venv/Lib/site-packages/sqlalchemy/sql/traversals.py +++ b/venv/Lib/site-packages/sqlalchemy/sql/traversals.py @@ -56,15 +56,15 @@ def _preconfigure_traversals(target_hierarchy: Type[Any]) -> None: if hasattr(cls, "_generate_cache_attrs") and hasattr( cls, "_traverse_internals" ): - cls._generate_cache_attrs() # type: ignore + cls._generate_cache_attrs() _copy_internals.generate_dispatch( - cls, # type: ignore - cls._traverse_internals, # type: ignore + cls, + cls._traverse_internals, "_generated_copy_internals_traversal", ) _get_children.generate_dispatch( - cls, # type: ignore - cls._traverse_internals, # type: ignore + cls, + cls._traverse_internals, "_generated_get_children_traversal", ) diff --git a/venv/Lib/site-packages/sqlalchemy/sql/type_api.py b/venv/Lib/site-packages/sqlalchemy/sql/type_api.py index 2be3972..9cf4872 100644 --- a/venv/Lib/site-packages/sqlalchemy/sql/type_api.py +++ b/venv/Lib/site-packages/sqlalchemy/sql/type_api.py @@ -191,7 +191,7 @@ class TypeEngine(Visitable, Generic[_T]): op_fn, addtl_kw = default_comparator.operator_lookup[op.__name__] if kwargs: addtl_kw = addtl_kw.union(kwargs) - return op_fn(self.expr, op, *other, **addtl_kw) # type: ignore + return op_fn(self.expr, op, *other, **addtl_kw) @util.preload_module("sqlalchemy.sql.default_comparator") def reverse_operate( @@ -201,7 +201,7 @@ class TypeEngine(Visitable, Generic[_T]): op_fn, addtl_kw = default_comparator.operator_lookup[op.__name__] if kwargs: addtl_kw = addtl_kw.union(kwargs) - return op_fn(self.expr, op, other, reverse=True, **addtl_kw) # type: ignore # noqa: E501 + return op_fn(self.expr, op, other, reverse=True, **addtl_kw) def _adapt_expression( self, @@ -354,33 +354,6 @@ class TypeEngine(Visitable, Generic[_T]): def copy(self, **kw: Any) -> Self: return self.adapt(self.__class__) - def compare_against_backend( - self, dialect: Dialect, conn_type: TypeEngine[Any] - ) -> Optional[bool]: - """Compare this type against the given backend type. - - This function is currently not implemented for SQLAlchemy - types, and for all built in types will return ``None``. However, - it can be implemented by a user-defined type - where it can be consumed by schema comparison tools such as - Alembic autogenerate. - - A future release of SQLAlchemy will potentially implement this method - for builtin types as well. - - The function should return True if this type is equivalent to the - given type; the type is typically reflected from the database - so should be database specific. The dialect in use is also - passed. It can also return False to assert that the type is - not equivalent. - - :param dialect: a :class:`.Dialect` that is involved in the comparison. - - :param conn_type: the type object reflected from the backend. - - """ - return None - def copy_value(self, value: Any) -> Any: return value @@ -816,7 +789,7 @@ class TypeEngine(Visitable, Generic[_T]): best_uppercase = None if not isinstance(self, TypeEngine): - return self.__class__ # type: ignore # mypy bug? + return self.__class__ for t in self.__class__.__mro__: if ( @@ -2323,7 +2296,7 @@ def to_instance( return NULLTYPE if callable(typeobj): - return typeobj(*arg, **kw) # type: ignore # for pyright + return typeobj(*arg, **kw) else: return typeobj diff --git a/venv/Lib/site-packages/sqlalchemy/sql/util.py b/venv/Lib/site-packages/sqlalchemy/sql/util.py index 0a50197..28480a5 100644 --- a/venv/Lib/site-packages/sqlalchemy/sql/util.py +++ b/venv/Lib/site-packages/sqlalchemy/sql/util.py @@ -1440,7 +1440,7 @@ def _offset_or_limit_clause_asint_if_possible( if clause is None: return None if hasattr(clause, "_limit_offset_value"): - value = clause._limit_offset_value # type: ignore + value = clause._limit_offset_value return util.asint(value) else: return clause @@ -1489,13 +1489,11 @@ def _make_slice( offset_clause = 0 if start != 0: - offset_clause = offset_clause + start # type: ignore + offset_clause = offset_clause + start if offset_clause == 0: offset_clause = None else: - offset_clause = _offset_or_limit_clause( - offset_clause # type: ignore - ) + offset_clause = _offset_or_limit_clause(offset_clause) - return limit_clause, offset_clause # type: ignore + return limit_clause, offset_clause diff --git a/venv/Lib/site-packages/sqlalchemy/sql/visitors.py b/venv/Lib/site-packages/sqlalchemy/sql/visitors.py index 69dc6a8..cccebe6 100644 --- a/venv/Lib/site-packages/sqlalchemy/sql/visitors.py +++ b/venv/Lib/site-packages/sqlalchemy/sql/visitors.py @@ -146,7 +146,7 @@ class Visitable: cls._original_compiler_dispatch ) = _compiler_dispatch - def __class_getitem__(cls, key: str) -> Any: + def __class_getitem__(cls, key: Any) -> Any: # allow generic classes in py3.9+ return cls @@ -161,16 +161,17 @@ class InternalTraversal(Enum): the ``_traverse_internals`` collection. Such as, the :class:`.Case` object defines ``_traverse_internals`` as :: - _traverse_internals = [ - ("value", InternalTraversal.dp_clauseelement), - ("whens", InternalTraversal.dp_clauseelement_tuples), - ("else_", InternalTraversal.dp_clauseelement), - ] + class Case(ColumnElement[_T]): + _traverse_internals = [ + ("value", InternalTraversal.dp_clauseelement), + ("whens", InternalTraversal.dp_clauseelement_tuples), + ("else_", InternalTraversal.dp_clauseelement), + ] Above, the :class:`.Case` class indicates its internal state as the attributes named ``value``, ``whens``, and ``else_``. They each link to an :class:`.InternalTraversal` method which indicates the type - of datastructure referred towards. + of datastructure to which each attribute refers. Using the ``_traverse_internals`` structure, objects of type :class:`.InternalTraversible` will have the following methods automatically diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/__init__.cpython-310.pyc index 591f4ef..41fc15f 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/assertions.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/assertions.cpython-310.pyc index b62654c..995ae09 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/assertions.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/assertions.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/assertsql.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/assertsql.cpython-310.pyc index a5bcc6a..be975a4 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/assertsql.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/assertsql.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/asyncio.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/asyncio.cpython-310.pyc index 1035864..31929b5 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/asyncio.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/asyncio.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/config.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/config.cpython-310.pyc index 14c326b..a6dd667 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/config.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/config.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/engines.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/engines.cpython-310.pyc index 61797e6..29a9378 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/engines.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/engines.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/entities.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/entities.cpython-310.pyc index 3d5cfb9..8a44f80 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/entities.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/entities.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/exclusions.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/exclusions.cpython-310.pyc index db10e27..88503d4 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/exclusions.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/exclusions.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/pickleable.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/pickleable.cpython-310.pyc index 13cbd49..5f36973 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/pickleable.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/pickleable.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/profiling.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/profiling.cpython-310.pyc index a12ae59..34800e7 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/profiling.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/profiling.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/provision.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/provision.cpython-310.pyc index f971163..620dab7 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/provision.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/provision.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/requirements.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/requirements.cpython-310.pyc index 89f006e..ef8f490 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/requirements.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/requirements.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/schema.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/schema.cpython-310.pyc index 99eb0c2..34ff813 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/schema.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/schema.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/util.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/util.cpython-310.pyc index 54e4357..0666dd9 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/util.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/util.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/warnings.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/warnings.cpython-310.pyc index 517e9b7..ca14223 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/warnings.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/warnings.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/assertsql.py b/venv/Lib/site-packages/sqlalchemy/testing/assertsql.py index 85e4246..3865497 100644 --- a/venv/Lib/site-packages/sqlalchemy/testing/assertsql.py +++ b/venv/Lib/site-packages/sqlalchemy/testing/assertsql.py @@ -50,6 +50,7 @@ class CursorSQL(SQLMatchRule): if self.statement != stmt.statement or ( self.params is not None and self.params != stmt.parameters ): + self.consume_statement = True self.errormessage = ( "Testing for exact SQL %s parameters %s received %s %s" % ( diff --git a/venv/Lib/site-packages/sqlalchemy/testing/config.py b/venv/Lib/site-packages/sqlalchemy/testing/config.py index b8f0336..8430203 100644 --- a/venv/Lib/site-packages/sqlalchemy/testing/config.py +++ b/venv/Lib/site-packages/sqlalchemy/testing/config.py @@ -22,10 +22,15 @@ from typing import Tuple from typing import TypeVar from typing import Union +from . import mock +from . import requirements as _requirements from .util import fail from .. import util -requirements = None +# default requirements; this is replaced by plugin_base when pytest +# is run +requirements = _requirements.SuiteRequirements() + db = None db_url = None db_opts = None @@ -42,7 +47,42 @@ if typing.TYPE_CHECKING: _fixture_functions: FixtureFunctions else: - _fixture_functions = None # installed by plugin_base + + class _NullFixtureFunctions: + def _null_decorator(self): + def go(fn): + return fn + + return go + + def skip_test_exception(self, *arg, **kw): + return Exception() + + @property + def add_to_marker(self): + return mock.Mock() + + def mark_base_test_class(self): + return self._null_decorator() + + def combinations(self, *arg_sets, **kw): + return self._null_decorator() + + def param_ident(self, *parameters): + return self._null_decorator() + + def fixture(self, *arg, **kw): + return self._null_decorator() + + def get_current_test_name(self): + return None + + def async_test(self, fn): + return fn + + # default fixture functions; these are replaced by plugin_base when + # pytest runs + _fixture_functions = _NullFixtureFunctions() _FN = TypeVar("_FN", bound=Callable[..., Any]) @@ -121,10 +161,7 @@ def combinations( ) -def combinations_list( - arg_iterable: Iterable[Tuple[Any,]], - **kw, -): +def combinations_list(arg_iterable: Iterable[Tuple[Any, ...]], **kw): "As combination, but takes a single iterable" return combinations(*arg_iterable, **kw) diff --git a/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/__init__.cpython-310.pyc index 505302c..1d352f1 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/base.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/base.cpython-310.pyc index 8187f6a..a938352 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/base.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/base.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/mypy.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/mypy.cpython-310.pyc index 0b71b32..c10d64d 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/mypy.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/mypy.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/orm.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/orm.cpython-310.pyc index 6b0ab55..307acf0 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/orm.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/orm.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/sql.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/sql.cpython-310.pyc index 86dcf02..6e57358 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/sql.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/sql.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/__init__.cpython-310.pyc index 5faf9f1..2e2d250 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/bootstrap.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/bootstrap.cpython-310.pyc index ecf4277..e4dffdb 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/bootstrap.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/bootstrap.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/plugin_base.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/plugin_base.cpython-310.pyc index db0b7ce..cd6c4e0 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/plugin_base.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/plugin_base.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/pytestplugin.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/pytestplugin.cpython-310.pyc index 3ce452c..b2fd1c3 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/pytestplugin.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/pytestplugin.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/plugin/plugin_base.py b/venv/Lib/site-packages/sqlalchemy/testing/plugin/plugin_base.py index 393070d..f6a7f15 100644 --- a/venv/Lib/site-packages/sqlalchemy/testing/plugin/plugin_base.py +++ b/venv/Lib/site-packages/sqlalchemy/testing/plugin/plugin_base.py @@ -14,6 +14,7 @@ from argparse import Namespace import configparser import logging import os +from pathlib import Path import re import sys from typing import Any @@ -320,6 +321,10 @@ def _log(opt_str, value, parser): def _list_dbs(*args): + if file_config is None: + # assume the current working directory is the one containing the + # setup file + read_config(Path.cwd()) print("Available --db options (use --dburi to override)") for macro in sorted(file_config.options("db")): print("%20s\t%s" % (macro, file_config.get("db", macro))) @@ -420,6 +425,7 @@ def _engine_uri(options, file_config): from sqlalchemy import testing from sqlalchemy.testing import config from sqlalchemy.testing import provision + from sqlalchemy.engine import url as sa_url if options.dburi: db_urls = list(options.dburi) @@ -444,18 +450,19 @@ def _engine_uri(options, file_config): config._current = None - expanded_urls = list(provision.generate_db_urls(db_urls, extra_drivers)) - - for db_url in expanded_urls: - log.info("Adding database URL: %s", db_url) - - if options.write_idents and provision.FOLLOWER_IDENT: + if options.write_idents and provision.FOLLOWER_IDENT: + for db_url in [sa_url.make_url(db_url) for db_url in db_urls]: with open(options.write_idents, "a") as file_: file_.write( f"{provision.FOLLOWER_IDENT} " f"{db_url.render_as_string(hide_password=False)}\n" ) + expanded_urls = list(provision.generate_db_urls(db_urls, extra_drivers)) + + for db_url in expanded_urls: + log.info("Adding database URL: %s", db_url) + cfg = provision.setup_config( db_url, options, file_config, provision.FOLLOWER_IDENT ) @@ -473,9 +480,6 @@ def _setup_requirements(argument): from sqlalchemy.testing import config from sqlalchemy import testing - if config.requirements is not None: - return - modname, clsname = argument.split(":") # importlib.import_module() only introduced in 2.7, a little diff --git a/venv/Lib/site-packages/sqlalchemy/testing/requirements.py b/venv/Lib/site-packages/sqlalchemy/testing/requirements.py index 479e1be..5d1f3fb 100644 --- a/venv/Lib/site-packages/sqlalchemy/testing/requirements.py +++ b/venv/Lib/site-packages/sqlalchemy/testing/requirements.py @@ -22,9 +22,8 @@ from __future__ import annotations import platform from . import asyncio as _test_asyncio -from . import config from . import exclusions -from . import only_on +from .exclusions import only_on from .. import create_engine from .. import util from ..pool import QueuePool @@ -59,6 +58,12 @@ class SuiteRequirements(Requirements): return exclusions.closed() + @property + def uuid_data_type(self): + """Return databases that support the UUID datatype.""" + + return exclusions.closed() + @property def foreign_keys(self): """Target database must support foreign keys.""" @@ -840,6 +845,14 @@ class SuiteRequirements(Requirements): """Target driver can create tables with a name like 'some " table'""" return exclusions.open() + @property + def datetime_interval(self): + """target dialect supports rendering of a datetime.timedelta as a + literal string, e.g. via the TypeEngine.literal_processor() method. + + """ + return exclusions.closed() + @property def datetime_literals(self): """target dialect supports rendering of a date, time, or datetime as a @@ -1448,10 +1461,14 @@ class SuiteRequirements(Requirements): @property def timing_intensive(self): + from . import config + return config.add_to_marker.timing_intensive @property def memory_intensive(self): + from . import config + return config.add_to_marker.memory_intensive @property diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/__init__.cpython-310.pyc index a170fd8..0bc021b 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_cte.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_cte.cpython-310.pyc index 0b45fe0..88f0620 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_cte.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_cte.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_ddl.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_ddl.cpython-310.pyc index a013b30..f63293f 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_ddl.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_ddl.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_deprecations.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_deprecations.cpython-310.pyc index 8631590..e6b6701 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_deprecations.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_deprecations.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_dialect.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_dialect.cpython-310.pyc index 9a72ef0..912bfb7 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_dialect.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_dialect.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_insert.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_insert.cpython-310.pyc index d8ce73e..6fddcb8 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_insert.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_insert.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_reflection.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_reflection.cpython-310.pyc index 324992d..782fe70 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_reflection.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_reflection.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_results.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_results.cpython-310.pyc index 0bb7a56..cc8e901 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_results.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_results.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_rowcount.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_rowcount.cpython-310.pyc index 32f434f..bf92f07 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_rowcount.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_rowcount.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_select.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_select.cpython-310.pyc index 826e211..927844c 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_select.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_select.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_sequence.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_sequence.cpython-310.pyc index 69a1902..3c08741 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_sequence.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_sequence.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_types.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_types.cpython-310.pyc index 3d6f743..7764e62 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_types.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_types.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_unicode_ddl.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_unicode_ddl.cpython-310.pyc index f1dfd3c..e3d9ace 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_unicode_ddl.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_unicode_ddl.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_update_delete.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_update_delete.cpython-310.pyc index 84aab68..c5e7329 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_update_delete.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_update_delete.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/test_insert.py b/venv/Lib/site-packages/sqlalchemy/testing/suite/test_insert.py index e164605..09f24d3 100644 --- a/venv/Lib/site-packages/sqlalchemy/testing/suite/test_insert.py +++ b/venv/Lib/site-packages/sqlalchemy/testing/suite/test_insert.py @@ -18,7 +18,6 @@ from ... import literal_column from ... import Numeric from ... import select from ... import String -from ...dialects.postgresql import BYTEA from ...types import LargeBinary from ...types import UUID from ...types import Uuid @@ -104,6 +103,15 @@ class InsertBehaviorTest(fixtures.TablesTest): Column("id", Integer, primary_key=True, autoincrement=False), Column("data", String(50)), ) + Table( + "no_implicit_returning", + metadata, + Column( + "id", Integer, primary_key=True, test_needs_autoincrement=True + ), + Column("data", String(50)), + implicit_returning=False, + ) Table( "includes_defaults", metadata, @@ -119,6 +127,33 @@ class InsertBehaviorTest(fixtures.TablesTest): ), ) + @testing.variation("style", ["plain", "return_defaults"]) + @testing.variation("executemany", [True, False]) + def test_no_results_for_non_returning_insert( + self, connection, style, executemany + ): + """test another INSERT issue found during #10453""" + + table = self.tables.no_implicit_returning + + stmt = table.insert() + if style.return_defaults: + stmt = stmt.return_defaults() + + if executemany: + data = [ + {"data": "d1"}, + {"data": "d2"}, + {"data": "d3"}, + {"data": "d4"}, + {"data": "d5"}, + ] + else: + data = {"data": "d1"} + + r = connection.execute(stmt, data) + assert not r.returns_rows + @requirements.autoincrement_insert def test_autoclose_on_insert(self, connection): r = connection.execute( @@ -394,7 +429,7 @@ class ReturningTest(fixtures.TablesTest): True, testing.requires.float_or_double_precision_behaves_generically, ), - (Float(), 8.5514, False), + (Float(), 8.5514, True), ( Float(8), 8.5514, @@ -517,7 +552,6 @@ class ReturningTest(fixtures.TablesTest): b"this is binary", ), ("LargeBinary2", LargeBinary(), b"7\xe7\x9f"), - ("PG BYTEA", BYTEA(), b"7\xe7\x9f", testing.only_on("postgresql")), argnames="type_,value", id_="iaa", ) diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/test_reflection.py b/venv/Lib/site-packages/sqlalchemy/testing/suite/test_reflection.py index 05b68e7..f2ecf1c 100644 --- a/venv/Lib/site-packages/sqlalchemy/testing/suite/test_reflection.py +++ b/venv/Lib/site-packages/sqlalchemy/testing/suite/test_reflection.py @@ -287,6 +287,65 @@ class HasIndexTest(fixtures.TablesTest): ) +class BizarroCharacterFKResolutionTest(fixtures.TestBase): + """tests for #10275""" + + __backend__ = True + + @testing.combinations( + ("id",), ("(3)",), ("col%p",), ("[brack]",), argnames="columnname" + ) + @testing.variation("use_composite", [True, False]) + @testing.combinations( + ("plain",), + ("(2)",), + ("per % cent",), + ("[brackets]",), + argnames="tablename", + ) + def test_fk_ref( + self, connection, metadata, use_composite, tablename, columnname + ): + tt = Table( + tablename, + metadata, + Column(columnname, Integer, key="id", primary_key=True), + test_needs_fk=True, + ) + if use_composite: + tt.append_column(Column("id2", Integer, primary_key=True)) + + if use_composite: + Table( + "other", + metadata, + Column("id", Integer, primary_key=True), + Column("ref", Integer), + Column("ref2", Integer), + sa.ForeignKeyConstraint(["ref", "ref2"], [tt.c.id, tt.c.id2]), + test_needs_fk=True, + ) + else: + Table( + "other", + metadata, + Column("id", Integer, primary_key=True), + Column("ref", ForeignKey(tt.c.id)), + test_needs_fk=True, + ) + + metadata.create_all(connection) + + m2 = MetaData() + + o2 = Table("other", m2, autoload_with=connection) + t1 = m2.tables[tablename] + + assert o2.c.ref.references(t1.c[0]) + if use_composite: + assert o2.c.ref2.references(t1.c[1]) + + class QuotedNameArgumentTest(fixtures.TablesTest): run_create_tables = "once" __backend__ = True @@ -3053,6 +3112,7 @@ __all__ = ( "ComponentReflectionTestExtra", "TableNoColumnsTest", "QuotedNameArgumentTest", + "BizarroCharacterFKResolutionTest", "HasTableTest", "HasIndexTest", "NormalizedNameTest", diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/test_results.py b/venv/Lib/site-packages/sqlalchemy/testing/suite/test_results.py index c0f5e40..e439d6c 100644 --- a/venv/Lib/site-packages/sqlalchemy/testing/suite/test_results.py +++ b/venv/Lib/site-packages/sqlalchemy/testing/suite/test_results.py @@ -254,7 +254,7 @@ class ServerSideCursorsTest( elif self.engine.dialect.driver == "pymysql": sscursor = __import__("pymysql.cursors").cursors.SSCursor return isinstance(cursor, sscursor) - elif self.engine.dialect.driver in ("aiomysql", "asyncmy"): + elif self.engine.dialect.driver in ("aiomysql", "asyncmy", "aioodbc"): return cursor.server_side elif self.engine.dialect.driver == "mysqldb": sscursor = __import__("MySQLdb.cursors").cursors.SSCursor @@ -311,7 +311,7 @@ class ServerSideCursorsTest( True, "SELECT 1 FOR UPDATE", True, - testing.skip_if("sqlite"), + testing.skip_if(["sqlite", "mssql"]), ), ("text_no_ss", False, text("select 42"), False), ( diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/test_rowcount.py b/venv/Lib/site-packages/sqlalchemy/testing/suite/test_rowcount.py index ba8e104..58295a5 100644 --- a/venv/Lib/site-packages/sqlalchemy/testing/suite/test_rowcount.py +++ b/venv/Lib/site-packages/sqlalchemy/testing/suite/test_rowcount.py @@ -66,6 +66,49 @@ class RowCountTest(fixtures.TablesTest): eq_(rows, self.data) + @testing.variation("statement", ["update", "delete", "insert", "select"]) + @testing.variation("close_first", [True, False]) + def test_non_rowcount_scenarios_no_raise( + self, connection, statement, close_first + ): + employees_table = self.tables.employees + + # WHERE matches 3, 3 rows changed + department = employees_table.c.department + + if statement.update: + r = connection.execute( + employees_table.update().where(department == "C"), + {"department": "Z"}, + ) + elif statement.delete: + r = connection.execute( + employees_table.delete().where(department == "C"), + {"department": "Z"}, + ) + elif statement.insert: + r = connection.execute( + employees_table.insert(), + [ + {"employee_id": 25, "name": "none 1", "department": "X"}, + {"employee_id": 26, "name": "none 2", "department": "Z"}, + {"employee_id": 27, "name": "none 3", "department": "Z"}, + ], + ) + elif statement.select: + s = select( + employees_table.c.name, employees_table.c.department + ).where(employees_table.c.department == "C") + r = connection.execute(s) + r.all() + else: + statement.fail() + + if close_first: + r.close() + + assert r.rowcount in (-1, 3) + def test_update_rowcount1(self, connection): employees_table = self.tables.employees diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/test_types.py b/venv/Lib/site-packages/sqlalchemy/testing/suite/test_types.py index 0a1419f..5debb45 100644 --- a/venv/Lib/site-packages/sqlalchemy/testing/suite/test_types.py +++ b/venv/Lib/site-packages/sqlalchemy/testing/suite/test_types.py @@ -28,6 +28,7 @@ from ... import Date from ... import DateTime from ... import Float from ... import Integer +from ... import Interval from ... import JSON from ... import literal from ... import literal_column @@ -82,6 +83,11 @@ class _LiteralRoundTripFixture: ) connection.execute(ins) + ins = t.insert().values( + x=literal(None, type_, literal_execute=True) + ) + connection.execute(ins) + if support_whereclause and self.supports_whereclause: if compare: stmt = t.select().where( @@ -108,7 +114,7 @@ class _LiteralRoundTripFixture: ) ) else: - stmt = t.select() + stmt = t.select().where(t.c.x.is_not(None)) rows = connection.execute(stmt).all() assert rows, "No rows returned" @@ -118,6 +124,10 @@ class _LiteralRoundTripFixture: value = filter_(value) assert value in output + stmt = t.select().where(t.c.x.is_(None)) + rows = connection.execute(stmt).all() + eq_(rows, [(None,)]) + return run @@ -452,6 +462,102 @@ class StringTest(_LiteralRoundTripFixture, fixtures.TestBase): ) +class IntervalTest(_LiteralRoundTripFixture, fixtures.TestBase): + __requires__ = ("datetime_interval",) + __backend__ = True + + datatype = Interval + data = datetime.timedelta(days=1, seconds=4) + + def test_literal(self, literal_round_trip): + literal_round_trip(self.datatype, [self.data], [self.data]) + + def test_select_direct_literal_interval(self, connection): + row = connection.execute(select(literal(self.data))).first() + eq_(row, (self.data,)) + + def test_arithmetic_operation_literal_interval(self, connection): + now = datetime.datetime.now().replace(microsecond=0) + # Able to subtract + row = connection.execute( + select(literal(now) - literal(self.data)) + ).scalar() + eq_(row, now - self.data) + + # Able to Add + row = connection.execute( + select(literal(now) + literal(self.data)) + ).scalar() + eq_(row, now + self.data) + + @testing.fixture + def arithmetic_table_fixture(cls, metadata, connection): + class Decorated(TypeDecorator): + impl = cls.datatype + cache_ok = True + + it = Table( + "interval_table", + metadata, + Column( + "id", Integer, primary_key=True, test_needs_autoincrement=True + ), + Column("interval_data", cls.datatype), + Column("date_data", DateTime), + Column("decorated_interval_data", Decorated), + ) + it.create(connection) + return it + + def test_arithmetic_operation_table_interval_and_literal_interval( + self, connection, arithmetic_table_fixture + ): + interval_table = arithmetic_table_fixture + data = datetime.timedelta(days=2, seconds=5) + connection.execute( + interval_table.insert(), {"id": 1, "interval_data": data} + ) + # Subtraction Operation + value = connection.execute( + select(interval_table.c.interval_data - literal(self.data)) + ).scalar() + eq_(value, data - self.data) + + # Addition Operation + value = connection.execute( + select(interval_table.c.interval_data + literal(self.data)) + ).scalar() + eq_(value, data + self.data) + + def test_arithmetic_operation_table_date_and_literal_interval( + self, connection, arithmetic_table_fixture + ): + interval_table = arithmetic_table_fixture + now = datetime.datetime.now().replace(microsecond=0) + connection.execute( + interval_table.insert(), {"id": 1, "date_data": now} + ) + # Subtraction Operation + value = connection.execute( + select(interval_table.c.date_data - literal(self.data)) + ).scalar() + eq_(value, (now - self.data)) + + # Addition Operation + value = connection.execute( + select(interval_table.c.date_data + literal(self.data)) + ).scalar() + eq_(value, (now + self.data)) + + +class PrecisionIntervalTest(IntervalTest): + __requires__ = ("datetime_interval",) + __backend__ = True + + datatype = Interval(day_precision=9, second_precision=9) + data = datetime.timedelta(days=103, seconds=4) + + class _DateFixture(_LiteralRoundTripFixture, fixtures.TestBase): compare = None @@ -1940,6 +2046,8 @@ __all__ = ( "TextTest", "NumericTest", "IntegerTest", + "IntervalTest", + "PrecisionIntervalTest", "CastTypeDecoratorTest", "DateTimeHistoricTest", "DateTimeCoercedToDateTimeTest", diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/test_update_delete.py b/venv/Lib/site-packages/sqlalchemy/testing/suite/test_update_delete.py index 62776ea..2d13bda 100644 --- a/venv/Lib/site-packages/sqlalchemy/testing/suite/test_update_delete.py +++ b/venv/Lib/site-packages/sqlalchemy/testing/suite/test_update_delete.py @@ -6,6 +6,7 @@ from ..schema import Column from ..schema import Table from ... import Integer from ... import String +from ... import testing class SimpleUpdateDeleteTest(fixtures.TablesTest): @@ -58,5 +59,71 @@ class SimpleUpdateDeleteTest(fixtures.TablesTest): [(1, "d1"), (3, "d3")], ) + @testing.variation("criteria", ["rows", "norows", "emptyin"]) + @testing.requires.update_returning + def test_update_returning(self, connection, criteria): + t = self.tables.plain_pk + + stmt = t.update().returning(t.c.id, t.c.data) + + if criteria.norows: + stmt = stmt.where(t.c.id == 10) + elif criteria.rows: + stmt = stmt.where(t.c.id == 2) + elif criteria.emptyin: + stmt = stmt.where(t.c.id.in_([])) + else: + criteria.fail() + + r = connection.execute(stmt, dict(data="d2_new")) + assert not r.is_insert + assert r.returns_rows + eq_(r.keys(), ["id", "data"]) + + if criteria.rows: + eq_(r.all(), [(2, "d2_new")]) + else: + eq_(r.all(), []) + + eq_( + connection.execute(t.select().order_by(t.c.id)).fetchall(), + [(1, "d1"), (2, "d2_new"), (3, "d3")] + if criteria.rows + else [(1, "d1"), (2, "d2"), (3, "d3")], + ) + + @testing.variation("criteria", ["rows", "norows", "emptyin"]) + @testing.requires.delete_returning + def test_delete_returning(self, connection, criteria): + t = self.tables.plain_pk + + stmt = t.delete().returning(t.c.id, t.c.data) + + if criteria.norows: + stmt = stmt.where(t.c.id == 10) + elif criteria.rows: + stmt = stmt.where(t.c.id == 2) + elif criteria.emptyin: + stmt = stmt.where(t.c.id.in_([])) + else: + criteria.fail() + + r = connection.execute(stmt) + assert not r.is_insert + assert r.returns_rows + eq_(r.keys(), ["id", "data"]) + + if criteria.rows: + eq_(r.all(), [(2, "d2")]) + else: + eq_(r.all(), []) + + eq_( + connection.execute(t.select().order_by(t.c.id)).fetchall(), + [(1, "d1"), (3, "d3")] + if criteria.rows + else [(1, "d1"), (2, "d2"), (3, "d3")], + ) + __all__ = ("SimpleUpdateDeleteTest",) diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/__init__.cpython-310.pyc index b7b2f91..9abdfc8 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_collections.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_collections.cpython-310.pyc index df856f8..46e1209 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_collections.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_collections.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_concurrency_py3k.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_concurrency_py3k.cpython-310.pyc index 77370e5..e419ec4 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_concurrency_py3k.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_concurrency_py3k.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_has_cy.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_has_cy.cpython-310.pyc index bc8d833..079561f 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_has_cy.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_has_cy.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_py_collections.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_py_collections.cpython-310.pyc index d73425b..4d140c4 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_py_collections.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_py_collections.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/compat.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/compat.cpython-310.pyc index cdb07be..3050238 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/compat.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/compat.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/concurrency.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/concurrency.cpython-310.pyc index a8410e2..9754a29 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/concurrency.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/concurrency.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/deprecations.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/deprecations.cpython-310.pyc index 1019dd3..b50e1b6 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/deprecations.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/deprecations.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/langhelpers.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/langhelpers.cpython-310.pyc index 67eab8e..02e0aa1 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/langhelpers.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/langhelpers.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/preloaded.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/preloaded.cpython-310.pyc index 1758f88..b44af76 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/preloaded.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/preloaded.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/queue.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/queue.cpython-310.pyc index 2d72c63..346454e 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/queue.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/queue.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/tool_support.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/tool_support.cpython-310.pyc index 8c2616d..d4fd45f 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/tool_support.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/tool_support.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/topological.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/topological.cpython-310.pyc index ac82e16..94dd781 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/topological.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/topological.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/typing.cpython-310.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/typing.cpython-310.pyc index 7957e32..65693b1 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/typing.cpython-310.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/typing.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/_collections.py b/venv/Lib/site-packages/sqlalchemy/util/_collections.py index 2e793e8..a0b1977 100644 --- a/venv/Lib/site-packages/sqlalchemy/util/_collections.py +++ b/venv/Lib/site-packages/sqlalchemy/util/_collections.py @@ -189,7 +189,7 @@ class Properties(Generic[_T]): return dir(super()) + [str(k) for k in self._data.keys()] def __add__(self, other: Properties[_F]) -> List[Union[_T, _F]]: - return list(self) + list(other) # type: ignore + return list(self) + list(other) def __setitem__(self, key: str, obj: _T) -> None: self._data[key] = obj @@ -393,16 +393,16 @@ class UniqueAppender(Generic[_T]): self.data = data self._unique = {} if via: - self._data_appender = getattr(data, via) # type: ignore[assignment] # noqa: E501 + self._data_appender = getattr(data, via) elif hasattr(data, "append"): - self._data_appender = cast("List[_T]", data).append # type: ignore[assignment] # noqa: E501 + self._data_appender = cast("List[_T]", data).append elif hasattr(data, "add"): - self._data_appender = cast("Set[_T]", data).add # type: ignore[assignment] # noqa: E501 + self._data_appender = cast("Set[_T]", data).add def append(self, item: _T) -> None: id_ = id(item) if id_ not in self._unique: - self._data_appender(item) # type: ignore[call-arg] + self._data_appender(item) self._unique[id_] = True def __iter__(self) -> Iterator[_T]: @@ -532,8 +532,8 @@ class LRUCache(typing.MutableMapping[_KT, _VT]): def get( self, key: _KT, default: Optional[Union[_VT, _T]] = None ) -> Optional[Union[_VT, _T]]: - item = self._data.get(key, default) - if item is not default and item is not None: + item = self._data.get(key) + if item is not None: item[2][0] = self._inc_counter() return item[1] else: @@ -677,7 +677,7 @@ class ThreadLocalRegistry(ScopedRegistry[_T]): return self.registry.value # type: ignore[no-any-return] except AttributeError: val = self.registry.value = self.createfunc() - return val # type: ignore[no-any-return] + return val def has(self) -> bool: return hasattr(self.registry, "value") diff --git a/venv/Lib/site-packages/sqlalchemy/util/_concurrency_py3k.py b/venv/Lib/site-packages/sqlalchemy/util/_concurrency_py3k.py index 2b6ae87..71d10a6 100644 --- a/venv/Lib/site-packages/sqlalchemy/util/_concurrency_py3k.py +++ b/venv/Lib/site-packages/sqlalchemy/util/_concurrency_py3k.py @@ -69,7 +69,7 @@ def is_exit_exception(e: BaseException) -> bool: # Issue for context: https://github.com/python-greenlet/greenlet/issues/173 -class _AsyncIoGreenlet(greenlet): # type: ignore +class _AsyncIoGreenlet(greenlet): dead: bool def __init__(self, fn: Callable[..., Any], driver: greenlet): @@ -147,7 +147,7 @@ def await_fallback(awaitable: Awaitable[_T]) -> _T: "loop is already running; can't call await_fallback() here. " "Was IO attempted in an unexpected place?" ) - return loop.run_until_complete(awaitable) # type: ignore[no-any-return] # noqa: E501 + return loop.run_until_complete(awaitable) return current.driver.switch(awaitable) # type: ignore[no-any-return] diff --git a/venv/Lib/site-packages/sqlalchemy/util/_py_collections.py b/venv/Lib/site-packages/sqlalchemy/util/_py_collections.py index 9962493..4f52d3b 100644 --- a/venv/Lib/site-packages/sqlalchemy/util/_py_collections.py +++ b/venv/Lib/site-packages/sqlalchemy/util/_py_collections.py @@ -227,11 +227,11 @@ class OrderedSet(Set[_T]): super().add(e) def __ior__(self, other: AbstractSet[_S]) -> OrderedSet[Union[_T, _S]]: - self.update(other) # type: ignore - return self # type: ignore + self.update(other) + return self def union(self, *other: Iterable[_S]) -> OrderedSet[Union[_T, _S]]: - result: OrderedSet[Union[_T, _S]] = self.copy() # type: ignore + result: OrderedSet[Union[_T, _S]] = self.copy() result.update(*other) return result diff --git a/venv/Lib/site-packages/sqlalchemy/util/compat.py b/venv/Lib/site-packages/sqlalchemy/util/compat.py index da653b8..98a0b65 100644 --- a/venv/Lib/site-packages/sqlalchemy/util/compat.py +++ b/venv/Lib/site-packages/sqlalchemy/util/compat.py @@ -12,6 +12,7 @@ from __future__ import annotations import base64 import dataclasses +import hashlib import inspect import operator import platform @@ -119,6 +120,18 @@ else: return gen.athrow(typ, value, traceback) +if py39: + # python stubs don't have a public type for this. not worth + # making a protocol + def md5_not_for_security() -> Any: + return hashlib.md5(usedforsecurity=False) + +else: + + def md5_not_for_security() -> Any: + return hashlib.md5() + + if typing.TYPE_CHECKING or py38: from importlib import metadata as importlib_metadata else: diff --git a/venv/Lib/site-packages/sqlalchemy/util/deprecations.py b/venv/Lib/site-packages/sqlalchemy/util/deprecations.py index dd5851c..26d9924 100644 --- a/venv/Lib/site-packages/sqlalchemy/util/deprecations.py +++ b/venv/Lib/site-packages/sqlalchemy/util/deprecations.py @@ -246,7 +246,7 @@ def deprecated_params(**specs: Tuple[str, str]) -> Callable[[_F], _F]: # latest mypy has opinions here, not sure if they implemented # Concatenate or something - @decorator # type: ignore + @decorator def warned(fn: _F, *args: Any, **kwargs: Any) -> _F: for m in check_defaults: if (defaults[m] is None and kwargs[m] is not None) or ( @@ -290,9 +290,9 @@ def deprecated_params(**specs: Tuple[str, str]) -> Callable[[_F], _F]: for param, (version, message) in specs.items() }, ) - decorated = warned(fn) # type: ignore + decorated = warned(fn) decorated.__doc__ = doc - return decorated # type: ignore[no-any-return] + return decorated return decorate @@ -334,7 +334,7 @@ def _decorate_cls_with_warning( clsdict["__doc__"] = doc clsdict.pop("__dict__", None) clsdict.pop("__weakref__", None) - cls = type(cls.__name__, cls.__bases__, clsdict) # type: ignore + cls = type(cls.__name__, cls.__bases__, clsdict) if constructor is not None: constructor_fn = clsdict[constructor] @@ -376,7 +376,7 @@ def _decorate_with_warning( else: doc_only = "" - @decorator # type: ignore + @decorator def warned(fn: _F, *args: Any, **kwargs: Any) -> _F: skip_warning = not enable_warnings or kwargs.pop( "_sa_skip_warning", False @@ -393,9 +393,9 @@ def _decorate_with_warning( doc = inject_docstring_text(doc, docstring_header, 1) - decorated = warned(func) # type: ignore + decorated = warned(func) decorated.__doc__ = doc decorated._sa_warn = lambda: _warn_with_version( # type: ignore message, version, wtype, stacklevel=3 ) - return decorated # type: ignore[no-any-return] + return decorated diff --git a/venv/Lib/site-packages/sqlalchemy/util/langhelpers.py b/venv/Lib/site-packages/sqlalchemy/util/langhelpers.py index 6c9afb5..9c56487 100644 --- a/venv/Lib/site-packages/sqlalchemy/util/langhelpers.py +++ b/venv/Lib/site-packages/sqlalchemy/util/langhelpers.py @@ -15,7 +15,6 @@ from __future__ import annotations import collections import enum from functools import update_wrapper -import hashlib import inspect import itertools import operator @@ -87,9 +86,9 @@ else: def md5_hex(x: Any) -> str: x = x.encode("utf-8") - m = hashlib.md5() + m = compat.md5_not_for_security() m.update(x) - return m.hexdigest() + return cast(str, m.hexdigest()) class safe_reraise: @@ -266,6 +265,13 @@ def decorator(target: Callable[..., Any]) -> Callable[[_Fn], _Fn]: metadata.update(format_argspec_plus(spec, grouped=False)) metadata["name"] = fn.__name__ + if inspect.iscoroutinefunction(fn): + metadata["prefix"] = "async " + metadata["target_prefix"] = "await " + else: + metadata["prefix"] = "" + metadata["target_prefix"] = "" + # look for __ positional arguments. This is a convention in # SQLAlchemy that arguments should be passed positionally # rather than as keyword @@ -277,16 +283,16 @@ def decorator(target: Callable[..., Any]) -> Callable[[_Fn], _Fn]: if "__" in repr(spec[0]): code = ( """\ -def %(name)s%(grouped_args)s: - return %(target)s(%(fn)s, %(apply_pos)s) +%(prefix)sdef %(name)s%(grouped_args)s: + return %(target_prefix)s%(target)s(%(fn)s, %(apply_pos)s) """ % metadata ) else: code = ( """\ -def %(name)s%(grouped_args)s: - return %(target)s(%(fn)s, %(apply_kw)s) +%(prefix)sdef %(name)s%(grouped_args)s: + return %(target_prefix)s%(target)s(%(fn)s, %(apply_kw)s) """ % metadata ) @@ -526,12 +532,10 @@ def get_callable_argspec( fn.__init__, no_self=no_self, _is_init=True ) elif hasattr(fn, "__func__"): - return compat.inspect_getfullargspec(fn.__func__) # type: ignore[attr-defined] # noqa: E501 + return compat.inspect_getfullargspec(fn.__func__) elif hasattr(fn, "__call__"): - if inspect.ismethod(fn.__call__): # type: ignore [operator] - return get_callable_argspec( - fn.__call__, no_self=no_self # type: ignore [operator] - ) + if inspect.ismethod(fn.__call__): + return get_callable_argspec(fn.__call__, no_self=no_self) else: raise TypeError("Can't inspect callable: %s" % fn) else: @@ -693,6 +697,7 @@ def create_proxy_methods( classmethods: Sequence[str] = (), methods: Sequence[str] = (), attributes: Sequence[str] = (), + use_intermediate_variable: Sequence[str] = (), ) -> Callable[[_T], _T]: """A class decorator indicating attributes should refer to a proxy class. @@ -1082,7 +1087,7 @@ class generic_fn_descriptor(Generic[_T_co]): __name__: str def __init__(self, fget: Callable[..., _T_co], doc: Optional[str] = None): - self.fget = fget # type: ignore[assignment] + self.fget = fget self.__doc__ = doc or fget.__doc__ self.__name__ = fget.__name__ @@ -1237,12 +1242,11 @@ class HasMemoized: __name__: str def __init__(self, fget: Callable[..., _T], doc: Optional[str] = None): - # https://github.com/python/mypy/issues/708 - self.fget = fget # type: ignore + self.fget = fget self.__doc__ = doc or fget.__doc__ self.__name__ = fget.__name__ - @overload # type: ignore[override] + @overload def __get__(self: _MA, obj: None, cls: Any) -> _MA: ... @@ -1476,7 +1480,7 @@ def assert_arg_type( if isinstance(argtype, tuple): raise exc.ArgumentError( "Argument '%s' is expected to be one of type %s, got '%s'" - % (name, " or ".join("'%s'" % a for a in argtype), type(arg)) # type: ignore # noqa: E501 + % (name, " or ".join("'%s'" % a for a in argtype), type(arg)) ) else: raise exc.ArgumentError( @@ -1527,7 +1531,7 @@ class classproperty(property): self.__doc__ = fget.__doc__ def __get__(self, obj: Any, cls: Optional[type] = None) -> Any: - return self.fget(cls) # type: ignore + return self.fget(cls) class hybridproperty(Generic[_T]): diff --git a/venv/Lib/site-packages/sqlalchemy/util/typing.py b/venv/Lib/site-packages/sqlalchemy/util/typing.py index 597549c..3d15d43 100644 --- a/venv/Lib/site-packages/sqlalchemy/util/typing.py +++ b/venv/Lib/site-packages/sqlalchemy/util/typing.py @@ -8,6 +8,7 @@ from __future__ import annotations +import builtins import re import sys import typing @@ -249,6 +250,12 @@ def eval_name_only( try: return base_globals[name] except KeyError as ke: + # check in builtins as well to handle `list`, `set` or `dict`, etc. + try: + return builtins.__dict__[name] + except KeyError: + pass + raise NameError( f"Could not locate name {name} in module {module_name}" ) from ke diff --git a/venv/Lib/site-packages/wtforms-3.2.1.dist-info/INSTALLER b/venv/Lib/site-packages/wtforms-3.2.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/Lib/site-packages/wtforms-3.2.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/Lib/site-packages/wtforms-3.2.1.dist-info/METADATA b/venv/Lib/site-packages/wtforms-3.2.1.dist-info/METADATA deleted file mode 100644 index fe8aec6..0000000 --- a/venv/Lib/site-packages/wtforms-3.2.1.dist-info/METADATA +++ /dev/null @@ -1,119 +0,0 @@ -Metadata-Version: 2.3 -Name: WTForms -Version: 3.2.1 -Summary: Form validation and rendering for Python web development. -Project-URL: Documentation, https://wtforms.readthedocs.io -Project-URL: Changes, https://wtforms.readthedocs.io/changes -Project-URL: Source Code, https://github.com/pallets-eco/wtforms/ -Project-URL: Issue Tracker, https://github.com/pallets-eco/wtforms/issues -Project-URL: Chat, https://discord.gg/pallets -Maintainer: WTForms -License: Copyright 2008 WTForms - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -License-File: LICENSE.rst -Classifier: Development Status :: 5 - Production/Stable -Classifier: Environment :: Web Environment -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: BSD License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content -Requires-Python: >=3.9 -Requires-Dist: markupsafe -Provides-Extra: email -Requires-Dist: email-validator; extra == 'email' -Description-Content-Type: text/x-rst - -WTForms -======= - -WTForms is a flexible forms validation and rendering library for Python -web development. It can work with whatever web framework and template -engine you choose. It supports data validation, CSRF protection, -internationalization (I18N), and more. There are various community -libraries that provide closer integration with popular frameworks. - - -Installation ------------- - -Install and update using pip: - -.. code-block:: text - - pip install -U WTForms - - -Third-Party Library Integrations --------------------------------- - -WTForms is designed to work with any web framework and template engine. -There are a number of community-provided libraries that make integrating -with frameworks even better. - -- `Flask-WTF`_ integrates with the Flask framework. It can - automatically load data from the request, uses Flask-Babel to - translate based on user-selected locale, provides full-application - CSRF, and more. -- `WTForms-Alchemy`_ provides rich support for generating forms from - SQLAlchemy models, including an expanded set of fields and - validators. -- `WTForms-SQLAlchemy`_ provides ORM-backed fields and form generation - from SQLAlchemy models. -- `WTForms-AppEngine`_ provides ORM-backed fields and form generation - from AppEnding db/ndb schema -- `WTForms-Django`_ provides ORM-backed fields and form generation - from Django models, as well as integration with Django's I18N - support. -- `WTForms-Bootstrap5`_ provides Bootstrap 5 favor renderer with - great customizability. -- `Starlette-WTF`_ integrates with Starlette and the FastAPI - framework, based on the features of Flask-WTF. -- `Bootstrap-Flask`_ Bootstrap-Flask is a collection of Jinja macros - for Bootstrap 4 & 5 and Flask using Flask-WTF. - -.. _Flask-WTF: https://flask-wtf.readthedocs.io/ -.. _WTForms-Alchemy: https://wtforms-alchemy.readthedocs.io/ -.. _WTForms-SQLAlchemy: https://github.com/pallets-eco/wtforms-sqlalchemy -.. _WTForms-AppEngine: https://github.com/pallets-eco/wtforms-appengine -.. _WTForms-Django: https://github.com/pallets-eco/wtforms-django -.. _WTForms-Bootstrap5: https://github.com/LaunchPlatform/wtforms-bootstrap5 -.. _Starlette-WTF: https://github.com/muicss/starlette-wtf -.. _Bootstrap-Flask: https://github.com/helloflask/bootstrap-flask - - -Links ------ - -- Documentation: https://wtforms.readthedocs.io/ -- Releases: https://pypi.org/project/WTForms/ -- Code: https://github.com/pallets-eco/wtforms -- Issue tracker: https://github.com/pallets-eco/wtforms/issues -- Discord Chat: https://discord.gg/F65P7Z9 -- Translation: https://hosted.weblate.org/projects/wtforms/wtforms/ diff --git a/venv/Lib/site-packages/wtforms-3.2.1.dist-info/RECORD b/venv/Lib/site-packages/wtforms-3.2.1.dist-info/RECORD deleted file mode 100644 index 310b42c..0000000 --- a/venv/Lib/site-packages/wtforms-3.2.1.dist-info/RECORD +++ /dev/null @@ -1,109 +0,0 @@ -wtforms-3.2.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -wtforms-3.2.1.dist-info/METADATA,sha256=oOzlfdk_oSeggHYC7BafQY4eyQKMeCOjXnKXRE998k0,5305 -wtforms-3.2.1.dist-info/RECORD,, -wtforms-3.2.1.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87 -wtforms-3.2.1.dist-info/licenses/LICENSE.rst,sha256=z0DWD_NPaytopT0iD4tmVntayN0RGbN7Yv0V6VGP5Zs,1475 -wtforms/__init__.py,sha256=aQn8cIuZR--RBgakKS49cqNvH2B-BP4Us5oyDpx9C5E,2408 -wtforms/__pycache__/__init__.cpython-310.pyc,, -wtforms/__pycache__/form.cpython-310.pyc,, -wtforms/__pycache__/i18n.cpython-310.pyc,, -wtforms/__pycache__/meta.cpython-310.pyc,, -wtforms/__pycache__/utils.cpython-310.pyc,, -wtforms/__pycache__/validators.cpython-310.pyc,, -wtforms/csrf/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -wtforms/csrf/__pycache__/__init__.cpython-310.pyc,, -wtforms/csrf/__pycache__/core.cpython-310.pyc,, -wtforms/csrf/__pycache__/session.cpython-310.pyc,, -wtforms/csrf/core.py,sha256=8Ka3ZATvo9I1WqreP1Y_i1r0t7m8Wcw5cKynVvJNXes,3097 -wtforms/csrf/session.py,sha256=4ajg5ooedVrZxxUOaeIj7WnLRSZVp9jpw_rf3oyeF5U,3092 -wtforms/fields/__init__.py,sha256=L3X1O4pOmLRmACTndbIwFFS2qFvO3oDfI3P6GslTScQ,2255 -wtforms/fields/__pycache__/__init__.cpython-310.pyc,, -wtforms/fields/__pycache__/choices.cpython-310.pyc,, -wtforms/fields/__pycache__/core.cpython-310.pyc,, -wtforms/fields/__pycache__/datetime.cpython-310.pyc,, -wtforms/fields/__pycache__/form.cpython-310.pyc,, -wtforms/fields/__pycache__/list.cpython-310.pyc,, -wtforms/fields/__pycache__/numeric.cpython-310.pyc,, -wtforms/fields/__pycache__/simple.cpython-310.pyc,, -wtforms/fields/choices.py,sha256=zAW-y1s1_sKjNT3qRwWuUKsUrojD9zIR6q5LwfGOwZc,6882 -wtforms/fields/core.py,sha256=a9OyjNpNUXMQq6e3m_9eWEKq1PKJshDmL2CEiH2BUX0,14385 -wtforms/fields/datetime.py,sha256=hImU4WDENQK7upIedBQJ1Y2N2-fwxZCkWOfeRYCibFE,5034 -wtforms/fields/form.py,sha256=_VreNaDy1ea_A7b3m4UdndYdcmJbyokDYYyZW_5jJOE,2897 -wtforms/fields/list.py,sha256=lfn89ankyMgJEgoxf50hplYAe7Zq_VvAp2k_FAMvUN0,6471 -wtforms/fields/numeric.py,sha256=Y39ODDk9eh6Nctb8gOx26u0ioiChIIUczpxAlK8Vyaw,6157 -wtforms/fields/simple.py,sha256=VBp8mRT5n3hRMH5ErgIjZtbqRr3jaRv2lZj4NMgs6XY,4075 -wtforms/form.py,sha256=DJOojlwLuswfhC1zsVSeprMbGqPAXed6fRxung131O4,12619 -wtforms/i18n.py,sha256=8AMTTSpQ5d-hONeVN8rt3RH0gRc3Mvl4zUum8Hyif88,1958 -wtforms/locale/README.md,sha256=Rb-tZdT5rErXDoe9lOmXl8Fj8ZCZPyE9fqpb0kQ2o8Y,1515 -wtforms/locale/ar/LC_MESSAGES/wtforms.mo,sha256=Wks5v3QGlNTRoIu1AKSmKHbatXQzQWYD4o4ieJdokQw,4393 -wtforms/locale/ar/LC_MESSAGES/wtforms.po,sha256=sQYvGsubsfzm1fr3qTuIyUxmkTZ0k7r6e_pzh7_gkzM,6919 -wtforms/locale/bg/LC_MESSAGES/wtforms.mo,sha256=vzeNlmzOzW7YsWfWPqI2Zt6Dgw0bd94QnLyRLhuRJy4,3932 -wtforms/locale/bg/LC_MESSAGES/wtforms.po,sha256=c70xbR04txPVUseRdnBsvg-KVUbUm1SOMMaSw73KHHA,6534 -wtforms/locale/ca/LC_MESSAGES/wtforms.mo,sha256=p0tFvBUip7wCRljw_SqFFeCV4cGNTlu5owphrsuK2Xo,3177 -wtforms/locale/ca/LC_MESSAGES/wtforms.po,sha256=2_ja11SMTPMUuE5Z6Z23sp2lzqv5ZnZGEjDXaOkD0gw,5693 -wtforms/locale/cs_CZ/LC_MESSAGES/wtforms.mo,sha256=eVPIUOfdIePaoCRPoMFHxi3EuuBya1xUU5jJMf8wi38,3398 -wtforms/locale/cs_CZ/LC_MESSAGES/wtforms.po,sha256=RZQgUiBLPdLZtMKd_WqJPTVT0-IDzstiXTgsOaNYW-A,5858 -wtforms/locale/cy/LC_MESSAGES/wtforms.mo,sha256=3gTVlrP7N9hNs9Avm_8dJhYUrMCKyk-VSEFdDEvEM1E,3142 -wtforms/locale/cy/LC_MESSAGES/wtforms.po,sha256=0ChyJkxdCuk7hDaHb7HYu_dfjUsdpW1QePW1zsmwY_o,5647 -wtforms/locale/de/LC_MESSAGES/wtforms.mo,sha256=Lx-Wgk5wbklVDo3PAweOtEyq0-qs50d8UYgwdxfFApQ,3175 -wtforms/locale/de/LC_MESSAGES/wtforms.po,sha256=FNpOXqoAMk5AlvYSWVLCEy4HLS0vQ9l7uBP1Eqx5eCo,5687 -wtforms/locale/de_CH/LC_MESSAGES/wtforms.mo,sha256=1yxa05bj0pdyt7he-x4f8ZV29pwrhh4c3oNNIXjClGs,3169 -wtforms/locale/de_CH/LC_MESSAGES/wtforms.po,sha256=m4nhUhZFBxsVc0TEq_pjM3KUPPhGYB9YamJzp0aI0Vs,5694 -wtforms/locale/el/LC_MESSAGES/wtforms.mo,sha256=Vj6ZE-q3kt_dx4BBDedDCjssbZVRRxnV0Gy1JBsjhBo,3951 -wtforms/locale/el/LC_MESSAGES/wtforms.po,sha256=3V1NhET6p8lwvHbedFDroEe3Fh4k2a0GzksRuB1cFyA,6583 -wtforms/locale/en/LC_MESSAGES/wtforms.mo,sha256=6MIjYtnt36bLr2EOGZCFJx_UntunQUCihf_hnWTNH9o,3323 -wtforms/locale/en/LC_MESSAGES/wtforms.po,sha256=Yn7Pb4rFmGxwp3emJW_aAqCBBZZw-E-JTGClfL78DY8,5046 -wtforms/locale/es/LC_MESSAGES/wtforms.mo,sha256=HQ1SSCbJtjyW8qtA4N96In6LcD3tg0vfG5hyI_KuDUg,3882 -wtforms/locale/es/LC_MESSAGES/wtforms.po,sha256=NtLOPMiz4pbRYup0jITAF7hNYtUDgojFK74l4EqJgzs,5857 -wtforms/locale/et/LC_MESSAGES/wtforms.mo,sha256=xk0veS0BiHnY-7GpFsIZrUC-0Z7UPaXV89WMiWAcLRs,3202 -wtforms/locale/et/LC_MESSAGES/wtforms.po,sha256=w-jnstN_c5s8NtzGwc-xv_16g8wfra6A6Yvdp8Wx2lk,5706 -wtforms/locale/fa/LC_MESSAGES/wtforms.mo,sha256=hrprM-rDJ1MWcRhUZFSn5jDsF9LIJsA0l_553y_qwhY,3796 -wtforms/locale/fa/LC_MESSAGES/wtforms.po,sha256=8ns8sQeTB9H-TeHJ2vSRGhZG4r9hF9aG4QQ1hwMAxvA,6377 -wtforms/locale/fi/LC_MESSAGES/wtforms.mo,sha256=GVCXedqhe-Botom4mMlRr1XKyR1iPnkxqCpUBC57hVw,3152 -wtforms/locale/fi/LC_MESSAGES/wtforms.po,sha256=rnS2nqVVQvaGqPtO4mxX5WAy1AwV8RZ9HEttWHR8ZnY,5661 -wtforms/locale/fr/LC_MESSAGES/wtforms.mo,sha256=ajwVOj920JIbkozJhf5lw63wGq4png3yEsajQ75UsJY,3961 -wtforms/locale/fr/LC_MESSAGES/wtforms.po,sha256=2BJf_hCqhEPGW8yqwv7wveVoP1EocQtRDcSkCZIO1yw,5995 -wtforms/locale/he/LC_MESSAGES/wtforms.mo,sha256=Kpd4x0_Y94JJl7J8AncB8cdmoW48cgKtrqMMpKvBGDA,3265 -wtforms/locale/he/LC_MESSAGES/wtforms.po,sha256=_17cvuiEz-Mbqp5dAa0BYh6pqv-x8JyFc1xFlgnsPZM,5853 -wtforms/locale/hu/LC_MESSAGES/wtforms.mo,sha256=oY_wtIcwQcAwf-6fLq_ZHLyxnj5IuVMzOiQzcgCwO6k,3275 -wtforms/locale/hu/LC_MESSAGES/wtforms.po,sha256=6JoOc56VMYQWEhekeFxdlHlr1qAeP31bFYuZhoYQpWM,5692 -wtforms/locale/it/LC_MESSAGES/wtforms.mo,sha256=gpaOYvoqzhZRYBvus5GOhFqiXba8xc7rgWSkGO9fwhc,3248 -wtforms/locale/it/LC_MESSAGES/wtforms.po,sha256=hBoipFIwf_iCrVEnUEw9KMLRPQdoY-cqHdhIDKYxdo0,5762 -wtforms/locale/ja/LC_MESSAGES/wtforms.mo,sha256=CPHCb9q7ZlSkSfjRvVghL1-SPz4wWBpJDYKOMgO_w80,3481 -wtforms/locale/ja/LC_MESSAGES/wtforms.po,sha256=1u2gjFZ_DVauUt4x-uTlzNOB5jrwqnA24iIsa_81xLQ,5925 -wtforms/locale/kk/LC_MESSAGES/wtforms.mo,sha256=hH-FF6mHH8AcMmQ2YpejeG5sh7xV9WzGr5IYKsT931c,4921 -wtforms/locale/kk/LC_MESSAGES/wtforms.po,sha256=nvWTHiY2xF2zqXm51IIpYGSo2KeJ5OXorZQLWHeB2B4,6898 -wtforms/locale/ko/LC_MESSAGES/wtforms.mo,sha256=qprPrphkxN_xv8nbQuPZtdTYMtfz_tLdddxO4KVMIMc,4291 -wtforms/locale/ko/LC_MESSAGES/wtforms.po,sha256=ztFv6iWLrACRPZrmuKHJ7Q6z2pwQ_QKd6wZJWu5Wl9o,6222 -wtforms/locale/nb/LC_MESSAGES/wtforms.mo,sha256=Gza9rzFM2f4OddYmbCfWbJoRq4h44XmwqgE6SaBGxwM,3080 -wtforms/locale/nb/LC_MESSAGES/wtforms.po,sha256=kczF9khVfrzaQQWGau54zPLemD1dOiMykzcrryPKwkU,5590 -wtforms/locale/nl/LC_MESSAGES/wtforms.mo,sha256=OuHmtAXr-XMlzXb7HAif9qwIuZZGpeuD6tzBy3m3YEY,3732 -wtforms/locale/nl/LC_MESSAGES/wtforms.po,sha256=RVF6zLUzoGXnt8S-GTukCh5cF1s52XG-wjfM3ow5FAo,5702 -wtforms/locale/pl/LC_MESSAGES/wtforms.mo,sha256=mgGAZqiFGPVAlKWaiWw2Y1dwIDYU0h91R_kMqMi2iQw,3428 -wtforms/locale/pl/LC_MESSAGES/wtforms.po,sha256=6CeRI1xqJW7hTsGhfPVMjcLk3470_dqPTHsZ8XKBqVc,5982 -wtforms/locale/pt/LC_MESSAGES/wtforms.mo,sha256=zJO_fssb4UthEuDKAbvePvbbRaqGziUSWcXx1W5MtWg,3892 -wtforms/locale/pt/LC_MESSAGES/wtforms.po,sha256=CVpaus2cfFEJz0hvUlvtQvs-pAzbaU6iI5ezwjFjA6A,5864 -wtforms/locale/ro/LC_MESSAGES/wtforms.mo,sha256=7bDI0iCHH7Zor2C562V44LsMdcxLpotDrNmlN4v97h8,4066 -wtforms/locale/ro/LC_MESSAGES/wtforms.po,sha256=JKyL8AqvI6GVE8fafuQLdfeVjxpL5JpMzYvkqc4HLFs,6398 -wtforms/locale/ru/LC_MESSAGES/wtforms.mo,sha256=3oZzAX1FhUq97FxblEYQRRKS1e8fEi8Mf4A96Ve-Xoo,4712 -wtforms/locale/ru/LC_MESSAGES/wtforms.po,sha256=nqKyMDRunEjnZqmD3-WS0u9sVjme-y6_mZbeYG7A-mM,7298 -wtforms/locale/sk/LC_MESSAGES/wtforms.mo,sha256=iThhdb0IqpjVIMWqgcQbl5-Hpw0Fu71tk8uOsjEcfdI,4054 -wtforms/locale/sk/LC_MESSAGES/wtforms.po,sha256=qg9Gz-k4cXgFj0y4RXyzbyU-jmzM8v7YbiK71junCZ8,6070 -wtforms/locale/sv/LC_MESSAGES/wtforms.mo,sha256=YsnbB0r1qZj7kOTKTYnIDB0xR-7NiKE0ZYBnH32YNjg,3818 -wtforms/locale/sv/LC_MESSAGES/wtforms.po,sha256=-RybPMmY47U8V6SMd6FEJlCc30UWEhYnVMBhf52Zbes,5787 -wtforms/locale/tr/LC_MESSAGES/wtforms.mo,sha256=QL-Cy032r0I4yVl7QflFXPrhy_Z3LXw0AkFgNlOmY1U,3885 -wtforms/locale/tr/LC_MESSAGES/wtforms.po,sha256=-d06BsM5zRIXYo7ZwyOkZY_holg3wDVFSfiP-dar35k,5854 -wtforms/locale/uk/LC_MESSAGES/wtforms.mo,sha256=17MF_xAnTQNjc7q5cUHI3lv9LRniNWEQ2q7MXXHJvR0,5187 -wtforms/locale/uk/LC_MESSAGES/wtforms.po,sha256=xoc7k-1MwCKntuTq0VvVsxzeGTGcKsq9wiQ00SPCKBM,7209 -wtforms/locale/wtforms.pot,sha256=g3_EOPz64hSjq7Ty4zvuoNx4U7LdoA4LoXtmqGIVqhk,4249 -wtforms/locale/zh/LC_MESSAGES/wtforms.mo,sha256=8lDDXliKMno8gBu1kuALzZFJvREJFBttptvfyYJesIQ,3296 -wtforms/locale/zh/LC_MESSAGES/wtforms.po,sha256=AGig61EOm-ir4sOhT0cpr5M10sntLaSng4BK5fvRqgY,5812 -wtforms/locale/zh_TW/LC_MESSAGES/wtforms.mo,sha256=9UZ69bwp4CBVQqBpmLuxCUvdleYqGRP-POOzp3qCDIM,3653 -wtforms/locale/zh_TW/LC_MESSAGES/wtforms.po,sha256=bslNzk1KhLiGhd3fQ9ifAmCTzjgAcTtG_z6K2Sii-Pk,5596 -wtforms/meta.py,sha256=SU8A6gDcd2wDkVzNmSGMLBBly_fMBTKVB7BD6GCfxYo,4097 -wtforms/utils.py,sha256=sAELlf-d7oXBqUbbLvRkefmvU-g6qHGVyPZzpFPWoSo,2399 -wtforms/validators.py,sha256=87C3JWB51wrENcx5I6Ap5gILgJbJWZUM7txxC3lANBg,21927 -wtforms/widgets/__init__.py,sha256=1sUdgvy1mW3g2IarCS7Ejvseh2GquBHGTSh_zz7q41s,1687 -wtforms/widgets/__pycache__/__init__.cpython-310.pyc,, -wtforms/widgets/__pycache__/core.cpython-310.pyc,, -wtforms/widgets/core.py,sha256=aalzXHzQqZkpuMZ892bGpDhNfo9Y9lufF-XdxXnhjUY,15509 diff --git a/venv/Lib/site-packages/wtforms-3.2.1.dist-info/WHEEL b/venv/Lib/site-packages/wtforms-3.2.1.dist-info/WHEEL deleted file mode 100644 index cdd68a4..0000000 --- a/venv/Lib/site-packages/wtforms-3.2.1.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: hatchling 1.25.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/venv/Lib/site-packages/wtforms-3.2.1.dist-info/licenses/LICENSE.rst b/venv/Lib/site-packages/wtforms-3.2.1.dist-info/licenses/LICENSE.rst deleted file mode 100644 index 30cbc2b..0000000 --- a/venv/Lib/site-packages/wtforms-3.2.1.dist-info/licenses/LICENSE.rst +++ /dev/null @@ -1,28 +0,0 @@ -Copyright 2008 WTForms - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/Lib/site-packages/wtforms/__init__.py b/venv/Lib/site-packages/wtforms/__init__.py index 358d67d..9af9f29 100644 --- a/venv/Lib/site-packages/wtforms/__init__.py +++ b/venv/Lib/site-packages/wtforms/__init__.py @@ -1,79 +1,7 @@ from wtforms import validators from wtforms import widgets -from wtforms.fields.choices import RadioField -from wtforms.fields.choices import SelectField -from wtforms.fields.choices import SelectFieldBase -from wtforms.fields.choices import SelectMultipleField -from wtforms.fields.core import Field -from wtforms.fields.core import Flags -from wtforms.fields.core import Label -from wtforms.fields.datetime import DateField -from wtforms.fields.datetime import DateTimeField -from wtforms.fields.datetime import DateTimeLocalField -from wtforms.fields.datetime import MonthField -from wtforms.fields.datetime import TimeField -from wtforms.fields.datetime import WeekField -from wtforms.fields.form import FormField -from wtforms.fields.list import FieldList -from wtforms.fields.numeric import DecimalField -from wtforms.fields.numeric import DecimalRangeField -from wtforms.fields.numeric import FloatField -from wtforms.fields.numeric import IntegerField -from wtforms.fields.numeric import IntegerRangeField -from wtforms.fields.simple import BooleanField -from wtforms.fields.simple import ColorField -from wtforms.fields.simple import EmailField -from wtforms.fields.simple import FileField -from wtforms.fields.simple import HiddenField -from wtforms.fields.simple import MultipleFileField -from wtforms.fields.simple import PasswordField -from wtforms.fields.simple import SearchField -from wtforms.fields.simple import StringField -from wtforms.fields.simple import SubmitField -from wtforms.fields.simple import TelField -from wtforms.fields.simple import TextAreaField -from wtforms.fields.simple import URLField +from wtforms.fields import * from wtforms.form import Form from wtforms.validators import ValidationError -__version__ = "3.2.1" - -__all__ = [ - "validators", - "widgets", - "Form", - "ValidationError", - "SelectField", - "SelectMultipleField", - "SelectFieldBase", - "RadioField", - "Field", - "Flags", - "Label", - "DateTimeField", - "DateField", - "TimeField", - "MonthField", - "DateTimeLocalField", - "WeekField", - "FormField", - "FieldList", - "IntegerField", - "DecimalField", - "FloatField", - "IntegerRangeField", - "DecimalRangeField", - "BooleanField", - "TextAreaField", - "PasswordField", - "FileField", - "MultipleFileField", - "HiddenField", - "SearchField", - "SubmitField", - "StringField", - "TelField", - "URLField", - "EmailField", - "ColorField", -] +__version__ = "3.1.1" diff --git a/venv/Lib/site-packages/wtforms/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/wtforms/__pycache__/__init__.cpython-310.pyc index 36e7a41..9b51c65 100644 Binary files a/venv/Lib/site-packages/wtforms/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/wtforms/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/wtforms/__pycache__/form.cpython-310.pyc b/venv/Lib/site-packages/wtforms/__pycache__/form.cpython-310.pyc index 7057710..0f05036 100644 Binary files a/venv/Lib/site-packages/wtforms/__pycache__/form.cpython-310.pyc and b/venv/Lib/site-packages/wtforms/__pycache__/form.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/wtforms/__pycache__/i18n.cpython-310.pyc b/venv/Lib/site-packages/wtforms/__pycache__/i18n.cpython-310.pyc index b1b399d..419ae8f 100644 Binary files a/venv/Lib/site-packages/wtforms/__pycache__/i18n.cpython-310.pyc and b/venv/Lib/site-packages/wtforms/__pycache__/i18n.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/wtforms/__pycache__/meta.cpython-310.pyc b/venv/Lib/site-packages/wtforms/__pycache__/meta.cpython-310.pyc index 2d42eae..97bf6f4 100644 Binary files a/venv/Lib/site-packages/wtforms/__pycache__/meta.cpython-310.pyc and b/venv/Lib/site-packages/wtforms/__pycache__/meta.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/wtforms/__pycache__/utils.cpython-310.pyc b/venv/Lib/site-packages/wtforms/__pycache__/utils.cpython-310.pyc index fbe55c1..cc20905 100644 Binary files a/venv/Lib/site-packages/wtforms/__pycache__/utils.cpython-310.pyc and b/venv/Lib/site-packages/wtforms/__pycache__/utils.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/wtforms/__pycache__/validators.cpython-310.pyc b/venv/Lib/site-packages/wtforms/__pycache__/validators.cpython-310.pyc index 6c940a7..0807294 100644 Binary files a/venv/Lib/site-packages/wtforms/__pycache__/validators.cpython-310.pyc and b/venv/Lib/site-packages/wtforms/__pycache__/validators.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/wtforms/csrf/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/wtforms/csrf/__pycache__/__init__.cpython-310.pyc index be6e62b..bbf8abf 100644 Binary files a/venv/Lib/site-packages/wtforms/csrf/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/wtforms/csrf/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/wtforms/csrf/__pycache__/core.cpython-310.pyc b/venv/Lib/site-packages/wtforms/csrf/__pycache__/core.cpython-310.pyc index 2ab75e9..d745db2 100644 Binary files a/venv/Lib/site-packages/wtforms/csrf/__pycache__/core.cpython-310.pyc and b/venv/Lib/site-packages/wtforms/csrf/__pycache__/core.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/wtforms/csrf/__pycache__/session.cpython-310.pyc b/venv/Lib/site-packages/wtforms/csrf/__pycache__/session.cpython-310.pyc index 9f1d94e..aedc9c4 100644 Binary files a/venv/Lib/site-packages/wtforms/csrf/__pycache__/session.cpython-310.pyc and b/venv/Lib/site-packages/wtforms/csrf/__pycache__/session.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/wtforms/csrf/session.py b/venv/Lib/site-packages/wtforms/csrf/session.py index d7ddd5b..62ba763 100644 --- a/venv/Lib/site-packages/wtforms/csrf/session.py +++ b/venv/Lib/site-packages/wtforms/csrf/session.py @@ -12,7 +12,6 @@ for extra security) is used as the value of the csrf_token. If this token validates with the hmac of the random value + expiration time, and the expiration time is not passed, the CSRF validation will pass. """ - import hmac import os from datetime import datetime diff --git a/venv/Lib/site-packages/wtforms/fields/__init__.py b/venv/Lib/site-packages/wtforms/fields/__init__.py index 64fb6d3..f72189c 100644 --- a/venv/Lib/site-packages/wtforms/fields/__init__.py +++ b/venv/Lib/site-packages/wtforms/fields/__init__.py @@ -1,71 +1,11 @@ -from wtforms.fields.choices import RadioField -from wtforms.fields.choices import SelectField +from wtforms.fields.choices import * from wtforms.fields.choices import SelectFieldBase -from wtforms.fields.choices import SelectMultipleField from wtforms.fields.core import Field from wtforms.fields.core import Flags from wtforms.fields.core import Label -from wtforms.fields.datetime import DateField -from wtforms.fields.datetime import DateTimeField -from wtforms.fields.datetime import DateTimeLocalField -from wtforms.fields.datetime import MonthField -from wtforms.fields.datetime import TimeField -from wtforms.fields.datetime import WeekField -from wtforms.fields.form import FormField -from wtforms.fields.list import FieldList -from wtforms.fields.numeric import DecimalField -from wtforms.fields.numeric import DecimalRangeField -from wtforms.fields.numeric import FloatField -from wtforms.fields.numeric import IntegerField -from wtforms.fields.numeric import IntegerRangeField -from wtforms.fields.simple import BooleanField -from wtforms.fields.simple import ColorField -from wtforms.fields.simple import EmailField -from wtforms.fields.simple import FileField -from wtforms.fields.simple import HiddenField -from wtforms.fields.simple import MultipleFileField -from wtforms.fields.simple import PasswordField -from wtforms.fields.simple import SearchField -from wtforms.fields.simple import StringField -from wtforms.fields.simple import SubmitField -from wtforms.fields.simple import TelField -from wtforms.fields.simple import TextAreaField -from wtforms.fields.simple import URLField +from wtforms.fields.datetime import * +from wtforms.fields.form import * +from wtforms.fields.list import * +from wtforms.fields.numeric import * +from wtforms.fields.simple import * from wtforms.utils import unset_value as _unset_value - -__all__ = [ - "Field", - "Flags", - "Label", - "SelectField", - "SelectMultipleField", - "SelectFieldBase", - "RadioField", - "DateTimeField", - "DateField", - "TimeField", - "MonthField", - "DateTimeLocalField", - "WeekField", - "FormField", - "IntegerField", - "DecimalField", - "FloatField", - "IntegerRangeField", - "DecimalRangeField", - "BooleanField", - "TextAreaField", - "PasswordField", - "FileField", - "MultipleFileField", - "HiddenField", - "SearchField", - "SubmitField", - "StringField", - "TelField", - "URLField", - "EmailField", - "ColorField", - "FieldList", - "_unset_value", -] diff --git a/venv/Lib/site-packages/wtforms/fields/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/wtforms/fields/__pycache__/__init__.cpython-310.pyc index 316f214..1e0e20d 100644 Binary files a/venv/Lib/site-packages/wtforms/fields/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/wtforms/fields/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/wtforms/fields/__pycache__/choices.cpython-310.pyc b/venv/Lib/site-packages/wtforms/fields/__pycache__/choices.cpython-310.pyc index bb1c913..39d69c9 100644 Binary files a/venv/Lib/site-packages/wtforms/fields/__pycache__/choices.cpython-310.pyc and b/venv/Lib/site-packages/wtforms/fields/__pycache__/choices.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/wtforms/fields/__pycache__/core.cpython-310.pyc b/venv/Lib/site-packages/wtforms/fields/__pycache__/core.cpython-310.pyc index e6a5260..3b95907 100644 Binary files a/venv/Lib/site-packages/wtforms/fields/__pycache__/core.cpython-310.pyc and b/venv/Lib/site-packages/wtforms/fields/__pycache__/core.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/wtforms/fields/__pycache__/datetime.cpython-310.pyc b/venv/Lib/site-packages/wtforms/fields/__pycache__/datetime.cpython-310.pyc index 0f64009..de98c1a 100644 Binary files a/venv/Lib/site-packages/wtforms/fields/__pycache__/datetime.cpython-310.pyc and b/venv/Lib/site-packages/wtforms/fields/__pycache__/datetime.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/wtforms/fields/__pycache__/form.cpython-310.pyc b/venv/Lib/site-packages/wtforms/fields/__pycache__/form.cpython-310.pyc index e35e168..a19ca00 100644 Binary files a/venv/Lib/site-packages/wtforms/fields/__pycache__/form.cpython-310.pyc and b/venv/Lib/site-packages/wtforms/fields/__pycache__/form.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/wtforms/fields/__pycache__/list.cpython-310.pyc b/venv/Lib/site-packages/wtforms/fields/__pycache__/list.cpython-310.pyc index 24ee7a8..3a4631b 100644 Binary files a/venv/Lib/site-packages/wtforms/fields/__pycache__/list.cpython-310.pyc and b/venv/Lib/site-packages/wtforms/fields/__pycache__/list.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/wtforms/fields/__pycache__/numeric.cpython-310.pyc b/venv/Lib/site-packages/wtforms/fields/__pycache__/numeric.cpython-310.pyc index e687a9a..1070dec 100644 Binary files a/venv/Lib/site-packages/wtforms/fields/__pycache__/numeric.cpython-310.pyc and b/venv/Lib/site-packages/wtforms/fields/__pycache__/numeric.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/wtforms/fields/__pycache__/simple.cpython-310.pyc b/venv/Lib/site-packages/wtforms/fields/__pycache__/simple.cpython-310.pyc index 3f88e67..30bdf1f 100644 Binary files a/venv/Lib/site-packages/wtforms/fields/__pycache__/simple.cpython-310.pyc and b/venv/Lib/site-packages/wtforms/fields/__pycache__/simple.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/wtforms/fields/choices.py b/venv/Lib/site-packages/wtforms/fields/choices.py index 62ed497..2b1fd2e 100644 --- a/venv/Lib/site-packages/wtforms/fields/choices.py +++ b/venv/Lib/site-packages/wtforms/fields/choices.py @@ -121,9 +121,8 @@ class SelectField(SelectFieldBase): _choices = zip(choices, choices) for value, label, *other_args in _choices: - selected = self.coerce(value) == self.data render_kw = other_args[0] if len(other_args) else {} - yield (value, label, selected, render_kw) + yield (value, label, self.coerce(value) == self.data, render_kw) def process_data(self, value): try: @@ -174,9 +173,9 @@ class SelectMultipleField(SelectField): else: _choices = zip(choices, choices) - for value, label, *other_args in _choices: + for value, label, *args in _choices: selected = self.data is not None and self.coerce(value) in self.data - render_kw = other_args[0] if len(other_args) else {} + render_kw = args[0] if len(args) else {} yield (value, label, selected, render_kw) def process_data(self, value): @@ -202,11 +201,9 @@ class SelectMultipleField(SelectField): if self.choices is None: raise TypeError(self.gettext("Choices cannot be None.")) - acceptable = [self.coerce(choice[0]) for choice in self.iter_choices()] - if any(data not in acceptable for data in self.data): - unacceptable = [ - str(data) for data in set(self.data) if data not in acceptable - ] + acceptable = {c[0] for c in self.iter_choices()} + if any(d not in acceptable for d in self.data): + unacceptable = [str(d) for d in set(self.data) - acceptable] raise ValidationError( self.ngettext( "'%(value)s' is not a valid choice for this field.", diff --git a/venv/Lib/site-packages/wtforms/fields/core.py b/venv/Lib/site-packages/wtforms/fields/core.py index 2155a89..2aba500 100644 --- a/venv/Lib/site-packages/wtforms/fields/core.py +++ b/venv/Lib/site-packages/wtforms/fields/core.py @@ -1,5 +1,6 @@ import inspect import itertools +import warnings from markupsafe import escape from markupsafe import Markup @@ -130,6 +131,17 @@ class Field: for v in itertools.chain(self.validators, [self.widget]): flags = getattr(v, "field_flags", {}) + # check for legacy format, remove eventually + if isinstance(flags, tuple): # pragma: no cover + warnings.warn( + "Flags should be stored in dicts and not in tuples. " + "The next version of WTForms will abandon support " + "for flags in tuples.", + DeprecationWarning, + stacklevel=2, + ) + flags = {flag_name: True for flag_name in flags} + for k, v in flags.items(): setattr(self.flags, k, v) @@ -169,14 +181,14 @@ class Field: for validator in validators: if not callable(validator): raise TypeError( - f"{validator} is not a valid validator because it is not " - "callable" + "{} is not a valid validator because it is not " + "callable".format(validator) ) if inspect.isclass(validator): raise TypeError( - f"{validator} is not a valid validator because it is a class, " - "it should be an instance" + "{} is not a valid validator because it is a class, " + "it should be an instance".format(validator) ) def gettext(self, string): @@ -387,10 +399,8 @@ class UnboundField: return self.field_class(*self.args, **kw) def __repr__(self): - return ( - "" + return "".format( + self.field_class.__name__, self.args, self.kwargs ) @@ -415,8 +425,7 @@ class Flags: for name in dir(self) if not name.startswith("_") ) - flags = ", ".join(flags) - return f"" + return "" % ", ".join(flags) class Label: diff --git a/venv/Lib/site-packages/wtforms/fields/datetime.py b/venv/Lib/site-packages/wtforms/fields/datetime.py index ac22951..63e32d7 100644 --- a/venv/Lib/site-packages/wtforms/fields/datetime.py +++ b/venv/Lib/site-packages/wtforms/fields/datetime.py @@ -34,8 +34,7 @@ class DateTimeField(Field): def _value(self): if self.raw_data: return " ".join(self.raw_data) - format = self.format[0] - return self.data and self.data.strftime(format) or "" + return self.data and self.data.strftime(self.format[0]) or "" def process_formdata(self, valuelist): if not valuelist: diff --git a/venv/Lib/site-packages/wtforms/fields/form.py b/venv/Lib/site-packages/wtforms/fields/form.py index 10fb30e..83f5abe 100644 --- a/venv/Lib/site-packages/wtforms/fields/form.py +++ b/venv/Lib/site-packages/wtforms/fields/form.py @@ -1,7 +1,6 @@ -from wtforms.utils import unset_value - from .. import widgets from .core import Field +from wtforms.utils import unset_value __all__ = ("FormField",) diff --git a/venv/Lib/site-packages/wtforms/fields/list.py b/venv/Lib/site-packages/wtforms/fields/list.py index dabd8b4..db52bc0 100644 --- a/venv/Lib/site-packages/wtforms/fields/list.py +++ b/venv/Lib/site-packages/wtforms/fields/list.py @@ -1,10 +1,9 @@ import itertools -from wtforms.utils import unset_value - from .. import widgets from .core import Field from .core import UnboundField +from wtforms.utils import unset_value __all__ = ("FieldList",) diff --git a/venv/Lib/site-packages/wtforms/form.py b/venv/Lib/site-packages/wtforms/form.py index d0a77ba..c6805c7 100644 --- a/venv/Lib/site-packages/wtforms/form.py +++ b/venv/Lib/site-packages/wtforms/form.py @@ -30,7 +30,6 @@ class BaseForm: prefix += "-" self.meta = meta - self._form_error_key = "" self._prefix = prefix self._fields = OrderedDict() @@ -114,7 +113,7 @@ class BaseForm: for name, field in self._fields.items(): field_extra_filters = filters.get(name, []) - inline_filter = getattr(self, f"filter_{name}", None) + inline_filter = getattr(self, "filter_%s" % name, None) if inline_filter is not None: field_extra_filters.append(inline_filter) @@ -156,7 +155,7 @@ class BaseForm: def errors(self): errors = {name: f.errors for name, f in self._fields.items() if f.errors} if self.form_errors: - errors[self._form_error_key] = self.form_errors + errors[None] = self.form_errors return errors diff --git a/venv/Lib/site-packages/wtforms/locale/ar/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/ar/LC_MESSAGES/wtforms.mo index 21a0725..723b023 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/ar/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/ar/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/ar/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/ar/LC_MESSAGES/wtforms.po index 3e9f9e3..4ccef2e 100644 --- a/venv/Lib/site-packages/wtforms/locale/ar/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/ar/LC_MESSAGES/wtforms.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 2.0dev\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" "PO-Revision-Date: 2015-04-08 20:59+0100\n" "Last-Translator: Jalal Maqdisi \n" "Language-Team: ar \n" @@ -123,11 +123,11 @@ msgstr "قيمة غير صالحة، يجب أن تكون اي من: %(values)s. #: src/wtforms/validators.py:698 #, fuzzy #| msgid "This field is required." -msgid "This field cannot be edited." +msgid "This field cannot be edited" msgstr "هذا الحقل مطلوب." #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." +msgid "This field is disabled and cannot have a value" msgstr "" #: src/wtforms/csrf/core.py:96 @@ -146,23 +146,23 @@ msgstr "CSRF قد فشل." msgid "CSRF token expired." msgstr "انتهت صلاحية رمز CSRF." -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "اختيار غير صالح: لا يمكن الاجبار." -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "" -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "اختيار غير صحيح." -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "اختيارات غير صالحة: واحدة او اكثر من الادخالات لا يمكن اجبارها." -#: src/wtforms/fields/choices.py:214 +#: src/wtforms/fields/choices.py:204 #, fuzzy, python-format #| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." diff --git a/venv/Lib/site-packages/wtforms/locale/bg/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/bg/LC_MESSAGES/wtforms.mo index 24c7fc5..33cb9fd 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/bg/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/bg/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/bg/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/bg/LC_MESSAGES/wtforms.po index 2398b87..a88b399 100644 --- a/venv/Lib/site-packages/wtforms/locale/bg/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/bg/LC_MESSAGES/wtforms.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 2.0dev\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" "PO-Revision-Date: 2017-02-16 11:59+0100\n" "Last-Translator: \n" "Language-Team: Vladimir Kolev \n" @@ -110,11 +110,11 @@ msgstr "Невалидна стойност, не може да бъде едн #: src/wtforms/validators.py:698 #, fuzzy #| msgid "This field is required." -msgid "This field cannot be edited." +msgid "This field cannot be edited" msgstr "Това поле е задължително" #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." +msgid "This field is disabled and cannot have a value" msgstr "" #: src/wtforms/csrf/core.py:96 @@ -133,25 +133,25 @@ msgstr "CSRF провален" msgid "CSRF token expired." msgstr "CSRF token изтече" -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "Невалиден избор: не може да бъде преобразувана" -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "" -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "Не е валиден избор" -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "" "Невалиден(и) избор(и): една или повече въведени данни не могат да бъдат " "преобразувани" -#: src/wtforms/fields/choices.py:214 +#: src/wtforms/fields/choices.py:204 #, fuzzy, python-format #| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." diff --git a/venv/Lib/site-packages/wtforms/locale/ca/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/ca/LC_MESSAGES/wtforms.mo index 678f013..f34b10e 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/ca/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/ca/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/ca/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/ca/LC_MESSAGES/wtforms.po index 8389f77..0015e67 100644 --- a/venv/Lib/site-packages/wtforms/locale/ca/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/ca/LC_MESSAGES/wtforms.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 2.0dev\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" "PO-Revision-Date: 2014-01-16 09:58+0100\n" "Last-Translator: Òscar Vilaplana \n" "Language-Team: ca \n" @@ -110,11 +110,11 @@ msgstr "Valor no vàlid, no pot ser cap d'aquests: %(values)s." #: src/wtforms/validators.py:698 #, fuzzy #| msgid "This field is required." -msgid "This field cannot be edited." +msgid "This field cannot be edited" msgstr "Aquest camp és obligatori." #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." +msgid "This field is disabled and cannot have a value" msgstr "" #: src/wtforms/csrf/core.py:96 @@ -133,24 +133,24 @@ msgstr "Ha fallat la comprovació de CSRF" msgid "CSRF token expired." msgstr "Token CSRF caducat" -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "Opció no vàlida" -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "" -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "Opció no acceptada" -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "" "Opció o opcions no vàlides: alguna de les entrades no s'ha pogut processar" -#: src/wtforms/fields/choices.py:214 +#: src/wtforms/fields/choices.py:204 #, fuzzy, python-format #| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." diff --git a/venv/Lib/site-packages/wtforms/locale/cs_CZ/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/cs_CZ/LC_MESSAGES/wtforms.mo index b2812ba..14684d3 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/cs_CZ/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/cs_CZ/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/cs_CZ/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/cs_CZ/LC_MESSAGES/wtforms.po index ffa6e3d..a0cfb6f 100644 --- a/venv/Lib/site-packages/wtforms/locale/cs_CZ/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/cs_CZ/LC_MESSAGES/wtforms.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 2.0.2dev\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Daniil Barabash \n" "Language-Team: cz \n" @@ -113,11 +113,11 @@ msgstr "Neplatná hodnota, nesmí být mezi: %(values)s." #: src/wtforms/validators.py:698 #, fuzzy #| msgid "This field is required." -msgid "This field cannot be edited." +msgid "This field cannot be edited" msgstr "Toto pole je povinné." #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." +msgid "This field is disabled and cannot have a value" msgstr "" #: src/wtforms/csrf/core.py:96 @@ -136,23 +136,23 @@ msgstr "Chyba CSRF." msgid "CSRF token expired." msgstr "Hodnota CSRF tokenu." -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "Neplatná volba: nelze převést." -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "" -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "Neplatná volba." -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "Neplatná volba: jeden nebo více datových vstupů nemohou být převedeny." -#: src/wtforms/fields/choices.py:214 +#: src/wtforms/fields/choices.py:204 #, fuzzy, python-format #| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." diff --git a/venv/Lib/site-packages/wtforms/locale/cy/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/cy/LC_MESSAGES/wtforms.mo index 3df36bd..cfd16c3 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/cy/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/cy/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/cy/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/cy/LC_MESSAGES/wtforms.po index ce6b802..a13c8a0 100644 --- a/venv/Lib/site-packages/wtforms/locale/cy/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/cy/LC_MESSAGES/wtforms.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 2.0dev\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" "PO-Revision-Date: 2015-01-29 14:07+0000\n" "Last-Translator: Josh Rowe josh.rowe@digital.justice.gov.uk\n" "Language-Team: cy \n" @@ -110,11 +110,11 @@ msgstr "Gwerth annilys, ni all fod yn un o'r canlynol: %(values)s" #: src/wtforms/validators.py:698 #, fuzzy #| msgid "This field is required." -msgid "This field cannot be edited." +msgid "This field cannot be edited" msgstr "Rhaid cwblhau'r maes hwn." #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." +msgid "This field is disabled and cannot have a value" msgstr "" #: src/wtforms/csrf/core.py:96 @@ -133,24 +133,24 @@ msgstr "CSRF wedi methu" msgid "CSRF token expired." msgstr "Tocyn CSRF wedi dod i ben" -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "Dewis annilys: ddim yn bosib gweithredu" -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "" -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "Nid yw hwn yn ddewis dilys" -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "" "Dewis(iadau) annilys: ddim yn bosib gweithredu un neu ragor o fewnbynnau data" -#: src/wtforms/fields/choices.py:214 +#: src/wtforms/fields/choices.py:204 #, fuzzy, python-format #| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." diff --git a/venv/Lib/site-packages/wtforms/locale/de/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/de/LC_MESSAGES/wtforms.mo index 0e762fb..69fa09b 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/de/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/de/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/de/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/de/LC_MESSAGES/wtforms.po index ef530ad..f83ed2a 100644 --- a/venv/Lib/site-packages/wtforms/locale/de/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/de/LC_MESSAGES/wtforms.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 1.0.4\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" "PO-Revision-Date: 2013-05-13 19:27+0100\n" "Last-Translator: Chris Buergi \n" "Language-Team: de \n" @@ -110,11 +110,11 @@ msgstr "Ungültiger Wert. Wert kann keiner von folgenden sein: %(values)s." #: src/wtforms/validators.py:698 #, fuzzy #| msgid "This field is required." -msgid "This field cannot be edited." +msgid "This field cannot be edited" msgstr "Dieses Feld wird benötigt." #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." +msgid "This field is disabled and cannot have a value" msgstr "" #: src/wtforms/csrf/core.py:96 @@ -133,25 +133,25 @@ msgstr "CSRF fehlgeschlagen." msgid "CSRF token expired." msgstr "CSRF-Code verfallen." -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "Ungültige Auswahl: Konnte nicht umwandeln." -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "" -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "Keine gültige Auswahl." -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "" "Ungültige Auswahl: Einer oder mehrere Eingaben konnten nicht umgewandelt " "werden." -#: src/wtforms/fields/choices.py:214 +#: src/wtforms/fields/choices.py:204 #, fuzzy, python-format #| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." diff --git a/venv/Lib/site-packages/wtforms/locale/de_CH/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/de_CH/LC_MESSAGES/wtforms.mo index af06d6f..9abf433 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/de_CH/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/de_CH/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/de_CH/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/de_CH/LC_MESSAGES/wtforms.po index 323f32c..a09f7e5 100644 --- a/venv/Lib/site-packages/wtforms/locale/de_CH/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/de_CH/LC_MESSAGES/wtforms.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 1.0.4\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" "PO-Revision-Date: 2013-05-13 19:27+0100\n" "Last-Translator: Chris Buergi \n" "Language-Team: de_CH \n" @@ -110,11 +110,11 @@ msgstr "Ungültiger Wert. Wert kann keiner von folgenden sein: %(values)s." #: src/wtforms/validators.py:698 #, fuzzy #| msgid "This field is required." -msgid "This field cannot be edited." +msgid "This field cannot be edited" msgstr "Dieses Feld wird benötigt." #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." +msgid "This field is disabled and cannot have a value" msgstr "" #: src/wtforms/csrf/core.py:96 @@ -133,25 +133,25 @@ msgstr "CSRF fehlgeschlagen" msgid "CSRF token expired." msgstr "CSRF-Code verfallen" -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "Ungültige Auswahl: Konnte nicht umwandeln" -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "" -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "Keine gültige Auswahl" -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "" "Ungültige Auswahl: Einer oder mehrere Eingaben konnten nicht umgewandelt " "werden." -#: src/wtforms/fields/choices.py:214 +#: src/wtforms/fields/choices.py:204 #, fuzzy, python-format #| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." diff --git a/venv/Lib/site-packages/wtforms/locale/el/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/el/LC_MESSAGES/wtforms.mo index 155d06b..6c77216 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/el/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/el/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/el/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/el/LC_MESSAGES/wtforms.po index d3035c9..06d5587 100644 --- a/venv/Lib/site-packages/wtforms/locale/el/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/el/LC_MESSAGES/wtforms.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 2.0dev\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" "PO-Revision-Date: 2014-04-04 20:18+0300\n" "Last-Translator: Daniel Dourvaris \n" "Language-Team: el \n" @@ -110,11 +110,11 @@ msgstr "Λάθος επιλογή, δεν μπορεί να είναι ένα α #: src/wtforms/validators.py:698 #, fuzzy #| msgid "This field is required." -msgid "This field cannot be edited." +msgid "This field cannot be edited" msgstr "Αυτό το πεδίο είναι υποχρεωτικό" #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." +msgid "This field is disabled and cannot have a value" msgstr "" #: src/wtforms/csrf/core.py:96 @@ -133,23 +133,23 @@ msgstr "Αποτυχία CSRF" msgid "CSRF token expired." msgstr "Έχει λήξει το διακριτικό CSRF" -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "Λανθασμένη Επιλογή: δεν μετατρέπεται" -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "" -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "Άγνωστη επιλογή" -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "Λανθασμένη επιλογή(ές): κάποιες τιμές δεν μπορούσαν να μετατραπούν" -#: src/wtforms/fields/choices.py:214 +#: src/wtforms/fields/choices.py:204 #, fuzzy, python-format #| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." diff --git a/venv/Lib/site-packages/wtforms/locale/en/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/en/LC_MESSAGES/wtforms.mo index e365816..2e8a0b1 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/en/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/en/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/es/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/es/LC_MESSAGES/wtforms.mo index c67cbf1..6f19672 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/es/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/es/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/es/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/es/LC_MESSAGES/wtforms.po index db13ca4..df705b1 100644 --- a/venv/Lib/site-packages/wtforms/locale/es/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/es/LC_MESSAGES/wtforms.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 1.0\n" "Report-Msgid-Bugs-To: eloi.rivard@nubla.fr\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" -"PO-Revision-Date: 2024-01-15 09:06+0000\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" +"PO-Revision-Date: 2023-10-06 21:11+0000\n" "Last-Translator: gallegonovato \n" "Language-Team: Spanish \n" @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.4-dev\n" +"X-Generator: Weblate 5.1-dev\n" "Generated-By: Babel 2.8.0\n" #: src/wtforms/validators.py:86 @@ -110,12 +110,12 @@ msgid "Invalid value, can't be any of: %(values)s." msgstr "Valor inválido, no puede ser ninguno de: %(values)s." #: src/wtforms/validators.py:698 -msgid "This field cannot be edited." -msgstr "Este campo no se puede editar." +msgid "This field cannot be edited" +msgstr "Este campo no se puede editar" #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." -msgstr "Este campo está desactivado y no puede tener un valor." +msgid "This field is disabled and cannot have a value" +msgstr "Este campo está deshabilitado y no puede tener un valor" #: src/wtforms/csrf/core.py:96 msgid "Invalid CSRF Token." @@ -133,25 +133,25 @@ msgstr "Fallo CSRF." msgid "CSRF token expired." msgstr "El token CSRF ha expirado." -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "Elección inválida: no se puede ajustar." -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "La elección no puede ser None." -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "Opción inválida." -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "" "Opción(es) inválida(s): una o más entradas de datos no pueden ser " "coaccionadas." -#: src/wtforms/fields/choices.py:214 +#: src/wtforms/fields/choices.py:204 #, python-format msgid "'%(value)s' is not a valid choice for this field." msgid_plural "'%(value)s' are not valid choices for this field." diff --git a/venv/Lib/site-packages/wtforms/locale/et/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/et/LC_MESSAGES/wtforms.mo index 5793358..d85f925 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/et/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/et/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/et/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/et/LC_MESSAGES/wtforms.po index 8241a60..7d5ff0e 100644 --- a/venv/Lib/site-packages/wtforms/locale/et/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/et/LC_MESSAGES/wtforms.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 1.0.6dev\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" "PO-Revision-Date: 2013-09-22 12:37+0300\n" "Last-Translator: Laur Mõtus \n" "Language-Team: Estonian \n" @@ -110,11 +110,11 @@ msgstr "Vigane väärtus, ei tohi olla ükski järgnevatest: %(values)s." #: src/wtforms/validators.py:698 #, fuzzy #| msgid "This field is required." -msgid "This field cannot be edited." +msgid "This field cannot be edited" msgstr "Kohustuslik väli." #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." +msgid "This field is disabled and cannot have a value" msgstr "" #: src/wtforms/csrf/core.py:96 @@ -133,23 +133,23 @@ msgstr "CSRF nurjus" msgid "CSRF token expired." msgstr "CSRF tunnus on aegunud" -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "Vigane valik: ei saa teisendada" -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "" -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "Pole korrektne valik" -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "Vigane valik: ühte või rohkemat andmesisendit ei saa teisendada" -#: src/wtforms/fields/choices.py:214 +#: src/wtforms/fields/choices.py:204 #, fuzzy, python-format #| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." diff --git a/venv/Lib/site-packages/wtforms/locale/fa/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/fa/LC_MESSAGES/wtforms.mo index 319928b..1acf6ef 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/fa/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/fa/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/fa/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/fa/LC_MESSAGES/wtforms.po index 979ce02..127cb56 100644 --- a/venv/Lib/site-packages/wtforms/locale/fa/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/fa/LC_MESSAGES/wtforms.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 1.0.3\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" "PO-Revision-Date: 2013-01-20 16:49+0330\n" "Last-Translator: mohammad Efazati \n" "Language-Team: fa \n" @@ -109,11 +109,11 @@ msgstr "ورودی اشتباه است. نباید یکی از %(values)s باش #: src/wtforms/validators.py:698 #, fuzzy #| msgid "This field is required." -msgid "This field cannot be edited." +msgid "This field cannot be edited" msgstr "این فیلد اجباریست." #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." +msgid "This field is disabled and cannot have a value" msgstr "" #: src/wtforms/csrf/core.py:96 @@ -132,23 +132,23 @@ msgstr "کلید امنیتی با خطا مواجه شد." msgid "CSRF token expired." msgstr "زمان استفاده از کلید امنیتی به اتمام رسیده است." -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "انتخاب شما اشتباه است. ورودی قابل بررسی نیست." -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "" -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "انتخاب درستی نیست." -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "انتخاب شما اشتباه است. یک یا چند تا از ورودی ها قابل بررسی نیست." -#: src/wtforms/fields/choices.py:214 +#: src/wtforms/fields/choices.py:204 #, fuzzy, python-format #| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." diff --git a/venv/Lib/site-packages/wtforms/locale/fi/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/fi/LC_MESSAGES/wtforms.mo index 8286dff..3b62bc4 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/fi/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/fi/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/fi/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/fi/LC_MESSAGES/wtforms.po index 2e8c0e5..0bea31b 100644 --- a/venv/Lib/site-packages/wtforms/locale/fi/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/fi/LC_MESSAGES/wtforms.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 2.0dev\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" "PO-Revision-Date: 2016-06-13 15:16+0300\n" "Last-Translator: Teijo Mursu \n" "Language-Team: fi \n" @@ -110,11 +110,11 @@ msgstr "Epäkelpo arvo, ei voi olla yksi seuraavista: %(values)s." #: src/wtforms/validators.py:698 #, fuzzy #| msgid "This field is required." -msgid "This field cannot be edited." +msgid "This field cannot be edited" msgstr "Pakollinen." #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." +msgid "This field is disabled and cannot have a value" msgstr "" #: src/wtforms/csrf/core.py:96 @@ -133,23 +133,23 @@ msgstr "CSRF epäonnistui" msgid "CSRF token expired." msgstr "CSRF-tunnus vanhentunut" -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "Virheellinen valinta: ei voida muuntaa" -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "" -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "Virheellinen valinta" -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "Virheellinen valinta: Yksi tai useampaa syötettä ei voitu muuntaa" -#: src/wtforms/fields/choices.py:214 +#: src/wtforms/fields/choices.py:204 #, fuzzy, python-format #| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." diff --git a/venv/Lib/site-packages/wtforms/locale/fr/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/fr/LC_MESSAGES/wtforms.mo index 3887789..389e4b8 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/fr/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/fr/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/fr/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/fr/LC_MESSAGES/wtforms.po index ccf0757..8a25807 100644 --- a/venv/Lib/site-packages/wtforms/locale/fr/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/fr/LC_MESSAGES/wtforms.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 1.0.3\n" "Report-Msgid-Bugs-To: eloi.rivard@nubla.fr\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" -"PO-Revision-Date: 2024-01-11 20:06+0000\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" +"PO-Revision-Date: 2023-10-06 21:11+0000\n" "Last-Translator: Éloi Rivard \n" "Language-Team: French \n" @@ -18,7 +18,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 5.4-dev\n" +"X-Generator: Weblate 5.1-dev\n" "Generated-By: Babel 2.8.0\n" #: src/wtforms/validators.py:86 @@ -112,12 +112,12 @@ msgid "Invalid value, can't be any of: %(values)s." msgstr "Valeur non valide, ne peut contenir : %(values)s." #: src/wtforms/validators.py:698 -msgid "This field cannot be edited." -msgstr "Ce champ n’est pas éditable." +msgid "This field cannot be edited" +msgstr "Ce champ n’est pas éditable" #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." -msgstr "Ce champ est désactivé et ne peut avoir de valeur." +msgid "This field is disabled and cannot have a value" +msgstr "Ce champ est désactivé et ne peut avoir de valeur" #: src/wtforms/csrf/core.py:96 msgid "Invalid CSRF Token." @@ -135,24 +135,24 @@ msgstr "CSRF a échoué." msgid "CSRF token expired." msgstr "Jeton CSRF expiré." -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "Choix non valide, ne peut pas être converti." -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "Vous devez choisir au moins un élément." -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "N'est pas un choix valide." -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "" "Choix incorrect, une ou plusieurs saisies ne peuvent pas être converties." -#: src/wtforms/fields/choices.py:214 +#: src/wtforms/fields/choices.py:204 #, python-format msgid "'%(value)s' is not a valid choice for this field." msgid_plural "'%(value)s' are not valid choices for this field." diff --git a/venv/Lib/site-packages/wtforms/locale/he/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/he/LC_MESSAGES/wtforms.mo index 252f8dc..b16091c 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/he/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/he/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/he/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/he/LC_MESSAGES/wtforms.po index 91c19d5..a96f927 100644 --- a/venv/Lib/site-packages/wtforms/locale/he/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/he/LC_MESSAGES/wtforms.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 2.0dev\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" "PO-Revision-Date: 2017-04-19 00:41+0300\n" "Last-Translator: Tomer Levy \n" "Language-Team: he \n" @@ -110,11 +110,11 @@ msgstr "ערך לא חוקי, לא יכול להיות מתוך: %(values)s." #: src/wtforms/validators.py:698 #, fuzzy #| msgid "This field is required." -msgid "This field cannot be edited." +msgid "This field cannot be edited" msgstr "חובה למלא שדה זה." #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." +msgid "This field is disabled and cannot have a value" msgstr "" #: src/wtforms/csrf/core.py:96 @@ -133,23 +133,23 @@ msgstr "CSRF נכשל" msgid "CSRF token expired." msgstr "מזהה CSRF פג תוקף" -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "" -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "" -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "לא בחירה חוקית" -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "בחירה\\ות לא תקינה: לא ניתן לכפות סוג על קלט אחד או יותר" -#: src/wtforms/fields/choices.py:214 +#: src/wtforms/fields/choices.py:204 #, fuzzy, python-format #| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." diff --git a/venv/Lib/site-packages/wtforms/locale/hu/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/hu/LC_MESSAGES/wtforms.mo index d8bdfe2..40ddc56 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/hu/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/hu/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/hu/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/hu/LC_MESSAGES/wtforms.po index f914302..577d703 100644 --- a/venv/Lib/site-packages/wtforms/locale/hu/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/hu/LC_MESSAGES/wtforms.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 2.0dev\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" "PO-Revision-Date: 2016-09-27 13:09-0400\n" "Last-Translator: Zoltan Fedor \n" "Language-Team: Hungarian <>\n" @@ -110,11 +110,11 @@ msgstr "Érvénytelen adat, a következőek egyike sem lehet: %(values)s." #: src/wtforms/validators.py:698 #, fuzzy #| msgid "This field is required." -msgid "This field cannot be edited." +msgid "This field cannot be edited" msgstr "Ez a mező kötelező." #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." +msgid "This field is disabled and cannot have a value" msgstr "" #: src/wtforms/csrf/core.py:96 @@ -133,23 +133,23 @@ msgstr "CSRF hiba" msgid "CSRF token expired." msgstr "Lejárt CSRF token" -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "Érvénytelen választás: adat nem használható" -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "" -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "Érvénytelen érték" -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "Érvénytelen választás: egy vagy több adat elem nem használható" -#: src/wtforms/fields/choices.py:214 +#: src/wtforms/fields/choices.py:204 #, fuzzy, python-format #| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." diff --git a/venv/Lib/site-packages/wtforms/locale/it/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/it/LC_MESSAGES/wtforms.mo index e7b83f3..2095cfd 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/it/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/it/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/it/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/it/LC_MESSAGES/wtforms.po index 33d9d31..8d2c783 100644 --- a/venv/Lib/site-packages/wtforms/locale/it/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/it/LC_MESSAGES/wtforms.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 2.0dev\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" "PO-Revision-Date: 2017-03-01 11:53+0100\n" "Last-Translator: \n" "Language-Team: \n" @@ -111,11 +111,11 @@ msgstr "Valore non valido, non può essere nessuno tra: %(values)s." #: src/wtforms/validators.py:698 #, fuzzy #| msgid "This field is required." -msgid "This field cannot be edited." +msgid "This field cannot be edited" msgstr "Questo campo è obbligatorio." #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." +msgid "This field is disabled and cannot have a value" msgstr "" #: src/wtforms/csrf/core.py:96 @@ -134,24 +134,24 @@ msgstr "CSRF fallito" msgid "CSRF token expired." msgstr "Token CSRF scaduto" -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "Opzione non valida: valore non convertibile" -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "" -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "Non è una opzione valida" -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "" "Opzione(i) non valida(e): uno o pù valori non possono essere convertiti" -#: src/wtforms/fields/choices.py:214 +#: src/wtforms/fields/choices.py:204 #, fuzzy, python-format #| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." diff --git a/venv/Lib/site-packages/wtforms/locale/ja/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/ja/LC_MESSAGES/wtforms.mo index 5f04957..91df7aa 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/ja/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/ja/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/ja/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/ja/LC_MESSAGES/wtforms.po index f650bc2..2e62ba2 100644 --- a/venv/Lib/site-packages/wtforms/locale/ja/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/ja/LC_MESSAGES/wtforms.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 2.0dev\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" "PO-Revision-Date: 2015-07-06 23:49+0900\n" "Last-Translator: yusuke furukawa \n" "Language-Team: ja \n" @@ -107,11 +107,11 @@ msgstr "無効な値です、次に含まれるものは使えません: %(value #: src/wtforms/validators.py:698 #, fuzzy #| msgid "This field is required." -msgid "This field cannot be edited." +msgid "This field cannot be edited" msgstr "このフィールドは必須です。" #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." +msgid "This field is disabled and cannot have a value" msgstr "" #: src/wtforms/csrf/core.py:96 @@ -130,23 +130,23 @@ msgstr "CSRF認証に失敗しました。" msgid "CSRF token expired." msgstr "CSRFトークンの期限が切れました。" -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "無効な選択: 型変換できません。" -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "" -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "選択肢が正しくありません。" -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "無効な選択: 1つ以上の値を型変換できません。" -#: src/wtforms/fields/choices.py:214 +#: src/wtforms/fields/choices.py:204 #, fuzzy, python-format #| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." diff --git a/venv/Lib/site-packages/wtforms/locale/kk/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/kk/LC_MESSAGES/wtforms.mo deleted file mode 100644 index 5329f6e..0000000 Binary files a/venv/Lib/site-packages/wtforms/locale/kk/LC_MESSAGES/wtforms.mo and /dev/null differ diff --git a/venv/Lib/site-packages/wtforms/locale/kk/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/kk/LC_MESSAGES/wtforms.po deleted file mode 100644 index ce09e44..0000000 --- a/venv/Lib/site-packages/wtforms/locale/kk/LC_MESSAGES/wtforms.po +++ /dev/null @@ -1,187 +0,0 @@ -# Translations template for WTForms. -# Copyright (C) 2024 WTForms Team -# This file is distributed under the same license as the WTForms project. -# FIRST AUTHOR , 2024. -# -msgid "" -msgstr "" -"Project-Id-Version: WTForms 3.0.0\n" -"Report-Msgid-Bugs-To: eloi.rivard@nubla.fr\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" -"PO-Revision-Date: 2024-03-11 07:01+0000\n" -"Last-Translator: Baurzhan Muftakhidinov \n" -"Language-Team: Kazakh \n" -"Language: kk\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.5-dev\n" -"Generated-By: Babel 2.12.1\n" - -#: src/wtforms/validators.py:86 -#, python-format -msgid "Invalid field name '%s'." -msgstr "Жарамсыз '%s' өріс атауы." - -#: src/wtforms/validators.py:99 -#, python-format -msgid "Field must be equal to %(other_name)s." -msgstr "Өріс мәні %(other_name)s өрісімен бірдей болуы тиіс." - -#: src/wtforms/validators.py:145 -#, python-format -msgid "Field must be at least %(min)d character long." -msgid_plural "Field must be at least %(min)d characters long." -msgstr[0] "Өріс ұзындығы кем дегенде %(min)d таңба болуы тиіс." -msgstr[1] "Өріс ұзындығы кем дегенде %(min)d таңба болуы тиіс." - -#: src/wtforms/validators.py:151 -#, python-format -msgid "Field cannot be longer than %(max)d character." -msgid_plural "Field cannot be longer than %(max)d characters." -msgstr[0] "Өріс ұзындығы көп дегенде %(max)d таңба болуы тиіс." -msgstr[1] "Өріс ұзындығы көп дегенде %(max)d таңба болуы тиіс." - -#: src/wtforms/validators.py:157 -#, python-format -msgid "Field must be exactly %(max)d character long." -msgid_plural "Field must be exactly %(max)d characters long." -msgstr[0] "Өріс ұзындығы дәл %(max)d таңба болуы тиіс." -msgstr[1] "Өріс ұзындығы дәл %(max)d таңба болуы тиіс." - -#: src/wtforms/validators.py:163 -#, python-format -msgid "Field must be between %(min)d and %(max)d characters long." -msgstr "Өріс ұзындығы %(min)d және %(max)d таңба арасында болуы тиіс." - -#: src/wtforms/validators.py:216 -#, python-format -msgid "Number must be at least %(min)s." -msgstr "Сан кем дегенде %(min)s болуы тиіс." - -#: src/wtforms/validators.py:219 -#, python-format -msgid "Number must be at most %(max)s." -msgstr "Сан көп дегенде %(max)s болуы тиіс." - -#: src/wtforms/validators.py:222 -#, python-format -msgid "Number must be between %(min)s and %(max)s." -msgstr "Сан %(min)s және %(max)s аралығында болуы тиіс." - -#: src/wtforms/validators.py:293 src/wtforms/validators.py:323 -msgid "This field is required." -msgstr "Бұл өріс міндетті түрде керек." - -#: src/wtforms/validators.py:358 -msgid "Invalid input." -msgstr "Жарасыз енгізу." - -#: src/wtforms/validators.py:422 -msgid "Invalid email address." -msgstr "Жарамсыз эл. пошта адресі." - -#: src/wtforms/validators.py:460 -msgid "Invalid IP address." -msgstr "Жарамсыз IP адрес." - -#: src/wtforms/validators.py:503 -msgid "Invalid Mac address." -msgstr "Жарамсыз Mac адрес." - -#: src/wtforms/validators.py:540 -msgid "Invalid URL." -msgstr "Жарамсыз URL адресі." - -#: src/wtforms/validators.py:561 -msgid "Invalid UUID." -msgstr "Жарамсыз UUID." - -#: src/wtforms/validators.py:594 -#, python-format -msgid "Invalid value, must be one of: %(values)s." -msgstr "Жарамсыз мән, келесінің біреуі болуы тиіс: %(values)s." - -#: src/wtforms/validators.py:629 -#, python-format -msgid "Invalid value, can't be any of: %(values)s." -msgstr "Жарамсыз мән, келесінің ешқайсысы болмауы тиіс: %(values)s." - -#: src/wtforms/validators.py:698 -msgid "This field cannot be edited." -msgstr "Бұл өрісті өңдеу мүмкін емес." - -#: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." -msgstr "Бұл өріс сөндірілген және мәнге ие бола алмайды." - -#: src/wtforms/csrf/core.py:96 -msgid "Invalid CSRF Token." -msgstr "Жарамсыз CSRF токені." - -#: src/wtforms/csrf/session.py:63 -msgid "CSRF token missing." -msgstr "CSRF токені жоқ болып тұр." - -#: src/wtforms/csrf/session.py:71 -msgid "CSRF failed." -msgstr "CSRF сәтсіз аяқталды." - -#: src/wtforms/csrf/session.py:76 -msgid "CSRF token expired." -msgstr "CSRF токенінің мерзімі аяқталды." - -#: src/wtforms/fields/choices.py:142 -msgid "Invalid Choice: could not coerce." -msgstr "Жарамсыз таңдау: Мәнін келтіру мүмкін емес." - -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 -msgid "Choices cannot be None." -msgstr "Таңдаулар мәні Ешнәрсе болмауы тиіс." - -#: src/wtforms/fields/choices.py:155 -msgid "Not a valid choice." -msgstr "Жарамды таңдау емес." - -#: src/wtforms/fields/choices.py:193 -msgid "Invalid choice(s): one or more data inputs could not be coerced." -msgstr "" -"Жарамсыз таңдау(лар): бір немесе бірнеше деректер енгізуін келтіру мүмкін " -"емес." - -#: src/wtforms/fields/choices.py:214 -#, python-format -msgid "'%(value)s' is not a valid choice for this field." -msgid_plural "'%(value)s' are not valid choices for this field." -msgstr[0] "'%(value)s' бұл өріс үшін жарамды таңдау емес." -msgstr[1] "'%(value)s' бұл өріс үшін жарамды таңдаулар емес." - -#: src/wtforms/fields/datetime.py:51 -msgid "Not a valid datetime value." -msgstr "Жарамды күн мен уақыт мәні емес." - -#: src/wtforms/fields/datetime.py:77 -msgid "Not a valid date value." -msgstr "Жарамды күн мәні емес." - -#: src/wtforms/fields/datetime.py:103 -msgid "Not a valid time value." -msgstr "Жарамды уақыт мәні емес." - -#: src/wtforms/fields/datetime.py:148 -msgid "Not a valid week value." -msgstr "Жарамды апта мәні емес." - -#: src/wtforms/fields/numeric.py:82 src/wtforms/fields/numeric.py:92 -msgid "Not a valid integer value." -msgstr "Жарамды бүтін сан мәні емес." - -#: src/wtforms/fields/numeric.py:168 -msgid "Not a valid decimal value." -msgstr "Жарамды ондық мән емес." - -#: src/wtforms/fields/numeric.py:197 -msgid "Not a valid float value." -msgstr "Жарамды қалқымалы үтірлі сан мәні емес." diff --git a/venv/Lib/site-packages/wtforms/locale/ko/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/ko/LC_MESSAGES/wtforms.mo index 36a5047..340c9f7 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/ko/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/ko/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/ko/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/ko/LC_MESSAGES/wtforms.po index ca0064f..a8b301c 100644 --- a/venv/Lib/site-packages/wtforms/locale/ko/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/ko/LC_MESSAGES/wtforms.po @@ -6,18 +6,16 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 1.0.3\n" -"Report-Msgid-Bugs-To: eloi.rivard@nubla.fr\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" -"PO-Revision-Date: 2024-09-29 13:15+0000\n" -"Last-Translator: simmon \n" -"Language-Team: Korean \n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" +"PO-Revision-Date: 2013-02-15 00:12+0900\n" +"Last-Translator: GunWoo Choi <6566gun@gmail.com>\n" +"Language-Team: ko_KR <6566gun@gmail.com>\n" "Language: ko\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 5.8-dev\n" +"Plural-Forms: nplurals=1; plural=0\n" "Generated-By: Babel 2.8.0\n" #: src/wtforms/validators.py:86 @@ -46,7 +44,7 @@ msgstr[0] "이 항목은 %(max)d자 보다 많을 수 없습니다." #, python-format msgid "Field must be exactly %(max)d character long." msgid_plural "Field must be exactly %(max)d characters long." -msgstr[0] "이 항목은 정확히 %(max)d자이어야 합니다." +msgstr[0] "이 항목은 정확히 %(max)d자이어야 합니다" #: src/wtforms/validators.py:163 #, python-format @@ -107,12 +105,14 @@ msgid "Invalid value, can't be any of: %(values)s." msgstr "올바르지 않은 값입니다, 다음 값은 사용할 수 없습니다: %(values)s." #: src/wtforms/validators.py:698 -msgid "This field cannot be edited." -msgstr "이 필드는 편집할 수 없습니다." +#, fuzzy +#| msgid "This field is required." +msgid "This field cannot be edited" +msgstr "이 항목은 필수입니다." #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." -msgstr "이 필드는 사용할 수 없으므로 값을 가질 수 없습니다." +msgid "This field is disabled and cannot have a value" +msgstr "" #: src/wtforms/csrf/core.py:96 msgid "Invalid CSRF Token." @@ -130,30 +130,28 @@ msgstr "CSRF 인증에 실패하였습니다." msgid "CSRF token expired." msgstr "CSRF 토큰이 만료되었습니다." -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "올바르지 않은 선택값입니다: 변환할 수 없습니다." -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "선택값이 None일 수 없습니다." -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "올바르지 않은 선택값입니다." -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "올바르지 않은 선택값입니다: 한개 이상의 값을 변화할 수 없습니다." -#: src/wtforms/fields/choices.py:214 -#, python-format +#: src/wtforms/fields/choices.py:204 +#, fuzzy, python-format +#| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." msgid_plural "'%(value)s' are not valid choices for this field." -msgstr[0] "" -"'%(value)s'는 이와 같은 부분을 위해 유효한 선택이 없습니다.\n" -"\n" -"'%(value)s'는 이와 같은 부분을 위해 유효한 선택들이 없습니다." +msgstr[0] "'%(value)s'는 이 항목에 유효하지 않은 선택 값입니다." #: src/wtforms/fields/datetime.py:51 msgid "Not a valid datetime value." @@ -168,8 +166,10 @@ msgid "Not a valid time value." msgstr "올바르지 않은 시간 값입니다." #: src/wtforms/fields/datetime.py:148 +#, fuzzy +#| msgid "Not a valid date value." msgid "Not a valid week value." -msgstr "유효한 주 값이 아닙니다." +msgstr "올바르지 않은 날짜 값입니다." #: src/wtforms/fields/numeric.py:82 src/wtforms/fields/numeric.py:92 msgid "Not a valid integer value." diff --git a/venv/Lib/site-packages/wtforms/locale/nb/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/nb/LC_MESSAGES/wtforms.mo index 71b8e25..bb7c89e 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/nb/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/nb/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/nb/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/nb/LC_MESSAGES/wtforms.po index 8e687cc..2f53eb7 100644 --- a/venv/Lib/site-packages/wtforms/locale/nb/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/nb/LC_MESSAGES/wtforms.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 2.0dev\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" "PO-Revision-Date: 2014-05-05 16:18+0100\n" "Last-Translator: Frode Danielsen \n" "Language-Team: nb \n" @@ -110,11 +110,11 @@ msgstr "Ugyldig verdi, den kan ikke være en av følgende: %(values)s." #: src/wtforms/validators.py:698 #, fuzzy #| msgid "This field is required." -msgid "This field cannot be edited." +msgid "This field cannot be edited" msgstr "Dette feltet er påkrevd." #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." +msgid "This field is disabled and cannot have a value" msgstr "" #: src/wtforms/csrf/core.py:96 @@ -133,23 +133,23 @@ msgstr "CSRF-sjekk feilet" msgid "CSRF token expired." msgstr "Utløpt CSRF-pollett" -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "Ugyldig valg: Kunne ikke oversette" -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "" -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "Ikke et gyldig valg" -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "Ugyldig(e) valg: En eller flere dataverdier kunne ikke oversettes" -#: src/wtforms/fields/choices.py:214 +#: src/wtforms/fields/choices.py:204 #, fuzzy, python-format #| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." diff --git a/venv/Lib/site-packages/wtforms/locale/nl/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/nl/LC_MESSAGES/wtforms.mo index cda6255..c80e763 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/nl/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/nl/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/nl/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/nl/LC_MESSAGES/wtforms.po index e8a97de..8a94ca6 100644 --- a/venv/Lib/site-packages/wtforms/locale/nl/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/nl/LC_MESSAGES/wtforms.po @@ -6,18 +6,16 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 2.0dev\n" -"Report-Msgid-Bugs-To: eloi.rivard@nubla.fr\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" -"PO-Revision-Date: 2024-03-22 11:01+0000\n" -"Last-Translator: Mikachu \n" -"Language-Team: Dutch \n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" +"PO-Revision-Date: 2014-01-16 09:56+0100\n" +"Last-Translator: Dirk Zittersteyn \n" +"Language-Team: nl \n" "Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.5-dev\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" "Generated-By: Babel 2.8.0\n" #: src/wtforms/validators.py:86 @@ -110,12 +108,14 @@ msgid "Invalid value, can't be any of: %(values)s." msgstr "Ongeldige waarde, kan geen waarde zijn uit: %(values)s." #: src/wtforms/validators.py:698 -msgid "This field cannot be edited." -msgstr "Dit veld kan niet worden bewerkt." +#, fuzzy +#| msgid "This field is required." +msgid "This field cannot be edited" +msgstr "Dit veld is vereist." #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." -msgstr "Dit veld is uitgeschakeld en kan geen waarde hebben." +msgid "This field is disabled and cannot have a value" +msgstr "" #: src/wtforms/csrf/core.py:96 msgid "Invalid CSRF Token." @@ -133,29 +133,30 @@ msgstr "CSRF is gefaald." msgid "CSRF token expired." msgstr "CSRF-token is verlopen." -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "Ongeldige keuze: kon niet omgezet worden." -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "Keuzes mogen niet None zijn." -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "Ongeldige keuze." -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "" "Ongeldige keuze(s): een of meer van de invoeren kon niet omgezet worden." -#: src/wtforms/fields/choices.py:214 -#, python-format +#: src/wtforms/fields/choices.py:204 +#, fuzzy, python-format +#| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." msgid_plural "'%(value)s' are not valid choices for this field." msgstr[0] "'%(value)s' is een ongeldige keuze voor dit veld." -msgstr[1] "'%(value)s' zijn ongeldige keuzes voor dit veld." +msgstr[1] "'%(value)s' is een ongeldige keuze voor dit veld." #: src/wtforms/fields/datetime.py:51 msgid "Not a valid datetime value." @@ -170,8 +171,10 @@ msgid "Not a valid time value." msgstr "Ongeldige waarde." #: src/wtforms/fields/datetime.py:148 +#, fuzzy +#| msgid "Not a valid date value." msgid "Not a valid week value." -msgstr "Ongeldige waarde voor week." +msgstr "Ongeldige datum." #: src/wtforms/fields/numeric.py:82 src/wtforms/fields/numeric.py:92 msgid "Not a valid integer value." diff --git a/venv/Lib/site-packages/wtforms/locale/pl/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/pl/LC_MESSAGES/wtforms.mo index 622f4c9..72da9e2 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/pl/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/pl/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/pl/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/pl/LC_MESSAGES/wtforms.po index d14a157..572d5e0 100644 --- a/venv/Lib/site-packages/wtforms/locale/pl/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/pl/LC_MESSAGES/wtforms.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 1.0\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" "PO-Revision-Date: 2012-05-05 23:20+0200\n" "Last-Translator: Aleksander Nitecki \n" "Language-Team: pl \n" @@ -114,11 +114,11 @@ msgstr "Wartość nie może być żadną z: %(values)s." #: src/wtforms/validators.py:698 #, fuzzy #| msgid "This field is required." -msgid "This field cannot be edited." +msgid "This field cannot be edited" msgstr "To pole jest wymagane." #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." +msgid "This field is disabled and cannot have a value" msgstr "" #: src/wtforms/csrf/core.py:96 @@ -137,24 +137,24 @@ msgstr "błąd CSRF" msgid "CSRF token expired." msgstr "Wygasł token CSRF" -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "Nieprawidłowy wybór: nie można skonwertować" -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "" -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "Nieprawidłowy wybór" -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "" "Nieprawidłowy wybór: nie można skonwertować przynajmniej jednej wartości" -#: src/wtforms/fields/choices.py:214 +#: src/wtforms/fields/choices.py:204 #, fuzzy, python-format #| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." diff --git a/venv/Lib/site-packages/wtforms/locale/pt/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/pt/LC_MESSAGES/wtforms.mo index 42dfea0..dc1e902 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/pt/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/pt/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/pt/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/pt/LC_MESSAGES/wtforms.po index ab66d24..aed1d2e 100644 --- a/venv/Lib/site-packages/wtforms/locale/pt/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/pt/LC_MESSAGES/wtforms.po @@ -6,24 +6,22 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 2.0dev\n" -"Report-Msgid-Bugs-To: eloi.rivard@nubla.fr\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" -"PO-Revision-Date: 2024-06-17 21:09+0000\n" -"Last-Translator: Josimar Gabriel \n" -"Language-Team: Portuguese \n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" +"PO-Revision-Date: 2014-01-16 10:36+0100\n" +"Last-Translator: Rui Pacheco \n" +"Language-Team: pt \n" "Language: pt\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.6-dev\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" "Generated-By: Babel 2.8.0\n" #: src/wtforms/validators.py:86 #, python-format msgid "Invalid field name '%s'." -msgstr "Nome do campo inválido '%s'." +msgstr "Nome do campo inválido '%s'" #: src/wtforms/validators.py:99 #, python-format @@ -48,8 +46,8 @@ msgstr[1] "Os campos não podem ter mais do que %(max)d caracteres." #, python-format msgid "Field must be exactly %(max)d character long." msgid_plural "Field must be exactly %(max)d characters long." -msgstr[0] "O campo deve ter exatamente %(max)d caracteres." -msgstr[1] "Os campos devem ter exatamente %(max)d caracteres." +msgstr[0] "" +msgstr[1] "" #: src/wtforms/validators.py:163 #, python-format @@ -110,12 +108,14 @@ msgid "Invalid value, can't be any of: %(values)s." msgstr "Valor inválido, não deve ser um dos seguintes: %(values)s." #: src/wtforms/validators.py:698 -msgid "This field cannot be edited." -msgstr "Este campo não pode ser editado." +#, fuzzy +#| msgid "This field is required." +msgid "This field cannot be edited" +msgstr "Campo obrigatório." #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." -msgstr "Campo desativado: não pode ter um valor." +msgid "This field is disabled and cannot have a value" +msgstr "" #: src/wtforms/csrf/core.py:96 msgid "Invalid CSRF Token." @@ -133,28 +133,29 @@ msgstr "CSRF falhou." msgid "CSRF token expired." msgstr "Token CSRF expirado." -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "Escolha inválida: não é possível calcular." -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." -msgstr "A escolha não pode ser None." +msgstr "" -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "Escolha inválida." -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "Escolha(s) inválida(s): não é possível calcular alguns dos valores." -#: src/wtforms/fields/choices.py:214 -#, python-format +#: src/wtforms/fields/choices.py:204 +#, fuzzy, python-format +#| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." msgid_plural "'%(value)s' are not valid choices for this field." msgstr[0] "‘%(value)s’ não é uma escolha válida para este campo." -msgstr[1] "‘%(value)s’ não são escolhas válidas para este campo." +msgstr[1] "‘%(value)s’ não é uma escolha válida para este campo." #: src/wtforms/fields/datetime.py:51 msgid "Not a valid datetime value." @@ -166,11 +167,13 @@ msgstr "A data não é válida." #: src/wtforms/fields/datetime.py:103 msgid "Not a valid time value." -msgstr "Não é um valor de tempo válido." +msgstr "" #: src/wtforms/fields/datetime.py:148 +#, fuzzy +#| msgid "Not a valid date value." msgid "Not a valid week value." -msgstr "Não é um valor de semana válido." +msgstr "A data não é válida." #: src/wtforms/fields/numeric.py:82 src/wtforms/fields/numeric.py:92 msgid "Not a valid integer value." @@ -182,4 +185,4 @@ msgstr "O valor decimal não é válido." #: src/wtforms/fields/numeric.py:197 msgid "Not a valid float value." -msgstr "O valor com vírgula flutuante não é válido." +msgstr "O valor com vírgula flutuante não é válido. " diff --git a/venv/Lib/site-packages/wtforms/locale/ro/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/ro/LC_MESSAGES/wtforms.mo index d04f1f2..06ea164 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/ro/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/ro/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/ro/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/ro/LC_MESSAGES/wtforms.po index ffa9d0d..46b8c9b 100644 --- a/venv/Lib/site-packages/wtforms/locale/ro/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/ro/LC_MESSAGES/wtforms.po @@ -6,15 +6,15 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 3.0.1\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" +"Report-Msgid-Bugs-To: eloi.rivard@nubla.fr\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" "PO-Revision-Date: 2023-10-07 06:11+0000\n" "Last-Translator: Victor Buzdugan \n" "Language-Team: Romanian \n" "Language: ro\n" "MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" +"Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < " "20)) ? 1 : 2;\n" @@ -114,15 +114,11 @@ msgid "Invalid value, can't be any of: %(values)s." msgstr "Valoare invalidă, nu trebuie să fie una din: %(values)s." #: src/wtforms/validators.py:698 -#, fuzzy -#| msgid "This field cannot be edited" -msgid "This field cannot be edited." +msgid "This field cannot be edited" msgstr "Câmpul nu poate fi editat" #: src/wtforms/validators.py:714 -#, fuzzy -#| msgid "This field is disabled and cannot have a value" -msgid "This field is disabled and cannot have a value." +msgid "This field is disabled and cannot have a value" msgstr "Câmpul este dezactivat și nu poate conține o valoare" #: src/wtforms/csrf/core.py:96 @@ -141,24 +137,24 @@ msgstr "Validarea CSRF a eșuat." msgid "CSRF token expired." msgstr "Token-ul CSRF a expirat." -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "Selecție invalidă: valoarea nu a putut fi transformată." -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "Selecția nu poate fi None." -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "Selecție invalidă." -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "" "Selecție(ii) invalidă: una sau mai multe valori nu au putut fi transformate." -#: src/wtforms/fields/choices.py:214 +#: src/wtforms/fields/choices.py:204 #, python-format msgid "'%(value)s' is not a valid choice for this field." msgid_plural "'%(value)s' are not valid choices for this field." diff --git a/venv/Lib/site-packages/wtforms/locale/ru/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/ru/LC_MESSAGES/wtforms.mo index 88d3238..27cb64e 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/ru/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/ru/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/ru/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/ru/LC_MESSAGES/wtforms.po index 4b0f168..bb87e8e 100644 --- a/venv/Lib/site-packages/wtforms/locale/ru/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/ru/LC_MESSAGES/wtforms.po @@ -6,19 +6,17 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 1.0.3\n" -"Report-Msgid-Bugs-To: eloi.rivard@nubla.fr\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" -"PO-Revision-Date: 2024-04-26 21:07+0000\n" -"Last-Translator: \"Sophie Sh.\" \n" -"Language-Team: Russian \n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" +"PO-Revision-Date: 2012-08-01 10:23+0400\n" +"Last-Translator: Yuriy Khomyakov <_yurka_@inbox.ru>\n" +"Language-Team: ru \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " -"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -"X-Generator: Weblate 5.5.1\n" +"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" "Generated-By: Babel 2.8.0\n" #: src/wtforms/validators.py:86 @@ -116,12 +114,12 @@ msgstr "Неверное значение, не должно быть одним #: src/wtforms/validators.py:698 #, fuzzy #| msgid "This field is required." -msgid "This field cannot be edited." -msgstr "Данное поле не может быть изменено." +msgid "This field cannot be edited" +msgstr "Обязательное поле." #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." -msgstr "Данное поле отключено и не может быть изменено." +msgid "This field is disabled and cannot have a value" +msgstr "" #: src/wtforms/csrf/core.py:96 msgid "Invalid CSRF Token." @@ -139,25 +137,25 @@ msgstr "Ошибка CSRF." msgid "CSRF token expired." msgstr "CSRF токен просрочен." -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "Неверный вариант: невозможно преобразовать." -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "Выбор не может быть None" -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "Неверный вариант." -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "" "Неверный вариант(варианты): одно или несколько значений невозможно " "преобразовать." -#: src/wtforms/fields/choices.py:214 +#: src/wtforms/fields/choices.py:204 #, fuzzy, python-format #| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." @@ -179,8 +177,10 @@ msgid "Not a valid time value." msgstr "Неверное значение времени." #: src/wtforms/fields/datetime.py:148 +#, fuzzy +#| msgid "Not a valid date value." msgid "Not a valid week value." -msgstr "Неверное значение недели." +msgstr "Неверное значение даты." #: src/wtforms/fields/numeric.py:82 src/wtforms/fields/numeric.py:92 msgid "Not a valid integer value." diff --git a/venv/Lib/site-packages/wtforms/locale/sk/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/sk/LC_MESSAGES/wtforms.mo index 13f4242..836e6f3 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/sk/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/sk/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/sk/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/sk/LC_MESSAGES/wtforms.po index e9dbd07..8a2be88 100644 --- a/venv/Lib/site-packages/wtforms/locale/sk/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/sk/LC_MESSAGES/wtforms.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 2.0dev\n" "Report-Msgid-Bugs-To: eloi.rivard@nubla.fr\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" -"PO-Revision-Date: 2024-01-19 21:00+0000\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" +"PO-Revision-Date: 2023-10-06 21:11+0000\n" "Last-Translator: Milan Šalka \n" "Language-Team: Slovak \n" @@ -16,8 +16,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2);\n" -"X-Generator: Weblate 5.4-dev\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" +"X-Generator: Weblate 5.1-dev\n" "Generated-By: Babel 2.8.0\n" #: src/wtforms/validators.py:86 @@ -113,12 +113,12 @@ msgid "Invalid value, can't be any of: %(values)s." msgstr "Neplatná hodnota, nesmie byť jedna z: %(values)s." #: src/wtforms/validators.py:698 -msgid "This field cannot be edited." -msgstr "Toto pole nie je možné upravovať." +msgid "This field cannot be edited" +msgstr "Toto pole nie je možné upravovať" #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." -msgstr "Toto pole je zakázané a nemôže mať hodnotu." +msgid "This field is disabled and cannot have a value" +msgstr "Toto pole je zakázané a nemôže mať hodnotu" #: src/wtforms/csrf/core.py:96 msgid "Invalid CSRF Token." @@ -136,23 +136,23 @@ msgstr "Chyba CSRF." msgid "CSRF token expired." msgstr "CSRF token expiroval." -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "Neplatná voľba: hodnotu sa nepodarilo previesť." -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "Výbery nemôžu byť žiadne." -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "Neplatná voľba." -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "Neplatná voľba: jeden alebo viacero vstupov sa nepodarilo previesť." -#: src/wtforms/fields/choices.py:214 +#: src/wtforms/fields/choices.py:204 #, python-format msgid "'%(value)s' is not a valid choice for this field." msgid_plural "'%(value)s' are not valid choices for this field." diff --git a/venv/Lib/site-packages/wtforms/locale/sv/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/sv/LC_MESSAGES/wtforms.mo index b598494..51605e0 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/sv/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/sv/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/sv/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/sv/LC_MESSAGES/wtforms.po index 118ce1b..d1c9a4a 100644 --- a/venv/Lib/site-packages/wtforms/locale/sv/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/sv/LC_MESSAGES/wtforms.po @@ -6,10 +6,10 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 2.0dev\n" -"Report-Msgid-Bugs-To: eloi.rivard@nubla.fr\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" -"PO-Revision-Date: 2024-01-24 11:01+0000\n" -"Last-Translator: bittin1ddc447d824349b2 \n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" +"PO-Revision-Date: 2023-08-22 10:53+0000\n" +"Last-Translator: Luna Jernberg \n" "Language-Team: Swedish \n" "Language: sv\n" @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.4-dev\n" +"X-Generator: Weblate 5.0-dev\n" "Generated-By: Babel 2.8.0\n" #: src/wtforms/validators.py:86 @@ -110,12 +110,14 @@ msgid "Invalid value, can't be any of: %(values)s." msgstr "Felaktigt värde, får inte vara något av: %(values)s." #: src/wtforms/validators.py:698 -msgid "This field cannot be edited." -msgstr "Detta fält kan inte redigeras." +#, fuzzy +#| msgid "This field is required." +msgid "This field cannot be edited" +msgstr "Det här fältet är obligatoriskt." #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." -msgstr "Det här fältet är inaktiverat och kan inte ha ett värde." +msgid "This field is disabled and cannot have a value" +msgstr "" #: src/wtforms/csrf/core.py:96 msgid "Invalid CSRF Token." @@ -133,28 +135,29 @@ msgstr "CSRF misslyckades" msgid "CSRF token expired." msgstr "CSRF-token utdaterat" -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "Felaktigt val; kunde inte ceorce:a" -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "Val kan inte vara Inga." -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "Inte ett giltigt val" -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "Felaktigt val; ett eller flera inputfält kunde inte coerca:s" -#: src/wtforms/fields/choices.py:214 -#, python-format +#: src/wtforms/fields/choices.py:204 +#, fuzzy, python-format +#| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." msgid_plural "'%(value)s' are not valid choices for this field." -msgstr[0] "'%(value)s' är inte ett giltigt val för detta fält." -msgstr[1] "'%(value)s' är inte giltiga val för detta fält." +msgstr[0] "'%(value)s' är inte ett giltigt värde för det här fältet" +msgstr[1] "'%(value)s' är inte ett giltigt värde för det här fältet" #: src/wtforms/fields/datetime.py:51 msgid "Not a valid datetime value." @@ -169,8 +172,10 @@ msgid "Not a valid time value." msgstr "Inte ett giltigt tidsvärde." #: src/wtforms/fields/datetime.py:148 +#, fuzzy +#| msgid "Not a valid date value." msgid "Not a valid week value." -msgstr "Inte ett giltigt veckovärde." +msgstr "Inte ett giltigt datum" #: src/wtforms/fields/numeric.py:82 src/wtforms/fields/numeric.py:92 msgid "Not a valid integer value." diff --git a/venv/Lib/site-packages/wtforms/locale/tr/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/tr/LC_MESSAGES/wtforms.mo index 3becb5a..493c471 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/tr/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/tr/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/tr/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/tr/LC_MESSAGES/wtforms.po index 8ef4c56..ae95292 100644 --- a/venv/Lib/site-packages/wtforms/locale/tr/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/tr/LC_MESSAGES/wtforms.po @@ -6,18 +6,16 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 1.0.4\n" -"Report-Msgid-Bugs-To: eloi.rivard@nubla.fr\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" -"PO-Revision-Date: 2024-01-22 19:01+0000\n" -"Last-Translator: Oğuz Ersen \n" -"Language-Team: Turkish \n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" +"PO-Revision-Date: 2017-05-28 02:23+0300\n" +"Last-Translator: Melih Uçar \n" +"Language-Team: tr \n" "Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.4-dev\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" "Generated-By: Babel 2.8.0\n" #: src/wtforms/validators.py:86 @@ -48,8 +46,8 @@ msgstr[1] "Alan %(max)d karakterden uzun olamaz." #, python-format msgid "Field must be exactly %(max)d character long." msgid_plural "Field must be exactly %(max)d characters long." -msgstr[0] "Alan tam olarak %(max)d karakter uzunluğunda olmalı." -msgstr[1] "Alan tam olarak %(max)d karakter uzunluğunda olmalı." +msgstr[0] "" +msgstr[1] "" #: src/wtforms/validators.py:163 #, python-format @@ -110,76 +108,81 @@ msgid "Invalid value, can't be any of: %(values)s." msgstr "Geçersiz değer, değerlerden biri olamaz: %(values)s." #: src/wtforms/validators.py:698 -msgid "This field cannot be edited." -msgstr "Bu alan düzenlenemez." +#, fuzzy +#| msgid "This field is required." +msgid "This field cannot be edited" +msgstr "Bu alan zorunludur." #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." -msgstr "Bu alan devre dışıdır ve bir değere sahip olamaz." +msgid "This field is disabled and cannot have a value" +msgstr "" #: src/wtforms/csrf/core.py:96 msgid "Invalid CSRF Token." -msgstr "Geçersiz CSRF Anahtarı." +msgstr "Geçersiz CSRF Anahtarı" #: src/wtforms/csrf/session.py:63 msgid "CSRF token missing." -msgstr "CSRF anahtarı gerekli." +msgstr "CSRF anahtarı gerekli" #: src/wtforms/csrf/session.py:71 msgid "CSRF failed." -msgstr "CSRF hatalı." +msgstr "CSRF hatalı" #: src/wtforms/csrf/session.py:76 msgid "CSRF token expired." -msgstr "CSRF anahtarının süresi doldu." +msgstr "CSRF anahtarının süresi doldu" -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." -msgstr "Geçersiz seçim: tip uyuşmazlığı." +msgstr "Geçersiz seçim: tip uyuşmazlığı" -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." -msgstr "Seçimler Hiçbiri olamaz." +msgstr "" -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." -msgstr "Geçerli bir seçenek değil." +msgstr "Geçerli bir seçenek değil" -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." -msgstr "Geçersiz seçenek: bir yada daha fazla tip uyuşmazlığı." +msgstr "Geçersiz seçenek: bir yada daha fazla tip uyuşmazlığı" -#: src/wtforms/fields/choices.py:214 -#, python-format +#: src/wtforms/fields/choices.py:204 +#, fuzzy, python-format +#| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." msgid_plural "'%(value)s' are not valid choices for this field." -msgstr[0] "'%(value)s' bu alan için geçerli bir seçim değil." -msgstr[1] "'%(value)s' bu alan için geçerli bir seçim değil." +msgstr[0] "'%(value)s' bu alan için geçerli değil" +msgstr[1] "'%(value)s' bu alan için geçerli değil" #: src/wtforms/fields/datetime.py:51 msgid "Not a valid datetime value." -msgstr "Geçerli bir tarih-saat değeri değil." +msgstr "Geçerli bir zaman değil" #: src/wtforms/fields/datetime.py:77 msgid "Not a valid date value." -msgstr "Geçerli bir tarih değeri değil." +msgstr "Geçerli bir tarih değil" #: src/wtforms/fields/datetime.py:103 msgid "Not a valid time value." -msgstr "Geçerli bir zaman değeri değil." +msgstr "" #: src/wtforms/fields/datetime.py:148 +#, fuzzy +#| msgid "Not a valid date value." msgid "Not a valid week value." -msgstr "Geçerli bir hafta değeri değil." +msgstr "Geçerli bir tarih değil" #: src/wtforms/fields/numeric.py:82 src/wtforms/fields/numeric.py:92 msgid "Not a valid integer value." -msgstr "Geçerli bir tam sayı değeri değil." +msgstr "Geçerli bir sayı değeri değil" #: src/wtforms/fields/numeric.py:168 msgid "Not a valid decimal value." -msgstr "Geçerli bir ondalık sayı değeri değil." +msgstr "Geçerli bir ondalık sayı değil" #: src/wtforms/fields/numeric.py:197 msgid "Not a valid float value." -msgstr "Geçerli bir ondalık sayı değeri değil." +msgstr "Geçerli bir ondalık sayı değil" diff --git a/venv/Lib/site-packages/wtforms/locale/uk/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/uk/LC_MESSAGES/wtforms.mo index 8c6c12e..d6e6de9 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/uk/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/uk/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/uk/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/uk/LC_MESSAGES/wtforms.po index 6482f6f..35a116a 100644 --- a/venv/Lib/site-packages/wtforms/locale/uk/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/uk/LC_MESSAGES/wtforms.po @@ -6,19 +6,17 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 2.0dev\n" -"Report-Msgid-Bugs-To: eloi.rivard@nubla.fr\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" -"PO-Revision-Date: 2024-01-15 09:06+0000\n" -"Last-Translator: Сергій \n" -"Language-Team: Ukrainian \n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" +"PO-Revision-Date: 2014-01-16 10:04+0100\n" +"Last-Translator: Oleg Pidsadnyi \n" +"Language-Team: uk \n" "Language: uk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " -"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -"X-Generator: Weblate 5.4-dev\n" +"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" "Generated-By: Babel 2.8.0\n" #: src/wtforms/validators.py:86 @@ -51,9 +49,9 @@ msgstr[2] "Значення поля має містити не більше н #, python-format msgid "Field must be exactly %(max)d character long." msgid_plural "Field must be exactly %(max)d characters long." -msgstr[0] "Поле повинно мати довжину рівно %(max)d символі." -msgstr[1] "Поле повинно мати довжину рівно %(max)d символи." -msgstr[2] "Поле повинно мати довжину рівно %(max)d символів." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" #: src/wtforms/validators.py:163 #, python-format @@ -114,12 +112,14 @@ msgid "Invalid value, can't be any of: %(values)s." msgstr "Значення невірне, не може бути одним з: %(values)s." #: src/wtforms/validators.py:698 -msgid "This field cannot be edited." -msgstr "Це поле не можна редагувати." +#, fuzzy +#| msgid "This field is required." +msgid "This field cannot be edited" +msgstr "Це поле є обов'язковим." #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." -msgstr "Це поле неактивне і не може містити значення." +msgid "This field is disabled and cannot have a value" +msgstr "" #: src/wtforms/csrf/core.py:96 msgid "Invalid CSRF Token." @@ -127,64 +127,67 @@ msgstr "Невірний CSRF токен." #: src/wtforms/csrf/session.py:63 msgid "CSRF token missing." -msgstr "CSRF токен відсутній." +msgstr "CSRF токен відсутній" #: src/wtforms/csrf/session.py:71 msgid "CSRF failed." -msgstr "Помилка CSRF." +msgstr "Помилка CSRF" #: src/wtforms/csrf/session.py:76 msgid "CSRF token expired." -msgstr "CSRF токен прострочений." +msgstr "CSRF токен прострочений" -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." -msgstr "Недійсний варіант: перетворення неможливе." +msgstr "Недійсний варіант: перетворення неможливе" -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." -msgstr "Варіанти не можуть бути None." +msgstr "" -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." -msgstr "Недійсний варіант." +msgstr "Недійсний варіант" -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." -msgstr "Недійсний варіант: одне чи більше значень неможливо перетворити." +msgstr "Недійсний варіант: одне чи більше значень неможливо перетворити" -#: src/wtforms/fields/choices.py:214 -#, python-format +#: src/wtforms/fields/choices.py:204 +#, fuzzy, python-format +#| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." msgid_plural "'%(value)s' are not valid choices for this field." -msgstr[0] "'%(value)s' не є дійсним варіантом для цього поля." -msgstr[1] "'%(value)s' не є дійсним варіантом для цього поля." -msgstr[2] "'%(value)s' не є дійсним варіантом для цього поля." +msgstr[0] "'%(value)s' не є дійсним варіантом для цього поля" +msgstr[1] "'%(value)s' не є дійсним варіантом для цього поля" +msgstr[2] "'%(value)s' не є дійсним варіантом для цього поля" #: src/wtforms/fields/datetime.py:51 msgid "Not a valid datetime value." -msgstr "Недійсне значення дати/часу." +msgstr "Недійсне значення дати/часу" #: src/wtforms/fields/datetime.py:77 msgid "Not a valid date value." -msgstr "Не дійсне значення дати." +msgstr "Не дійсне значення дати" #: src/wtforms/fields/datetime.py:103 msgid "Not a valid time value." -msgstr "Не дійсне значення часу." +msgstr "Не дійсне значення часу" #: src/wtforms/fields/datetime.py:148 +#, fuzzy +#| msgid "Not a valid date value." msgid "Not a valid week value." -msgstr "Недійсне значення тижня." +msgstr "Не дійсне значення дати" #: src/wtforms/fields/numeric.py:82 src/wtforms/fields/numeric.py:92 msgid "Not a valid integer value." -msgstr "Недійсне ціле число." +msgstr "Недійсне ціле число" #: src/wtforms/fields/numeric.py:168 msgid "Not a valid decimal value." -msgstr "Не є дійсним десятковим числом." +msgstr "Не є дійсним десятичним числом" #: src/wtforms/fields/numeric.py:197 msgid "Not a valid float value." -msgstr "Недійсне число з рухомою комою." +msgstr "Недійсне десятичне дробове число" diff --git a/venv/Lib/site-packages/wtforms/locale/wtforms.pot b/venv/Lib/site-packages/wtforms/locale/wtforms.pot index e849881..9bdf80f 100644 --- a/venv/Lib/site-packages/wtforms/locale/wtforms.pot +++ b/venv/Lib/site-packages/wtforms/locale/wtforms.pot @@ -1,14 +1,14 @@ # Translations template for WTForms. -# Copyright (C) 2024 WTForms Team +# Copyright (C) 2023 WTForms Team # This file is distributed under the same license as the WTForms project. -# FIRST AUTHOR , 2024. +# FIRST AUTHOR , 2023. # #, fuzzy msgid "" msgstr "" -"Project-Id-Version: WTForms 3.0.0\n" +"Project-Id-Version: WTForms 3.0.1\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -107,11 +107,11 @@ msgid "Invalid value, can't be any of: %(values)s." msgstr "" #: src/wtforms/validators.py:698 -msgid "This field cannot be edited." +msgid "This field cannot be edited" msgstr "" #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." +msgid "This field is disabled and cannot have a value" msgstr "" #: src/wtforms/csrf/core.py:96 @@ -130,23 +130,23 @@ msgstr "" msgid "CSRF token expired." msgstr "" -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "" -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "" -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "" -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "" -#: src/wtforms/fields/choices.py:214 +#: src/wtforms/fields/choices.py:204 #, python-format msgid "'%(value)s' is not a valid choice for this field." msgid_plural "'%(value)s' are not valid choices for this field." diff --git a/venv/Lib/site-packages/wtforms/locale/zh/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/zh/LC_MESSAGES/wtforms.mo index e314b6d..f407328 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/zh/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/zh/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/zh/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/zh/LC_MESSAGES/wtforms.po index 1937605..792ac02 100644 --- a/venv/Lib/site-packages/wtforms/locale/zh/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/zh/LC_MESSAGES/wtforms.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 1.0.3\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" "PO-Revision-Date: 2012-01-31 13:03-0700\n" "Last-Translator: Grey Li \n" "Language-Team: zh_CN \n" @@ -110,11 +110,11 @@ msgstr "无效的值,不能是下列任何一个: %(values)s。" #: src/wtforms/validators.py:698 #, fuzzy #| msgid "This field is required." -msgid "This field cannot be edited." +msgid "This field cannot be edited" msgstr "该字段是必填字段。" #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." +msgid "This field is disabled and cannot have a value" msgstr "" #: src/wtforms/csrf/core.py:96 @@ -133,23 +133,23 @@ msgstr "CSRF 验证失败。" msgid "CSRF token expired." msgstr "CSRF 验证令牌过期。" -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "选择无效:无法转化类型。" -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "选择不能是空值。" -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "不是有效的选择。" -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "选择无效:至少一个数据输入无法被转化类型。" -#: src/wtforms/fields/choices.py:214 +#: src/wtforms/fields/choices.py:204 #, fuzzy, python-format #| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." diff --git a/venv/Lib/site-packages/wtforms/locale/zh_TW/LC_MESSAGES/wtforms.mo b/venv/Lib/site-packages/wtforms/locale/zh_TW/LC_MESSAGES/wtforms.mo index 570695c..09e7f30 100644 Binary files a/venv/Lib/site-packages/wtforms/locale/zh_TW/LC_MESSAGES/wtforms.mo and b/venv/Lib/site-packages/wtforms/locale/zh_TW/LC_MESSAGES/wtforms.mo differ diff --git a/venv/Lib/site-packages/wtforms/locale/zh_TW/LC_MESSAGES/wtforms.po b/venv/Lib/site-packages/wtforms/locale/zh_TW/LC_MESSAGES/wtforms.po index 5d68e40..8e918a7 100644 --- a/venv/Lib/site-packages/wtforms/locale/zh_TW/LC_MESSAGES/wtforms.po +++ b/venv/Lib/site-packages/wtforms/locale/zh_TW/LC_MESSAGES/wtforms.po @@ -6,24 +6,22 @@ msgid "" msgstr "" "Project-Id-Version: WTForms 1.0.3\n" -"Report-Msgid-Bugs-To: eloi.rivard@nubla.fr\n" -"POT-Creation-Date: 2024-01-11 08:20+0100\n" -"PO-Revision-Date: 2024-06-30 03:38+0000\n" -"Last-Translator: hugoalh \n" -"Language-Team: Chinese (Traditional) \n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2023-10-05 13:42+0200\n" +"PO-Revision-Date: 2013-04-14 00:26+0800\n" +"Last-Translator: Grey Li \n" +"Language-Team: zh_TW \n" "Language: zh_TW\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 5.7-dev\n" +"Plural-Forms: nplurals=1; plural=0\n" "Generated-By: Babel 2.8.0\n" #: src/wtforms/validators.py:86 #, python-format msgid "Invalid field name '%s'." -msgstr "無效的欄位名稱「%s」。" +msgstr "'%s' 是無效的欄位名。" #: src/wtforms/validators.py:99 #, python-format @@ -34,43 +32,43 @@ msgstr "欄位必須與 %(other_name)s 相同。" #, python-format msgid "Field must be at least %(min)d character long." msgid_plural "Field must be at least %(min)d characters long." -msgstr[0] "欄位長度必須至少為 %(min)d 個字元。" +msgstr[0] "欄位必須超過 %(min)d 個字元。" #: src/wtforms/validators.py:151 #, python-format msgid "Field cannot be longer than %(max)d character." msgid_plural "Field cannot be longer than %(max)d characters." -msgstr[0] "欄位長度不能超過 %(max)d 個字元。" +msgstr[0] "欄位必須少於 %(max)d 個字元。" #: src/wtforms/validators.py:157 #, python-format msgid "Field must be exactly %(max)d character long." msgid_plural "Field must be exactly %(max)d characters long." -msgstr[0] "欄位長度必須剛好為 %(max)d 個字元。" +msgstr[0] "欄位必須為 %(max)d 個字元。" #: src/wtforms/validators.py:163 #, python-format msgid "Field must be between %(min)d and %(max)d characters long." -msgstr "欄位長度必須介於 %(min)d 和 %(max)d 個字元之間。" +msgstr "欄位必須介於 %(min)d 至 %(max)d 個字元。" #: src/wtforms/validators.py:216 #, python-format msgid "Number must be at least %(min)s." -msgstr "數字必須至少為 %(min)s。" +msgstr "數字必須大於 %(min)s。" #: src/wtforms/validators.py:219 #, python-format msgid "Number must be at most %(max)s." -msgstr "數字必須至多為 %(max)s。" +msgstr "數字必須小於 %(max)s。" #: src/wtforms/validators.py:222 #, python-format msgid "Number must be between %(min)s and %(max)s." -msgstr "數字必須介於 %(min)s 和 %(max)s 之間。" +msgstr "數字必須介於 %(min)s 至 %(max)s 之間。" #: src/wtforms/validators.py:293 src/wtforms/validators.py:323 msgid "This field is required." -msgstr "此欄位是必需的。" +msgstr "此欄位為必填。" #: src/wtforms/validators.py:358 msgid "Invalid input." @@ -90,7 +88,7 @@ msgstr "無效的 MAC 位址。" #: src/wtforms/validators.py:540 msgid "Invalid URL." -msgstr "無效的網址。" +msgstr "無效的 URL。" #: src/wtforms/validators.py:561 msgid "Invalid UUID." @@ -99,20 +97,22 @@ msgstr "無效的 UUID。" #: src/wtforms/validators.py:594 #, python-format msgid "Invalid value, must be one of: %(values)s." -msgstr "無效的值,必須為以下之一:%(values)s。" +msgstr "無效的資料,必須為以下任一:%(values)s。" #: src/wtforms/validators.py:629 #, python-format msgid "Invalid value, can't be any of: %(values)s." -msgstr "無效的值,不能為以下之一:%(values)s。" +msgstr "無效的資料,不得為以下任一:%(values)s。" #: src/wtforms/validators.py:698 -msgid "This field cannot be edited." -msgstr "此欄位不能編輯。" +#, fuzzy +#| msgid "This field is required." +msgid "This field cannot be edited" +msgstr "此欄位為必填。" #: src/wtforms/validators.py:714 -msgid "This field is disabled and cannot have a value." -msgstr "此欄位被停用並且不能有值。" +msgid "This field is disabled and cannot have a value" +msgstr "" #: src/wtforms/csrf/core.py:96 msgid "Invalid CSRF Token." @@ -130,43 +130,46 @@ msgstr "CSRF 驗證失敗。" msgid "CSRF token expired." msgstr "CSRF 憑證過期。" -#: src/wtforms/fields/choices.py:142 +#: src/wtforms/fields/choices.py:135 msgid "Invalid Choice: could not coerce." msgstr "無效的選擇:無法強制轉化。" -#: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203 +#: src/wtforms/fields/choices.py:139 src/wtforms/fields/choices.py:192 msgid "Choices cannot be None." msgstr "選擇不能為空值。" -#: src/wtforms/fields/choices.py:155 +#: src/wtforms/fields/choices.py:148 msgid "Not a valid choice." msgstr "不是有效的選擇。" -#: src/wtforms/fields/choices.py:193 +#: src/wtforms/fields/choices.py:185 msgid "Invalid choice(s): one or more data inputs could not be coerced." msgstr "無效的選擇:至少有一筆資料無法被強制轉化。" -#: src/wtforms/fields/choices.py:214 -#, python-format +#: src/wtforms/fields/choices.py:204 +#, fuzzy, python-format +#| msgid "'%(value)s' is not a valid choice for this field." msgid "'%(value)s' is not a valid choice for this field." msgid_plural "'%(value)s' are not valid choices for this field." -msgstr[0] "「%(value)s」不是此欄位的有效選擇。" +msgstr[0] "'%(value)s' 對此欄位為無效的選項。" #: src/wtforms/fields/datetime.py:51 msgid "Not a valid datetime value." -msgstr "不是有效的日期與時間值。" +msgstr "不是有效的日期與時間。" #: src/wtforms/fields/datetime.py:77 msgid "Not a valid date value." -msgstr "不是有效的日期值。" +msgstr "不是有效的日期。" #: src/wtforms/fields/datetime.py:103 msgid "Not a valid time value." -msgstr "不是有效的時間值。" +msgstr "不是有效的時間。" #: src/wtforms/fields/datetime.py:148 +#, fuzzy +#| msgid "Not a valid date value." msgid "Not a valid week value." -msgstr "不是有效的週值。" +msgstr "不是有效的日期。" #: src/wtforms/fields/numeric.py:82 src/wtforms/fields/numeric.py:92 msgid "Not a valid integer value." diff --git a/venv/Lib/site-packages/wtforms/utils.py b/venv/Lib/site-packages/wtforms/utils.py index 51bbe8a..4911afa 100644 --- a/venv/Lib/site-packages/wtforms/utils.py +++ b/venv/Lib/site-packages/wtforms/utils.py @@ -1,11 +1,9 @@ -import os import re -_LEADING_SYMBOL = "#" if os.name == "nt" else "-" # https://docs.python.org/3/library/datetime.html#technical-detail (see NOTE #9) _DATETIME_STRIP_ZERO_PADDING_FORMATS_RE = re.compile( - f"%{_LEADING_SYMBOL}[" + "%-[" "d" # day of month "m" # month "H" # hour (24-hour) @@ -28,7 +26,7 @@ def clean_datetime_format_for_strptime(formats): return [ re.sub( _DATETIME_STRIP_ZERO_PADDING_FORMATS_RE, - lambda m: m[0].replace(_LEADING_SYMBOL, ""), + lambda m: m[0].replace("-", ""), format, ) for format in formats diff --git a/venv/Lib/site-packages/wtforms/validators.py b/venv/Lib/site-packages/wtforms/validators.py index 3536963..59134f2 100644 --- a/venv/Lib/site-packages/wtforms/validators.py +++ b/venv/Lib/site-packages/wtforms/validators.py @@ -586,8 +586,7 @@ class AnyOf: self.values_formatter = values_formatter def __call__(self, form, field): - data = field.data if isinstance(field.data, list) else [field.data] - if any(d in self.values for d in data): + if field.data in self.values: return message = self.message @@ -622,8 +621,7 @@ class NoneOf: self.values_formatter = values_formatter def __call__(self, form, field): - data = field.data if isinstance(field.data, list) else [field.data] - if not any(d in self.values for d in data): + if field.data not in self.values: return message = self.message @@ -697,7 +695,7 @@ class ReadOnly: def __call__(self, form, field): if field.data != field.object_data: - raise ValidationError(field.gettext("This field cannot be edited.")) + raise ValidationError(field.gettext("This field cannot be edited")) class Disabled: @@ -713,7 +711,7 @@ class Disabled: def __call__(self, form, field): if field.raw_data is not None: raise ValidationError( - field.gettext("This field is disabled and cannot have a value.") + field.gettext("This field is disabled and cannot have a value") ) diff --git a/venv/Lib/site-packages/wtforms/widgets/__init__.py b/venv/Lib/site-packages/wtforms/widgets/__init__.py index ad29ea5..c87f108 100644 --- a/venv/Lib/site-packages/wtforms/widgets/__init__.py +++ b/venv/Lib/site-packages/wtforms/widgets/__init__.py @@ -1,57 +1,3 @@ -from wtforms.widgets.core import CheckboxInput -from wtforms.widgets.core import ColorInput -from wtforms.widgets.core import DateInput -from wtforms.widgets.core import DateTimeInput -from wtforms.widgets.core import DateTimeLocalInput -from wtforms.widgets.core import EmailInput -from wtforms.widgets.core import FileInput -from wtforms.widgets.core import HiddenInput +from wtforms.widgets.core import * from wtforms.widgets.core import html_params from wtforms.widgets.core import Input -from wtforms.widgets.core import ListWidget -from wtforms.widgets.core import MonthInput -from wtforms.widgets.core import NumberInput -from wtforms.widgets.core import Option -from wtforms.widgets.core import PasswordInput -from wtforms.widgets.core import RadioInput -from wtforms.widgets.core import RangeInput -from wtforms.widgets.core import SearchInput -from wtforms.widgets.core import Select -from wtforms.widgets.core import SubmitInput -from wtforms.widgets.core import TableWidget -from wtforms.widgets.core import TelInput -from wtforms.widgets.core import TextArea -from wtforms.widgets.core import TextInput -from wtforms.widgets.core import TimeInput -from wtforms.widgets.core import URLInput -from wtforms.widgets.core import WeekInput - -__all__ = [ - "CheckboxInput", - "ColorInput", - "DateInput", - "DateTimeInput", - "DateTimeLocalInput", - "EmailInput", - "FileInput", - "HiddenInput", - "ListWidget", - "MonthInput", - "NumberInput", - "Option", - "PasswordInput", - "RadioInput", - "RangeInput", - "SearchInput", - "Select", - "SubmitInput", - "TableWidget", - "TextArea", - "TextInput", - "TelInput", - "TimeInput", - "URLInput", - "WeekInput", - "html_params", - "Input", -] diff --git a/venv/Lib/site-packages/wtforms/widgets/__pycache__/__init__.cpython-310.pyc b/venv/Lib/site-packages/wtforms/widgets/__pycache__/__init__.cpython-310.pyc index 4520329..98aac8f 100644 Binary files a/venv/Lib/site-packages/wtforms/widgets/__pycache__/__init__.cpython-310.pyc and b/venv/Lib/site-packages/wtforms/widgets/__pycache__/__init__.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/wtforms/widgets/__pycache__/core.cpython-310.pyc b/venv/Lib/site-packages/wtforms/widgets/__pycache__/core.cpython-310.pyc index 638f50c..b082d1b 100644 Binary files a/venv/Lib/site-packages/wtforms/widgets/__pycache__/core.cpython-310.pyc and b/venv/Lib/site-packages/wtforms/widgets/__pycache__/core.cpython-310.pyc differ diff --git a/venv/Lib/site-packages/wtforms/widgets/core.py b/venv/Lib/site-packages/wtforms/widgets/core.py index 832918e..62d86e9 100644 --- a/venv/Lib/site-packages/wtforms/widgets/core.py +++ b/venv/Lib/site-packages/wtforms/widgets/core.py @@ -1,3 +1,5 @@ +import warnings + from markupsafe import escape from markupsafe import Markup @@ -109,7 +111,7 @@ class ListWidget: html.append(f"
  • {subfield.label} {subfield()}
  • ") else: html.append(f"
  • {subfield()} {subfield.label}
  • ") - html.append(f"") + html.append("" % self.html_tag) return Markup("".join(html)) @@ -132,15 +134,15 @@ class TableWidget: html = [] if self.with_table_tag: kwargs.setdefault("id", field.id) - table_params = html_params(**kwargs) - html.append(f"
    ") + html.append("
    " % html_params(**kwargs)) hidden = "" for subfield in field: if subfield.type in ("HiddenField", "CSRFTokenField"): hidden += str(subfield) else: html.append( - f"" + "" + % (str(subfield.label), hidden, str(subfield)) ) hidden = "" if self.with_table_tag: @@ -161,6 +163,7 @@ class Input: """ html_params = staticmethod(html_params) + validation_attrs = ["required", "disabled"] def __init__(self, input_type=None): if input_type is not None: @@ -175,8 +178,7 @@ class Input: for k in dir(flags): if k in self.validation_attrs and k not in kwargs: kwargs[k] = getattr(flags, k) - input_params = self.html_params(name=field.name, **kwargs) - return Markup(f"") + return Markup("" % self.html_params(name=field.name, **kwargs)) class TextInput(Input): @@ -229,7 +231,6 @@ class HiddenInput(Input): """ input_type = "hidden" - validation_attrs = ["disabled"] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -244,7 +245,6 @@ class CheckboxInput(Input): """ input_type = "checkbox" - validation_attrs = ["required", "disabled"] def __call__(self, field, **kwargs): if getattr(field, "checked", field.data): @@ -261,7 +261,6 @@ class RadioInput(Input): """ input_type = "radio" - validation_attrs = ["required", "disabled"] def __call__(self, field, **kwargs): if field.checked: @@ -301,7 +300,6 @@ class SubmitInput(Input): """ input_type = "submit" - validation_attrs = ["required", "disabled"] def __call__(self, field, **kwargs): kwargs.setdefault("value", field.label.text) @@ -323,10 +321,9 @@ class TextArea: for k in dir(flags): if k in self.validation_attrs and k not in kwargs: kwargs[k] = getattr(flags, k) - textarea_params = html_params(name=field.name, **kwargs) - textarea_innerhtml = escape(field._value()) return Markup( - f"" + "" + % (html_params(name=field.name, **kwargs), escape(field._value())) ) @@ -359,19 +356,37 @@ class Select: for k in dir(flags): if k in self.validation_attrs and k not in kwargs: kwargs[k] = getattr(flags, k) - select_params = html_params(name=field.name, **kwargs) - html = [f"" % html_params(name=field.name, **kwargs)] if field.has_groups(): for group, choices in field.iter_groups(): - optgroup_params = html_params(label=group) - html.append(f"") + html.append("" % html_params(label=group)) for choice in choices: - val, label, selected, render_kw = choice + if len(choice) == 4: + val, label, selected, render_kw = choice + else: + warnings.warn( + "'iter_groups' is expected to return 4 items tuple since " + "wtforms 3.1, this will be mandatory in wtforms 3.2", + DeprecationWarning, + stacklevel=2, + ) + val, label, selected = choice + render_kw = {} html.append(self.render_option(val, label, selected, **render_kw)) html.append("") else: for choice in field.iter_choices(): - val, label, selected, render_kw = choice + if len(choice) == 4: + val, label, selected, render_kw = choice + else: + warnings.warn( + "'iter_groups' is expected to return 4 items tuple since " + "wtforms 3.1, this will be mandatory in wtforms 3.2", + DeprecationWarning, + stacklevel=2, + ) + val, label, selected = choice + render_kw = {} html.append(self.render_option(val, label, selected, **render_kw)) html.append("") return Markup("".join(html)) @@ -549,7 +564,7 @@ class RangeInput(Input): """ input_type = "range" - validation_attrs = ["disabled", "max", "min", "step"] + validation_attrs = ["required", "disabled", "max", "min", "step"] def __init__(self, step=None): self.step = step @@ -566,4 +581,3 @@ class ColorInput(Input): """ input_type = "color" - validation_attrs = ["disabled"]
    {subfield.label}{hidden}{subfield}
    %s%s%s