lol
This commit is contained in:
@@ -11,6 +11,7 @@ WORKDIR /app
|
|||||||
# Install dependencies
|
# Install dependencies
|
||||||
COPY requirements.txt .
|
COPY requirements.txt .
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
RUN pip install gunicorn
|
||||||
|
|
||||||
# Copy project files
|
# Copy project files
|
||||||
COPY . .
|
COPY . .
|
||||||
@@ -22,5 +23,5 @@ EXPOSE 5000
|
|||||||
ENV FLASK_APP=app.py
|
ENV FLASK_APP=app.py
|
||||||
ENV FLASK_ENV=production
|
ENV FLASK_ENV=production
|
||||||
|
|
||||||
# Run the application
|
# Run the application with gunicorn
|
||||||
CMD ["flask", "run", "--host=0.0.0.0"]
|
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]
|
||||||
7
app.py
7
app.py
@@ -1,5 +1,6 @@
|
|||||||
from flask import Flask, render_template, request, redirect, url_for, flash, session
|
from flask import Flask, render_template, request, redirect, url_for, flash, session
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
from flask_migrate import Migrate
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from werkzeug.security import generate_password_hash, check_password_hash
|
from werkzeug.security import generate_password_hash, check_password_hash
|
||||||
from werkzeug.utils import secure_filename
|
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)
|
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
|
||||||
|
|
||||||
db = SQLAlchemy(app)
|
db = SQLAlchemy(app)
|
||||||
|
migrate = Migrate(app, db)
|
||||||
|
|
||||||
# Database Models
|
# Database Models
|
||||||
class User(db.Model):
|
class User(db.Model):
|
||||||
@@ -1142,4 +1144,7 @@ def seed_db():
|
|||||||
description=plant['description'],
|
description=plant['description'],
|
||||||
care_guide=plant['care_guide']
|
care_guide=plant['care_guide']
|
||||||
))
|
))
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run(debug=True)
|
||||||
BIN
instance/site.db
BIN
instance/site.db
Binary file not shown.
1
migrations/README
Normal file
1
migrations/README
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Single-database configuration for Flask.
|
||||||
50
migrations/alembic.ini
Normal file
50
migrations/alembic.ini
Normal file
@@ -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
|
||||||
113
migrations/env.py
Normal file
113
migrations/env.py
Normal file
@@ -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()
|
||||||
24
migrations/script.py.mako
Normal file
24
migrations/script.py.mako
Normal file
@@ -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"}
|
||||||
@@ -5,4 +5,6 @@ Flask-WTF==1.2.1
|
|||||||
SQLAlchemy==2.0.23
|
SQLAlchemy==2.0.23
|
||||||
Werkzeug==2.3.7
|
Werkzeug==2.3.7
|
||||||
WTForms==3.1.1
|
WTForms==3.1.1
|
||||||
python-dotenv==1.0.0
|
python-dotenv==1.0.0
|
||||||
|
psycopg2-binary==2.9.9
|
||||||
|
gunicorn==21.2.0
|
||||||
@@ -1 +0,0 @@
|
|||||||
pip
|
|
||||||
@@ -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.
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
Wheel-Version: 1.0
|
|
||||||
Generator: bdist_wheel (0.38.4)
|
|
||||||
Root-Is-Purelib: true
|
|
||||||
Tag: py3-none-any
|
|
||||||
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
flask_wtf
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
pip
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
Copyright 2005-2023 SQLAlchemy authors and contributors <see AUTHORS file>.
|
|
||||||
|
|
||||||
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.
|
|
||||||
@@ -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 <https://www.sqlalchemy.org/docs/intro.html#installation>`_.
|
|
||||||
|
|
||||||
Getting Help / Development / Bug reporting
|
|
||||||
------------------------------------------
|
|
||||||
|
|
||||||
Please refer to the `SQLAlchemy Community Guide <https://www.sqlalchemy.org/support.html>`_.
|
|
||||||
|
|
||||||
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 <https://www.sqlalchemy.org/codeofconduct.html>`_.
|
|
||||||
|
|
||||||
License
|
|
||||||
-------
|
|
||||||
|
|
||||||
SQLAlchemy is distributed under the `MIT license
|
|
||||||
<https://www.opensource.org/licenses/mit-license.php>`_.
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
Wheel-Version: 1.0
|
|
||||||
Generator: bdist_wheel (0.41.1)
|
|
||||||
Root-Is-Purelib: false
|
|
||||||
Tag: cp310-cp310-win_amd64
|
|
||||||
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
sqlalchemy
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
pip
|
|
||||||
@@ -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.
|
|
||||||
@@ -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 <contact@palletsprojects.com>
|
|
||||||
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
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
Wheel-Version: 1.0
|
|
||||||
Generator: flit 3.9.0
|
|
||||||
Root-Is-Purelib: true
|
|
||||||
Tag: py3-none-any
|
|
||||||
@@ -4,43 +4,23 @@ import typing as t
|
|||||||
|
|
||||||
from .extension import SQLAlchemy
|
from .extension import SQLAlchemy
|
||||||
|
|
||||||
__version__ = "3.0.5"
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"SQLAlchemy",
|
"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:
|
def __getattr__(name: str) -> t.Any:
|
||||||
import importlib
|
if name == "__version__":
|
||||||
import warnings
|
import importlib.metadata
|
||||||
|
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"
|
|
||||||
|
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
f"'{name}' has been {action} to '{path[1:]}'. The top-level import is"
|
"The '__version__' attribute is deprecated and will be removed in"
|
||||||
" deprecated and will be removed in Flask-SQLAlchemy 3.1.",
|
" Flask-SQLAlchemy 3.2. Use feature detection or"
|
||||||
|
" 'importlib.metadata.version(\"flask-sqlalchemy\")' instead.",
|
||||||
DeprecationWarning,
|
DeprecationWarning,
|
||||||
stacklevel=2,
|
stacklevel=2,
|
||||||
)
|
)
|
||||||
mod = importlib.import_module(import_path, __name__)
|
return importlib.metadata.version("flask-sqlalchemy")
|
||||||
return getattr(mod, new_name)
|
|
||||||
|
|
||||||
raise AttributeError(name)
|
raise AttributeError(name)
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,7 +1,9 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import types
|
||||||
import typing as t
|
import typing as t
|
||||||
|
import warnings
|
||||||
from weakref import WeakKeyDictionary
|
from weakref import WeakKeyDictionary
|
||||||
|
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
@@ -14,8 +16,11 @@ from flask import Flask
|
|||||||
from flask import has_app_context
|
from flask import has_app_context
|
||||||
|
|
||||||
from .model import _QueryProperty
|
from .model import _QueryProperty
|
||||||
|
from .model import BindMixin
|
||||||
from .model import DefaultMeta
|
from .model import DefaultMeta
|
||||||
|
from .model import DefaultMetaNoName
|
||||||
from .model import Model
|
from .model import Model
|
||||||
|
from .model import NameMixin
|
||||||
from .pagination import Pagination
|
from .pagination import Pagination
|
||||||
from .pagination import SelectPagination
|
from .pagination import SelectPagination
|
||||||
from .query import Query
|
from .query import Query
|
||||||
@@ -26,6 +31,33 @@ from .table import _Table
|
|||||||
_O = t.TypeVar("_O", bound=object) # Based on sqlalchemy.orm._typing.py
|
_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:
|
class SQLAlchemy:
|
||||||
"""Integrates SQLAlchemy with Flask. This handles setting up one or more engines,
|
"""Integrates SQLAlchemy with Flask. This handles setting up one or more engines,
|
||||||
associating tables and models with specific engines, and cleaning up connections and
|
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
|
:param add_models_to_shell: Add the ``db`` instance and all model classes to
|
||||||
``flask shell``.
|
``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
|
.. versionchanged:: 3.0
|
||||||
An active Flask application context is always required to access ``session`` and
|
An active Flask application context is always required to access ``session`` and
|
||||||
``engine``.
|
``engine``.
|
||||||
@@ -100,11 +144,6 @@ class SQLAlchemy:
|
|||||||
.. versionchanged:: 3.0
|
.. versionchanged:: 3.0
|
||||||
Removed the ``use_native_unicode`` parameter and config.
|
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
|
.. versionchanged:: 2.4
|
||||||
Added the ``engine_options`` parameter.
|
Added the ``engine_options`` parameter.
|
||||||
|
|
||||||
@@ -129,9 +168,10 @@ class SQLAlchemy:
|
|||||||
metadata: sa.MetaData | None = None,
|
metadata: sa.MetaData | None = None,
|
||||||
session_options: dict[str, t.Any] | None = None,
|
session_options: dict[str, t.Any] | None = None,
|
||||||
query_class: type[Query] = Query,
|
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,
|
engine_options: dict[str, t.Any] | None = None,
|
||||||
add_models_to_shell: bool = True,
|
add_models_to_shell: bool = True,
|
||||||
|
disable_autonaming: bool = False,
|
||||||
):
|
):
|
||||||
if session_options is None:
|
if session_options is None:
|
||||||
session_options = {}
|
session_options = {}
|
||||||
@@ -173,8 +213,17 @@ class SQLAlchemy:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if metadata is not None:
|
if metadata is not None:
|
||||||
metadata.info["bind_key"] = None
|
if len(_get_2x_declarative_bases(model_class)) > 0:
|
||||||
self.metadatas[None] = metadata
|
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()
|
self.Table = self._make_table_class()
|
||||||
"""A :class:`sqlalchemy.schema.Table` class that chooses a metadata
|
"""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.
|
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
|
"""A SQLAlchemy declarative model class. Subclass this to define database
|
||||||
models.
|
models.
|
||||||
|
|
||||||
@@ -204,9 +255,15 @@ class SQLAlchemy:
|
|||||||
database engine. Otherwise, it will use the default :attr:`metadata` and
|
database engine. Otherwise, it will use the default :attr:`metadata` and
|
||||||
:attr:`engine`. This is ignored if the model sets ``metadata`` or ``__table__``.
|
:attr:`engine`. This is ignored if the model sets ``metadata`` or ``__table__``.
|
||||||
|
|
||||||
Customize this by subclassing :class:`.Model` and passing the ``model_class``
|
For code using the SQLAlchemy 1.x API, customize this model by subclassing
|
||||||
parameter to the extension. A fully created declarative model class can be
|
: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.
|
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:
|
if engine_options is None:
|
||||||
@@ -258,25 +315,13 @@ class SQLAlchemy:
|
|||||||
)
|
)
|
||||||
|
|
||||||
app.extensions["sqlalchemy"] = self
|
app.extensions["sqlalchemy"] = self
|
||||||
|
app.teardown_appcontext(self._teardown_session)
|
||||||
|
|
||||||
if self._add_models_to_shell:
|
if self._add_models_to_shell:
|
||||||
from .cli import add_models_to_shell
|
from .cli import add_models_to_shell
|
||||||
|
|
||||||
app.shell_context_processor(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(
|
basic_uri: str | sa.engine.URL | None = app.config.setdefault(
|
||||||
"SQLALCHEMY_DATABASE_URI", None
|
"SQLALCHEMY_DATABASE_URI", None
|
||||||
)
|
)
|
||||||
@@ -393,20 +438,6 @@ class SQLAlchemy:
|
|||||||
options.setdefault("query_cls", self.Query)
|
options.setdefault("query_cls", self.Query)
|
||||||
return sa_orm.sessionmaker(db=self, **options)
|
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:
|
def _teardown_session(self, exc: BaseException | None) -> None:
|
||||||
"""Remove the current session at the end of the request.
|
"""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)):
|
if not args or (len(args) >= 2 and isinstance(args[1], sa.MetaData)):
|
||||||
return super().__new__(cls, *args, **kwargs)
|
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)
|
metadata = self._make_metadata(bind_key)
|
||||||
return super().__new__(cls, *[args[0], metadata, *args[1:]], **kwargs)
|
return super().__new__(cls, *[args[0], metadata, *args[1:]], **kwargs)
|
||||||
|
|
||||||
return Table
|
return Table
|
||||||
|
|
||||||
def _make_declarative_base(
|
def _make_declarative_base(
|
||||||
self, model: type[Model] | sa_orm.DeclarativeMeta
|
self,
|
||||||
) -> type[t.Any]:
|
model_class: _FSA_MCT,
|
||||||
|
disable_autonaming: bool = False,
|
||||||
|
) -> t.Type[_FSAModel]:
|
||||||
"""Create a SQLAlchemy declarative model class. The result is available as
|
"""Create a SQLAlchemy declarative model class. The result is available as
|
||||||
:attr:`Model`.
|
:attr:`Model`.
|
||||||
|
|
||||||
@@ -498,7 +516,14 @@ class SQLAlchemy:
|
|||||||
|
|
||||||
:meta private:
|
: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
|
.. versionchanged:: 3.0
|
||||||
Renamed with a leading underscore, this method is internal.
|
Renamed with a leading underscore, this method is internal.
|
||||||
@@ -506,22 +531,45 @@ class SQLAlchemy:
|
|||||||
.. versionchanged:: 2.3
|
.. versionchanged:: 2.3
|
||||||
``model`` can be an already created declarative model class.
|
``model`` can be an already created declarative model class.
|
||||||
"""
|
"""
|
||||||
if not isinstance(model, sa_orm.DeclarativeMeta):
|
model: t.Type[_FSAModel]
|
||||||
metadata = self._make_metadata(None)
|
declarative_bases = _get_2x_declarative_bases(model_class)
|
||||||
model = sa_orm.declarative_base(
|
if len(declarative_bases) > 1:
|
||||||
metadata=metadata, cls=model, name="Model", metaclass=DefaultMeta
|
# 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:
|
if None not in self.metadatas:
|
||||||
# Use the model's metadata as the default metadata.
|
# Use the model's metadata as the default metadata.
|
||||||
model.metadata.info["bind_key"] = None # type: ignore[union-attr]
|
model.metadata.info["bind_key"] = None
|
||||||
self.metadatas[None] = model.metadata # type: ignore[union-attr]
|
self.metadatas[None] = model.metadata
|
||||||
else:
|
else:
|
||||||
# Use the passed in default metadata as the model's metadata.
|
# 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_class = self.Query
|
||||||
model.query = _QueryProperty()
|
model.query = _QueryProperty() # type: ignore[assignment]
|
||||||
model.__fsa__ = self
|
model.__fsa__ = self
|
||||||
return model
|
return model
|
||||||
|
|
||||||
@@ -660,80 +708,41 @@ class SQLAlchemy:
|
|||||||
"""
|
"""
|
||||||
return self.engines[None]
|
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.
|
"""Get the engine for the given bind key for the current application.
|
||||||
|
|
||||||
This requires that a Flask application context is active.
|
This requires that a Flask application context is active.
|
||||||
|
|
||||||
:param bind_key: The name of the engine.
|
:param bind_key: The name of the engine.
|
||||||
|
|
||||||
.. deprecated:: 3.0
|
.. 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
|
.. versionchanged:: 3.0
|
||||||
Renamed the ``bind`` parameter to ``bind_key``. Removed the ``app``
|
Renamed the ``bind`` parameter to ``bind_key``. Removed the ``app``
|
||||||
parameter.
|
parameter.
|
||||||
"""
|
"""
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"'get_engine' is deprecated and will be removed in Flask-SQLAlchemy 3.1."
|
"'get_engine' is deprecated and will be removed in Flask-SQLAlchemy"
|
||||||
" Use 'engine' or 'engines[key]' instead.",
|
" 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,
|
DeprecationWarning,
|
||||||
stacklevel=2,
|
stacklevel=2,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if "bind" in kwargs:
|
||||||
|
bind_key = kwargs.pop("bind")
|
||||||
|
|
||||||
return self.engines[bind_key]
|
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(
|
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:
|
) -> _O:
|
||||||
"""Like :meth:`session.get() <sqlalchemy.orm.Session.get>` but aborts with a
|
"""Like :meth:`session.get() <sqlalchemy.orm.Session.get>` but aborts with a
|
||||||
``404 Not Found`` error instead of returning ``None``.
|
``404 Not Found`` error instead of returning ``None``.
|
||||||
@@ -741,10 +750,14 @@ class SQLAlchemy:
|
|||||||
:param entity: The model class to query.
|
:param entity: The model class to query.
|
||||||
:param ident: The primary key to query.
|
:param ident: The primary key to query.
|
||||||
:param description: A custom message to show on the error page.
|
: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
|
.. versionadded:: 3.0
|
||||||
"""
|
"""
|
||||||
value = self.session.get(entity, ident)
|
value = self.session.get(entity, ident, **kwargs)
|
||||||
|
|
||||||
if value is None:
|
if value is None:
|
||||||
abort(404, description=description)
|
abort(404, description=description)
|
||||||
@@ -974,24 +987,11 @@ class SQLAlchemy:
|
|||||||
.. versionchanged:: 3.0
|
.. versionchanged:: 3.0
|
||||||
The :attr:`Query` class is set on ``backref``.
|
The :attr:`Query` class is set on ``backref``.
|
||||||
"""
|
"""
|
||||||
# Deprecated, removed in SQLAlchemy 2.0. Accessed through ``__getattr__``.
|
|
||||||
self._set_rel_query(kwargs)
|
self._set_rel_query(kwargs)
|
||||||
f = sa_orm.relationship
|
f = sa_orm.relationship
|
||||||
return f(*args, **kwargs)
|
return f(*args, **kwargs)
|
||||||
|
|
||||||
def __getattr__(self, name: str) -> t.Any:
|
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":
|
if name == "relation":
|
||||||
return self._relation
|
return self._relation
|
||||||
|
|
||||||
|
|||||||
@@ -18,14 +18,6 @@ class _QueryProperty:
|
|||||||
:meta private:
|
: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:
|
def __get__(self, obj: Model | None, cls: type[Model]) -> Query:
|
||||||
return cls.query_class(
|
return cls.query_class(
|
||||||
cls, session=cls.__fsa__.session() # type: ignore[arg-type]
|
cls, session=cls.__fsa__.session() # type: ignore[arg-type]
|
||||||
@@ -100,6 +92,38 @@ class BindMetaMixin(type):
|
|||||||
super().__init__(name, bases, d, **kwargs)
|
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):
|
class NameMetaMixin(type):
|
||||||
"""Metaclass mixin that sets a model's ``__tablename__`` by converting the
|
"""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
|
``CamelCase`` class name to ``snake_case``. A name is set for non-abstract models
|
||||||
@@ -169,6 +193,77 @@ class NameMetaMixin(type):
|
|||||||
return None
|
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:
|
def should_set_tablename(cls: type) -> bool:
|
||||||
"""Determine whether ``__tablename__`` should be generated for a model.
|
"""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
|
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.
|
joined-table inheritance. If no primary key is found, the name will be unset.
|
||||||
"""
|
"""
|
||||||
if cls.__dict__.get("__abstract__", False) or not any(
|
if (
|
||||||
isinstance(b, sa_orm.DeclarativeMeta) for b in cls.__mro__[1:]
|
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
|
return False
|
||||||
|
|
||||||
@@ -196,7 +299,14 @@ def should_set_tablename(cls: type) -> bool:
|
|||||||
return not (
|
return not (
|
||||||
base is cls
|
base is cls
|
||||||
or base.__dict__.get("__abstract__", False)
|
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
|
return True
|
||||||
@@ -212,3 +322,9 @@ class DefaultMeta(BindMetaMixin, NameMetaMixin, sa_orm.DeclarativeMeta):
|
|||||||
"""SQLAlchemy declarative metaclass that provides ``__bind_key__`` and
|
"""SQLAlchemy declarative metaclass that provides ``__bind_key__`` and
|
||||||
``__tablename__`` support.
|
``__tablename__`` support.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class DefaultMetaNoName(BindMetaMixin, sa_orm.DeclarativeMeta):
|
||||||
|
"""SQLAlchemy declarative metaclass that provides ``__bind_key__`` and
|
||||||
|
``__tablename__`` support.
|
||||||
|
"""
|
||||||
|
|||||||
@@ -70,30 +70,6 @@ class _QueryInfo:
|
|||||||
def duration(self) -> float:
|
def duration(self) -> float:
|
||||||
return self.end_time - self.start_time
|
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:
|
def _listen(engine: sa.engine.Engine) -> None:
|
||||||
sa_event.listen(engine, "before_cursor_execute", _record_start, named=True)
|
sa_event.listen(engine, "before_cursor_execute", _record_start, named=True)
|
||||||
|
|||||||
@@ -79,13 +79,22 @@ class Session(sa_orm.Session):
|
|||||||
|
|
||||||
|
|
||||||
def _clause_to_engine(
|
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:
|
) -> sa.engine.Engine | None:
|
||||||
"""If the clause is a table, return the engine associated with the table's
|
"""If the clause is a table, return the engine associated with the table's
|
||||||
metadata's bind key.
|
metadata's bind key.
|
||||||
"""
|
"""
|
||||||
if isinstance(clause, sa.Table) and "bind_key" in clause.metadata.info:
|
table = None
|
||||||
key = clause.metadata.info["bind_key"]
|
|
||||||
|
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:
|
if key not in engines:
|
||||||
raise sa_exc.UnboundExecutionError(
|
raise sa_exc.UnboundExecutionError(
|
||||||
|
|||||||
@@ -5,4 +5,4 @@ from .recaptcha import Recaptcha
|
|||||||
from .recaptcha import RecaptchaField
|
from .recaptcha import RecaptchaField
|
||||||
from .recaptcha import RecaptchaWidget
|
from .recaptcha import RecaptchaWidget
|
||||||
|
|
||||||
__version__ = "1.1.1"
|
__version__ = "1.2.1"
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -217,7 +217,7 @@ class CSRFProtect:
|
|||||||
if not request.endpoint:
|
if not request.endpoint:
|
||||||
return
|
return
|
||||||
|
|
||||||
if request.blueprint in self._exempt_blueprints:
|
if app.blueprints.get(request.blueprint) in self._exempt_blueprints:
|
||||||
return
|
return
|
||||||
|
|
||||||
view = app.view_functions.get(request.endpoint)
|
view = app.view_functions.get(request.endpoint)
|
||||||
@@ -292,7 +292,7 @@ class CSRFProtect:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if isinstance(view, Blueprint):
|
if isinstance(view, Blueprint):
|
||||||
self._exempt_blueprints.add(view.name)
|
self._exempt_blueprints.add(view)
|
||||||
return view
|
return view
|
||||||
|
|
||||||
if isinstance(view, str):
|
if isinstance(view, str):
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from collections import abc
|
|||||||
|
|
||||||
from werkzeug.datastructures import FileStorage
|
from werkzeug.datastructures import FileStorage
|
||||||
from wtforms import FileField as _FileField
|
from wtforms import FileField as _FileField
|
||||||
|
from wtforms import MultipleFileField as _MultipleFileField
|
||||||
from wtforms.validators import DataRequired
|
from wtforms.validators import DataRequired
|
||||||
from wtforms.validators import StopValidation
|
from wtforms.validators import StopValidation
|
||||||
from wtforms.validators import ValidationError
|
from wtforms.validators import ValidationError
|
||||||
@@ -20,8 +21,24 @@ class FileField(_FileField):
|
|||||||
self.raw_data = ()
|
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):
|
class FileRequired(DataRequired):
|
||||||
"""Validates that the data is a Werkzeug
|
"""Validates that the uploaded files(s) is a Werkzeug
|
||||||
:class:`~werkzeug.datastructures.FileStorage` object.
|
:class:`~werkzeug.datastructures.FileStorage` object.
|
||||||
|
|
||||||
:param message: error message
|
:param message: error message
|
||||||
@@ -30,7 +47,10 @@ class FileRequired(DataRequired):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __call__(self, form, field):
|
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(
|
raise StopValidation(
|
||||||
self.message or field.gettext("This field is required.")
|
self.message or field.gettext("This field is required.")
|
||||||
)
|
)
|
||||||
@@ -40,7 +60,7 @@ file_required = FileRequired
|
|||||||
|
|
||||||
|
|
||||||
class FileAllowed:
|
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`.
|
extensions or a Flask-Uploads :class:`~flaskext.uploads.UploadSet`.
|
||||||
|
|
||||||
:param upload_set: A list of extensions or an
|
:param upload_set: A list of extensions or an
|
||||||
@@ -55,34 +75,38 @@ class FileAllowed:
|
|||||||
self.message = message
|
self.message = message
|
||||||
|
|
||||||
def __call__(self, form, field):
|
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
|
return
|
||||||
|
|
||||||
filename = field.data.filename.lower()
|
filenames = [f.filename.lower() for f in field_data]
|
||||||
|
|
||||||
if isinstance(self.upload_set, abc.Iterable):
|
for filename in filenames:
|
||||||
if any(filename.endswith("." + x) for x in self.upload_set):
|
if isinstance(self.upload_set, abc.Iterable):
|
||||||
return
|
if any(filename.endswith("." + x) for x in self.upload_set):
|
||||||
|
continue
|
||||||
|
|
||||||
raise StopValidation(
|
raise StopValidation(
|
||||||
self.message
|
self.message
|
||||||
or field.gettext(
|
or field.gettext(
|
||||||
"File does not have an approved extension: {extensions}"
|
"File does not have an approved extension: {extensions}"
|
||||||
).format(extensions=", ".join(self.upload_set))
|
).format(extensions=", ".join(self.upload_set))
|
||||||
)
|
)
|
||||||
|
|
||||||
if not self.upload_set.file_allowed(field.data, filename):
|
if not self.upload_set.file_allowed(field_data, filename):
|
||||||
raise StopValidation(
|
raise StopValidation(
|
||||||
self.message
|
self.message
|
||||||
or field.gettext("File does not have an approved extension.")
|
or field.gettext("File does not have an approved extension.")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
file_allowed = FileAllowed
|
file_allowed = FileAllowed
|
||||||
|
|
||||||
|
|
||||||
class FileSize:
|
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).
|
file size (set in bytes).
|
||||||
|
|
||||||
:param min_size: minimum allowed file size (in bytes). Defaults to 0 bytes.
|
:param min_size: minimum allowed file size (in bytes). Defaults to 0 bytes.
|
||||||
@@ -98,22 +122,26 @@ class FileSize:
|
|||||||
self.message = message
|
self.message = message
|
||||||
|
|
||||||
def __call__(self, form, field):
|
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
|
return
|
||||||
|
|
||||||
file_size = len(field.data.read())
|
for f in field_data:
|
||||||
field.data.seek(0) # reset cursor position to beginning of file
|
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):
|
if (file_size < self.min_size) or (file_size > self.max_size):
|
||||||
# the file is too small or too big => validation failure
|
# the file is too small or too big => validation failure
|
||||||
raise ValidationError(
|
raise ValidationError(
|
||||||
self.message
|
self.message
|
||||||
or field.gettext(
|
or field.gettext(
|
||||||
"File must be between {min_size} and {max_size} bytes.".format(
|
"File must be between {min_size} and {max_size} bytes.".format(
|
||||||
min_size=self.min_size, max_size=self.max_size
|
min_size=self.min_size, max_size=self.max_size
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
file_size = FileSize
|
file_size = FileSize
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,9 +1,9 @@
|
|||||||
import json
|
import json
|
||||||
from urllib import request as http
|
from urllib import request as http
|
||||||
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
from flask import request
|
from flask import request
|
||||||
from werkzeug.urls import url_encode
|
|
||||||
from wtforms import ValidationError
|
from wtforms import ValidationError
|
||||||
|
|
||||||
RECAPTCHA_VERIFY_SERVER_DEFAULT = "https://www.google.com/recaptcha/api/siteverify"
|
RECAPTCHA_VERIFY_SERVER_DEFAULT = "https://www.google.com/recaptcha/api/siteverify"
|
||||||
@@ -54,7 +54,7 @@ class Recaptcha:
|
|||||||
if not verify_server:
|
if not verify_server:
|
||||||
verify_server = RECAPTCHA_VERIFY_SERVER_DEFAULT
|
verify_server = RECAPTCHA_VERIFY_SERVER_DEFAULT
|
||||||
|
|
||||||
data = url_encode(
|
data = urlencode(
|
||||||
{"secret": private_key, "remoteip": remote_addr, "response": response}
|
{"secret": private_key, "remoteip": remote_addr, "response": response}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
from flask import Markup
|
from markupsafe import Markup
|
||||||
from werkzeug.urls import url_encode
|
|
||||||
|
|
||||||
RECAPTCHA_SCRIPT_DEFAULT = "https://www.google.com/recaptcha/api.js"
|
RECAPTCHA_SCRIPT_DEFAULT = "https://www.google.com/recaptcha/api.js"
|
||||||
RECAPTCHA_DIV_CLASS_DEFAULT = "g-recaptcha"
|
RECAPTCHA_DIV_CLASS_DEFAULT = "g-recaptcha"
|
||||||
@@ -22,10 +23,10 @@ class RecaptchaWidget:
|
|||||||
if not script:
|
if not script:
|
||||||
script = RECAPTCHA_SCRIPT_DEFAULT
|
script = RECAPTCHA_SCRIPT_DEFAULT
|
||||||
if params:
|
if params:
|
||||||
script += "?" + url_encode(params)
|
script += "?" + urlencode(params)
|
||||||
attrs = current_app.config.get("RECAPTCHA_DATA_ATTRS", {})
|
attrs = current_app.config.get("RECAPTCHA_DATA_ATTRS", {})
|
||||||
attrs["sitekey"] = public_key
|
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")
|
div_class = current_app.config.get("RECAPTCHA_DIV_CLASS")
|
||||||
if not div_class:
|
if not div_class:
|
||||||
div_class = RECAPTCHA_DIV_CLASS_DEFAULT
|
div_class = RECAPTCHA_DIV_CLASS_DEFAULT
|
||||||
|
|||||||
@@ -269,7 +269,7 @@ from .types import Uuid as Uuid
|
|||||||
from .types import VARBINARY as VARBINARY
|
from .types import VARBINARY as VARBINARY
|
||||||
from .types import VARCHAR as VARCHAR
|
from .types import VARCHAR as VARCHAR
|
||||||
|
|
||||||
__version__ = "2.0.20"
|
__version__ = "2.0.23"
|
||||||
|
|
||||||
|
|
||||||
def __go(lcls: Any) -> None:
|
def __go(lcls: Any) -> None:
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -227,7 +227,7 @@ class PyODBCConnector(Connector):
|
|||||||
def get_isolation_level_values(
|
def get_isolation_level_values(
|
||||||
self, dbapi_connection: interfaces.DBAPIConnection
|
self, dbapi_connection: interfaces.DBAPIConnection
|
||||||
) -> List[IsolationLevel]:
|
) -> List[IsolationLevel]:
|
||||||
return super().get_isolation_level_values(dbapi_connection) + [ # type: ignore # noqa: E501
|
return super().get_isolation_level_values(dbapi_connection) + [
|
||||||
"AUTOCOMMIT"
|
"AUTOCOMMIT"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -51,7 +51,7 @@ def _auto_fn(name: str) -> Optional[Callable[[], Type[Dialect]]]:
|
|||||||
|
|
||||||
if hasattr(module, driver):
|
if hasattr(module, driver):
|
||||||
module = getattr(module, driver)
|
module = getattr(module, driver)
|
||||||
return lambda: module.dialect # type: ignore
|
return lambda: module.dialect
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -6,6 +6,7 @@
|
|||||||
# the MIT License: https://www.opensource.org/licenses/mit-license.php
|
# the MIT License: https://www.opensource.org/licenses/mit-license.php
|
||||||
# mypy: ignore-errors
|
# mypy: ignore-errors
|
||||||
|
|
||||||
|
from . import aioodbc # noqa
|
||||||
from . import base # noqa
|
from . import base # noqa
|
||||||
from . import pymssql # noqa
|
from . import pymssql # noqa
|
||||||
from . import pyodbc # noqa
|
from . import pyodbc # noqa
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1537,28 +1537,22 @@ class MSUUid(sqltypes.Uuid):
|
|||||||
if self.native_uuid:
|
if self.native_uuid:
|
||||||
|
|
||||||
def process(value):
|
def process(value):
|
||||||
if value is not None:
|
return f"""'{str(value).replace("''", "'")}'"""
|
||||||
value = f"""'{str(value).replace("''", "'")}'"""
|
|
||||||
return value
|
|
||||||
|
|
||||||
return process
|
return process
|
||||||
else:
|
else:
|
||||||
if self.as_uuid:
|
if self.as_uuid:
|
||||||
|
|
||||||
def process(value):
|
def process(value):
|
||||||
if value is not None:
|
return f"""'{value.hex}'"""
|
||||||
value = f"""'{value.hex}'"""
|
|
||||||
return value
|
|
||||||
|
|
||||||
return process
|
return process
|
||||||
else:
|
else:
|
||||||
|
|
||||||
def process(value):
|
def process(value):
|
||||||
if value is not None:
|
return f"""'{
|
||||||
value = f"""'{
|
|
||||||
value.replace("-", "").replace("'", "''")
|
value.replace("-", "").replace("'", "''")
|
||||||
}'"""
|
}'"""
|
||||||
return value
|
|
||||||
|
|
||||||
return process
|
return process
|
||||||
|
|
||||||
@@ -1942,6 +1936,7 @@ class MSExecutionContext(default.DefaultExecutionContext):
|
|||||||
row = self.cursor.fetchall()[0]
|
row = self.cursor.fetchall()[0]
|
||||||
self._lastrowid = int(row[0])
|
self._lastrowid = int(row[0])
|
||||||
|
|
||||||
|
self.cursor_fetch_strategy = _cursor._NO_CURSOR_DML
|
||||||
elif (
|
elif (
|
||||||
self.compiled is not None
|
self.compiled is not None
|
||||||
and is_sql_compiler(self.compiled)
|
and is_sql_compiler(self.compiled)
|
||||||
@@ -2057,6 +2052,12 @@ class MSSQLCompiler(compiler.SQLCompiler):
|
|||||||
def visit_char_length_func(self, fn, **kw):
|
def visit_char_length_func(self, fn, **kw):
|
||||||
return "LEN%s" % self.function_argspec(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(
|
def visit_concat_op_expression_clauselist(
|
||||||
self, clauselist, operator, **kw
|
self, clauselist, operator, **kw
|
||||||
):
|
):
|
||||||
@@ -2119,6 +2120,7 @@ class MSSQLCompiler(compiler.SQLCompiler):
|
|||||||
or (
|
or (
|
||||||
# limit can use TOP with is by itself. fetch only uses TOP
|
# limit can use TOP with is by itself. fetch only uses TOP
|
||||||
# when it needs to because of PERCENT and/or WITH TIES
|
# 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)
|
select._simple_int_clause(select._fetch_clause)
|
||||||
and (
|
and (
|
||||||
select._fetch_clause_options["percent"]
|
select._fetch_clause_options["percent"]
|
||||||
@@ -2379,10 +2381,13 @@ class MSSQLCompiler(compiler.SQLCompiler):
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
def order_by_clause(self, select, **kw):
|
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 (
|
if (
|
||||||
self.is_subquery()
|
self.is_subquery()
|
||||||
and not select._limit
|
and not self._use_top(select)
|
||||||
and (
|
and (
|
||||||
select._offset is None
|
select._offset is None
|
||||||
or not self.dialect._supports_offset_fetch
|
or not self.dialect._supports_offset_fetch
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ class NumericSqlVariant(TypeDecorator):
|
|||||||
cache_ok = True
|
cache_ok = True
|
||||||
|
|
||||||
def column_expression(self, colexpr):
|
def column_expression(self, colexpr):
|
||||||
return cast(colexpr, Numeric)
|
return cast(colexpr, Numeric(38, 0))
|
||||||
|
|
||||||
|
|
||||||
identity_columns = Table(
|
identity_columns = Table(
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ def generate_driver_url(url, driver, query_str):
|
|||||||
|
|
||||||
new_url = url.set(drivername="%s+%s" % (backend, driver))
|
new_url = url.set(drivername="%s+%s" % (backend, driver))
|
||||||
|
|
||||||
if driver != "pyodbc":
|
if driver not in ("pyodbc", "aioodbc"):
|
||||||
new_url = new_url.set(query="")
|
new_url = new_url.set(query="")
|
||||||
|
|
||||||
if query_str:
|
if query_str:
|
||||||
|
|||||||
@@ -365,6 +365,7 @@ from ... import exc
|
|||||||
from ... import types as sqltypes
|
from ... import types as sqltypes
|
||||||
from ... import util
|
from ... import util
|
||||||
from ...connectors.pyodbc import PyODBCConnector
|
from ...connectors.pyodbc import PyODBCConnector
|
||||||
|
from ...engine import cursor as _cursor
|
||||||
|
|
||||||
|
|
||||||
class _ms_numeric_pyodbc:
|
class _ms_numeric_pyodbc:
|
||||||
@@ -585,14 +586,22 @@ class MSExecutionContext_pyodbc(MSExecutionContext):
|
|||||||
try:
|
try:
|
||||||
# fetchall() ensures the cursor is consumed
|
# fetchall() ensures the cursor is consumed
|
||||||
# without closing it (FreeTDS particularly)
|
# without closing it (FreeTDS particularly)
|
||||||
row = self.cursor.fetchall()[0]
|
rows = self.cursor.fetchall()
|
||||||
break
|
|
||||||
except self.dialect.dbapi.Error:
|
except self.dialect.dbapi.Error:
|
||||||
# no way around this - nextset() consumes the previous set
|
# no way around this - nextset() consumes the previous set
|
||||||
# so we need to just keep flipping
|
# so we need to just keep flipping
|
||||||
self.cursor.nextset()
|
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._lastrowid = int(row[0])
|
||||||
|
|
||||||
|
self.cursor_fetch_strategy = _cursor._NO_CURSOR_DML
|
||||||
else:
|
else:
|
||||||
super().post_exec()
|
super().post_exec()
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user