├── .git-blame-ignore-revs ├── .github ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.yaml │ ├── config.yml │ ├── typing.yaml │ └── use_case.yaml ├── SECURITY.md ├── dependabot.yml ├── pull_request_template.md ├── stale.yml └── workflows │ ├── create-wheels.yaml │ ├── run-on-pr.yaml │ ├── run-test.yaml │ └── scripts │ └── can_install.py ├── .gitignore ├── .gitreview ├── .pre-commit-config.yaml ├── AUTHORS ├── CHANGES.rst ├── LICENSE ├── MANIFEST.in ├── README.dialects.rst ├── README.rst ├── README.unittests.rst ├── doc └── build │ ├── Makefile │ ├── changelog │ ├── README.txt │ ├── changelog_01.rst │ ├── changelog_02.rst │ ├── changelog_03.rst │ ├── changelog_04.rst │ ├── changelog_05.rst │ ├── changelog_06.rst │ ├── changelog_07.rst │ ├── changelog_08.rst │ ├── changelog_09.rst │ ├── changelog_10.rst │ ├── changelog_11.rst │ ├── changelog_12.rst │ ├── changelog_13.rst │ ├── changelog_14.rst │ ├── changelog_20.rst │ ├── changelog_21.rst │ ├── index.rst │ ├── migration_04.rst │ ├── migration_05.rst │ ├── migration_06.rst │ ├── migration_07.rst │ ├── migration_08.rst │ ├── migration_09.rst │ ├── migration_10.rst │ ├── migration_11.rst │ ├── migration_12.rst │ ├── migration_13.rst │ ├── migration_14.rst │ ├── migration_20.rst │ ├── migration_21.rst │ ├── unreleased_11 │ │ └── README.txt │ ├── unreleased_12 │ │ └── README.txt │ ├── unreleased_13 │ │ ├── 6135.rst │ │ ├── 6182.rst │ │ ├── 6392.rst │ │ ├── 6589.rst │ │ ├── 7115.rst │ │ └── README.txt │ ├── unreleased_14 │ │ └── README.txt │ ├── unreleased_20 │ │ ├── 12593.rst │ │ ├── 12600.rst │ │ ├── 8664.rst │ │ └── README.txt │ ├── unreleased_21 │ │ ├── 10050.rst │ │ ├── 10197.rst │ │ ├── 10236.rst │ │ ├── 10247.rst │ │ ├── 10296.rst │ │ ├── 10339.rst │ │ ├── 10357.rst │ │ ├── 10415.rst │ │ ├── 10497.rst │ │ ├── 10500.rst │ │ ├── 10564.rst │ │ ├── 10594.rst │ │ ├── 10635.rst │ │ ├── 10646.rst │ │ ├── 10721.rst │ │ ├── 10788.rst │ │ ├── 10789.rst │ │ ├── 10816.rst │ │ ├── 11045.rst │ │ ├── 11163.rst │ │ ├── 11234.rst │ │ ├── 11250.rst │ │ ├── 11349.rst │ │ ├── 11515.rst │ │ ├── 11776.rst │ │ ├── 11811.rst │ │ ├── 12168.rst │ │ ├── 12195.rst │ │ ├── 12218.rst │ │ ├── 12240 .rst │ │ ├── 12293.rst │ │ ├── 12342.rst │ │ ├── 12346.rst │ │ ├── 12395.rst │ │ ├── 12437.rst │ │ ├── 12441.rst │ │ ├── 12479.rst │ │ ├── 5252.rst │ │ ├── 8579.rst │ │ ├── 9647.rst │ │ ├── README.txt │ │ ├── async_fallback.rst │ │ ├── mysql_limit.rst │ │ └── pep_621.rst │ └── whatsnew_20.rst │ ├── conf.py │ ├── contents.rst │ ├── copyright.rst │ ├── core │ ├── api_basics.rst │ ├── compiler.rst │ ├── connections.rst │ ├── constraints.rst │ ├── custom_types.rst │ ├── ddl.rst │ ├── defaults.rst │ ├── dml.rst │ ├── engines.rst │ ├── engines_connections.rst │ ├── event.rst │ ├── events.rst │ ├── exceptions.rst │ ├── expression_api.rst │ ├── foundation.rst │ ├── functions.rst │ ├── future.rst │ ├── index.rst │ ├── inspection.rst │ ├── internals.rst │ ├── metadata.rst │ ├── operators.rst │ ├── pooling.rst │ ├── reflection.rst │ ├── schema.rst │ ├── selectable.rst │ ├── serializer.rst │ ├── sqla_engine_arch.png │ ├── sqlelement.rst │ ├── tutorial.rst │ ├── type_api.rst │ ├── type_basics.rst │ ├── types.rst │ └── visitors.rst │ ├── dialects │ ├── index.rst │ ├── mssql.rst │ ├── mysql.rst │ ├── oracle.rst │ ├── postgresql.rst │ └── sqlite.rst │ ├── errors.rst │ ├── faq │ ├── connections.rst │ ├── index.rst │ ├── installation.rst │ ├── metadata_schema.rst │ ├── ormconfiguration.rst │ ├── performance.rst │ ├── sessions.rst │ ├── sqlexpressions.rst │ └── thirdparty.rst │ ├── glossary.rst │ ├── index.rst │ ├── intro.rst │ ├── orm │ ├── backref.rst │ ├── basic_relationships.rst │ ├── cascades.rst │ ├── classical.rst │ ├── collection_api.rst │ ├── collections.rst │ ├── composites.rst │ ├── constructors.rst │ ├── contextual.rst │ ├── dataclasses.rst │ ├── declarative_config.rst │ ├── declarative_mapping.rst │ ├── declarative_mixins.rst │ ├── declarative_styles.rst │ ├── declarative_tables.rst │ ├── events.rst │ ├── examples.rst │ ├── exceptions.rst │ ├── extending.rst │ ├── extensions │ │ ├── associationproxy.rst │ │ ├── asyncio.rst │ │ ├── automap.rst │ │ ├── baked.rst │ │ ├── declarative │ │ │ ├── api.rst │ │ │ ├── basic_use.rst │ │ │ ├── index.rst │ │ │ ├── inheritance.rst │ │ │ ├── mixins.rst │ │ │ ├── relationships.rst │ │ │ └── table_config.rst │ │ ├── horizontal_shard.rst │ │ ├── hybrid.rst │ │ ├── index.rst │ │ ├── indexable.rst │ │ ├── instrumentation.rst │ │ ├── mutable.rst │ │ └── orderinglist.rst │ ├── index.rst │ ├── inheritance.rst │ ├── inheritance_loading.rst │ ├── internals.rst │ ├── join_conditions.rst │ ├── large_collections.rst │ ├── loading.rst │ ├── loading_columns.rst │ ├── loading_objects.rst │ ├── loading_relationships.rst │ ├── mapped_attributes.rst │ ├── mapped_sql_expr.rst │ ├── mapper_config.rst │ ├── mapping_api.rst │ ├── mapping_columns.rst │ ├── mapping_styles.rst │ ├── nonstandard_mappings.rst │ ├── persistence_techniques.rst │ ├── query.rst │ ├── queryguide.rst │ ├── queryguide │ │ ├── _deferred_setup.rst │ │ ├── _dml_setup.rst │ │ ├── _end_doctest.rst │ │ ├── _inheritance_setup.rst │ │ ├── _plain_setup.rst │ │ ├── _single_inheritance.rst │ │ ├── api.rst │ │ ├── columns.rst │ │ ├── dml.rst │ │ ├── index.rst │ │ ├── inheritance.rst │ │ ├── query.rst │ │ ├── queryguide_nav_include.rst │ │ ├── relationships.rst │ │ └── select.rst │ ├── quickstart.rst │ ├── relationship_api.rst │ ├── relationship_persistence.rst │ ├── relationships.rst │ ├── scalar_mapping.rst │ ├── self_referential.rst │ ├── session.rst │ ├── session_api.rst │ ├── session_basics.rst │ ├── session_events.rst │ ├── session_state_management.rst │ ├── session_transaction.rst │ ├── space_invaders.jpg │ ├── tutorial.rst │ └── versioning.rst │ ├── requirements.txt │ ├── sqla_arch_small.png │ ├── texinputs │ ├── Makefile │ └── sphinx.sty │ └── tutorial │ ├── data.rst │ ├── data_insert.rst │ ├── data_select.rst │ ├── data_update.rst │ ├── dbapi_transactions.rst │ ├── engine.rst │ ├── further_reading.rst │ ├── index.rst │ ├── metadata.rst │ ├── orm_data_manipulation.rst │ ├── orm_related_objects.rst │ └── tutorial_nav_include.rst ├── examples ├── __init__.py ├── adjacency_list │ ├── __init__.py │ └── adjacency_list.py ├── association │ ├── __init__.py │ ├── basic_association.py │ ├── dict_of_sets_with_default.py │ └── proxied_association.py ├── asyncio │ ├── __init__.py │ ├── async_orm.py │ ├── async_orm_writeonly.py │ ├── basic.py │ ├── gather_orm_statements.py │ └── greenlet_orm.py ├── custom_attributes │ ├── __init__.py │ ├── active_column_defaults.py │ ├── custom_management.py │ └── listen_for_events.py ├── dogpile_caching │ ├── __init__.py │ ├── advanced.py │ ├── caching_query.py │ ├── environment.py │ ├── fixture_data.py │ ├── helloworld.py │ ├── local_session_caching.py │ ├── model.py │ └── relationship_caching.py ├── dynamic_dict │ ├── __init__.py │ └── dynamic_dict.py ├── extending_query │ ├── __init__.py │ ├── filter_public.py │ └── temporal_range.py ├── generic_associations │ ├── __init__.py │ ├── discriminator_on_association.py │ ├── generic_fk.py │ ├── table_per_association.py │ └── table_per_related.py ├── graphs │ ├── __init__.py │ └── directed_graph.py ├── inheritance │ ├── __init__.py │ ├── concrete.py │ ├── joined.py │ └── single.py ├── materialized_paths │ ├── __init__.py │ └── materialized_paths.py ├── nested_sets │ ├── __init__.py │ └── nested_sets.py ├── performance │ ├── __init__.py │ ├── __main__.py │ ├── bulk_inserts.py │ ├── bulk_updates.py │ ├── large_resultsets.py │ ├── short_selects.py │ └── single_inserts.py ├── sharding │ ├── __init__.py │ ├── asyncio.py │ ├── separate_databases.py │ ├── separate_schema_translates.py │ └── separate_tables.py ├── space_invaders │ ├── __init__.py │ └── space_invaders.py ├── syntax_extensions │ ├── __init__.py │ ├── qualify.py │ └── test_qualify.py ├── versioned_history │ ├── __init__.py │ ├── history_meta.py │ └── test_versioning.py ├── versioned_rows │ ├── __init__.py │ ├── versioned_map.py │ ├── versioned_rows.py │ ├── versioned_rows_w_versionid.py │ └── versioned_update_old_row.py └── vertical │ ├── __init__.py │ ├── dictlike-polymorphic.py │ └── dictlike.py ├── lib └── sqlalchemy │ ├── __init__.py │ ├── connectors │ ├── __init__.py │ ├── aioodbc.py │ ├── asyncio.py │ └── pyodbc.py │ ├── dialects │ ├── __init__.py │ ├── _typing.py │ ├── mssql │ │ ├── __init__.py │ │ ├── aioodbc.py │ │ ├── base.py │ │ ├── information_schema.py │ │ ├── json.py │ │ ├── provision.py │ │ ├── pymssql.py │ │ └── pyodbc.py │ ├── mysql │ │ ├── __init__.py │ │ ├── aiomysql.py │ │ ├── asyncmy.py │ │ ├── base.py │ │ ├── cymysql.py │ │ ├── dml.py │ │ ├── enumerated.py │ │ ├── expression.py │ │ ├── json.py │ │ ├── mariadb.py │ │ ├── mariadbconnector.py │ │ ├── mysqlconnector.py │ │ ├── mysqldb.py │ │ ├── provision.py │ │ ├── pymysql.py │ │ ├── pyodbc.py │ │ ├── reflection.py │ │ ├── reserved_words.py │ │ └── types.py │ ├── oracle │ │ ├── __init__.py │ │ ├── base.py │ │ ├── cx_oracle.py │ │ ├── dictionary.py │ │ ├── oracledb.py │ │ ├── provision.py │ │ ├── types.py │ │ └── vector.py │ ├── postgresql │ │ ├── __init__.py │ │ ├── _psycopg_common.py │ │ ├── array.py │ │ ├── asyncpg.py │ │ ├── base.py │ │ ├── dml.py │ │ ├── ext.py │ │ ├── hstore.py │ │ ├── json.py │ │ ├── named_types.py │ │ ├── operators.py │ │ ├── pg8000.py │ │ ├── pg_catalog.py │ │ ├── provision.py │ │ ├── psycopg.py │ │ ├── psycopg2.py │ │ ├── psycopg2cffi.py │ │ ├── ranges.py │ │ └── types.py │ ├── sqlite │ │ ├── __init__.py │ │ ├── aiosqlite.py │ │ ├── base.py │ │ ├── dml.py │ │ ├── json.py │ │ ├── provision.py │ │ ├── pysqlcipher.py │ │ └── pysqlite.py │ └── type_migration_guidelines.txt │ ├── engine │ ├── __init__.py │ ├── _processors_cy.py │ ├── _row_cy.py │ ├── _util_cy.py │ ├── base.py │ ├── characteristics.py │ ├── create.py │ ├── cursor.py │ ├── default.py │ ├── events.py │ ├── interfaces.py │ ├── mock.py │ ├── processors.py │ ├── reflection.py │ ├── result.py │ ├── row.py │ ├── strategies.py │ ├── url.py │ └── util.py │ ├── event │ ├── __init__.py │ ├── api.py │ ├── attr.py │ ├── base.py │ ├── legacy.py │ └── registry.py │ ├── events.py │ ├── exc.py │ ├── ext │ ├── __init__.py │ ├── associationproxy.py │ ├── asyncio │ │ ├── __init__.py │ │ ├── base.py │ │ ├── engine.py │ │ ├── exc.py │ │ ├── result.py │ │ ├── scoping.py │ │ └── session.py │ ├── automap.py │ ├── baked.py │ ├── compiler.py │ ├── declarative │ │ ├── __init__.py │ │ └── extensions.py │ ├── horizontal_shard.py │ ├── hybrid.py │ ├── indexable.py │ ├── instrumentation.py │ ├── mutable.py │ ├── orderinglist.py │ └── serializer.py │ ├── future │ ├── __init__.py │ └── engine.py │ ├── inspection.py │ ├── log.py │ ├── orm │ ├── __init__.py │ ├── _orm_constructors.py │ ├── _typing.py │ ├── attributes.py │ ├── base.py │ ├── bulk_persistence.py │ ├── clsregistry.py │ ├── collections.py │ ├── context.py │ ├── decl_api.py │ ├── decl_base.py │ ├── dependency.py │ ├── descriptor_props.py │ ├── dynamic.py │ ├── evaluator.py │ ├── events.py │ ├── exc.py │ ├── identity.py │ ├── instrumentation.py │ ├── interfaces.py │ ├── loading.py │ ├── mapped_collection.py │ ├── mapper.py │ ├── path_registry.py │ ├── persistence.py │ ├── properties.py │ ├── query.py │ ├── relationships.py │ ├── scoping.py │ ├── session.py │ ├── state.py │ ├── state_changes.py │ ├── strategies.py │ ├── strategy_options.py │ ├── sync.py │ ├── unitofwork.py │ ├── util.py │ └── writeonly.py │ ├── pool │ ├── __init__.py │ ├── base.py │ ├── events.py │ └── impl.py │ ├── py.typed │ ├── schema.py │ ├── sql │ ├── __init__.py │ ├── _dml_constructors.py │ ├── _elements_constructors.py │ ├── _orm_types.py │ ├── _selectable_constructors.py │ ├── _typing.py │ ├── _util_cy.py │ ├── annotation.py │ ├── base.py │ ├── cache_key.py │ ├── coercions.py │ ├── compiler.py │ ├── crud.py │ ├── ddl.py │ ├── default_comparator.py │ ├── dml.py │ ├── elements.py │ ├── events.py │ ├── expression.py │ ├── functions.py │ ├── lambdas.py │ ├── naming.py │ ├── operators.py │ ├── roles.py │ ├── schema.py │ ├── selectable.py │ ├── sqltypes.py │ ├── traversals.py │ ├── type_api.py │ ├── util.py │ └── visitors.py │ ├── testing │ ├── __init__.py │ ├── assertions.py │ ├── assertsql.py │ ├── asyncio.py │ ├── config.py │ ├── engines.py │ ├── entities.py │ ├── exclusions.py │ ├── fixtures │ │ ├── __init__.py │ │ ├── base.py │ │ ├── mypy.py │ │ ├── orm.py │ │ └── sql.py │ ├── pickleable.py │ ├── plugin │ │ ├── __init__.py │ │ ├── bootstrap.py │ │ ├── plugin_base.py │ │ └── pytestplugin.py │ ├── profiling.py │ ├── provision.py │ ├── requirements.py │ ├── schema.py │ ├── suite │ │ ├── __init__.py │ │ ├── test_cte.py │ │ ├── test_ddl.py │ │ ├── test_dialect.py │ │ ├── test_insert.py │ │ ├── test_reflection.py │ │ ├── test_results.py │ │ ├── test_rowcount.py │ │ ├── test_select.py │ │ ├── test_sequence.py │ │ ├── test_types.py │ │ ├── test_unicode_ddl.py │ │ └── test_update_delete.py │ ├── util.py │ └── warnings.py │ ├── types.py │ └── util │ ├── __init__.py │ ├── _collections.py │ ├── _collections_cy.pxd │ ├── _collections_cy.py │ ├── _has_cython.py │ ├── _immutabledict_cy.py │ ├── compat.py │ ├── concurrency.py │ ├── cython.py │ ├── deprecations.py │ ├── langhelpers.py │ ├── preloaded.py │ ├── queue.py │ ├── tool_support.py │ ├── topological.py │ └── typing.py ├── mypy_plugin.ini ├── pyproject.toml ├── reap_dbs.py ├── regen_callcounts.tox.ini ├── setup.cfg ├── setup.py ├── test ├── __init__.py ├── aaa_profiling │ ├── __init__.py │ ├── test_compiler.py │ ├── test_memusage.py │ ├── test_misc.py │ ├── test_orm.py │ ├── test_pool.py │ └── test_resultset.py ├── base │ ├── __init__.py │ ├── _concurrency_fixtures.py │ ├── test_concurrency.py │ ├── test_dependency.py │ ├── test_events.py │ ├── test_examples.py │ ├── test_except.py │ ├── test_inspect.py │ ├── test_misc_py3k.py │ ├── test_result.py │ ├── test_tutorials.py │ ├── test_typing_utils.py │ ├── test_utils.py │ └── test_warnings.py ├── binary_data_one.dat ├── binary_data_two.dat ├── conftest.py ├── dialect │ ├── __init__.py │ ├── mssql │ │ ├── __init__.py │ │ ├── test_compiler.py │ │ ├── test_deprecations.py │ │ ├── test_engine.py │ │ ├── test_query.py │ │ ├── test_reflection.py │ │ ├── test_sequence.py │ │ └── test_types.py │ ├── mysql │ │ ├── __init__.py │ │ ├── test_compiler.py │ │ ├── test_deprecations.py │ │ ├── test_dialect.py │ │ ├── test_for_update.py │ │ ├── test_on_duplicate.py │ │ ├── test_query.py │ │ ├── test_reflection.py │ │ └── test_types.py │ ├── oracle │ │ ├── __init__.py │ │ ├── _oracledb_mode.py │ │ ├── test_compiler.py │ │ ├── test_dialect.py │ │ ├── test_reflection.py │ │ └── test_types.py │ ├── postgresql │ │ ├── __init__.py │ │ ├── test_async_pg_py3k.py │ │ ├── test_compiler.py │ │ ├── test_dialect.py │ │ ├── test_on_conflict.py │ │ ├── test_query.py │ │ ├── test_reflection.py │ │ └── test_types.py │ ├── test_all.py │ ├── test_pyodbc.py │ ├── test_sqlite.py │ └── test_suite.py ├── engine │ ├── __init__.py │ ├── test_ddlevents.py │ ├── test_deprecations.py │ ├── test_execute.py │ ├── test_logging.py │ ├── test_parseconnect.py │ ├── test_pool.py │ ├── test_processors.py │ ├── test_reconnect.py │ ├── test_reflection.py │ └── test_transaction.py ├── ext │ ├── __init__.py │ ├── asyncio │ │ ├── __init__.py │ │ ├── test_engine_py3k.py │ │ ├── test_scoping_py3k.py │ │ └── test_session_py3k.py │ ├── declarative │ │ ├── __init__.py │ │ ├── test_deprecations.py │ │ ├── test_inheritance.py │ │ └── test_reflection.py │ ├── test_associationproxy.py │ ├── test_automap.py │ ├── test_baked.py │ ├── test_compiler.py │ ├── test_deprecations.py │ ├── test_extendedattr.py │ ├── test_horizontal_shard.py │ ├── test_hybrid.py │ ├── test_indexable.py │ ├── test_mutable.py │ ├── test_orderinglist.py │ └── test_serializer.py ├── orm │ ├── __init__.py │ ├── _fixtures.py │ ├── declarative │ │ ├── __init__.py │ │ ├── test_abs_import_only.py │ │ ├── test_basic.py │ │ ├── test_clsregistry.py │ │ ├── test_concurrency.py │ │ ├── test_dc_transforms.py │ │ ├── test_dc_transforms_future_anno_sync.py │ │ ├── test_inheritance.py │ │ ├── test_mixin.py │ │ ├── test_reflection.py │ │ ├── test_tm_future_annotations.py │ │ ├── test_tm_future_annotations_sync.py │ │ └── test_typed_mapping.py │ ├── dml │ │ ├── __init__.py │ │ ├── test_bulk.py │ │ ├── test_bulk_statements.py │ │ ├── test_evaluator.py │ │ └── test_update_delete_where.py │ ├── inheritance │ │ ├── __init__.py │ │ ├── _poly_fixtures.py │ │ ├── test_abc_inheritance.py │ │ ├── test_abc_polymorphic.py │ │ ├── test_assorted_poly.py │ │ ├── test_basic.py │ │ ├── test_concrete.py │ │ ├── test_deprecations.py │ │ ├── test_magazine.py │ │ ├── test_manytomany.py │ │ ├── test_poly_linked_list.py │ │ ├── test_poly_loading.py │ │ ├── test_poly_persistence.py │ │ ├── test_polymorphic_rel.py │ │ ├── test_productspec.py │ │ ├── test_relationship.py │ │ ├── test_selects.py │ │ ├── test_single.py │ │ └── test_with_poly.py │ ├── test_ac_relationships.py │ ├── test_association.py │ ├── test_assorted_eager.py │ ├── test_attributes.py │ ├── test_backref_mutations.py │ ├── test_bind.py │ ├── test_bundle.py │ ├── test_cache_key.py │ ├── test_cascade.py │ ├── test_collection.py │ ├── test_compile.py │ ├── test_composites.py │ ├── test_core_compilation.py │ ├── test_cycles.py │ ├── test_dataclasses_py3k.py │ ├── test_default_strategies.py │ ├── test_defaults.py │ ├── test_deferred.py │ ├── test_deprecations.py │ ├── test_descriptor.py │ ├── test_dynamic.py │ ├── test_eager_relations.py │ ├── test_events.py │ ├── test_expire.py │ ├── test_froms.py │ ├── test_generative.py │ ├── test_hasparent.py │ ├── test_immediate_load.py │ ├── test_inspect.py │ ├── test_instrumentation.py │ ├── test_joins.py │ ├── test_lambdas.py │ ├── test_lazy_relations.py │ ├── test_load_on_fks.py │ ├── test_loading.py │ ├── test_lockmode.py │ ├── test_manytomany.py │ ├── test_mapper.py │ ├── test_merge.py │ ├── test_naturalpks.py │ ├── test_of_type.py │ ├── test_onetoone.py │ ├── test_options.py │ ├── test_pickled.py │ ├── test_query.py │ ├── test_recursive_loaders.py │ ├── test_rel_fn.py │ ├── test_relationship_criteria.py │ ├── test_relationships.py │ ├── test_scoping.py │ ├── test_selectable.py │ ├── test_selectin_relations.py │ ├── test_session.py │ ├── test_session_state_change.py │ ├── test_subquery_relations.py │ ├── test_sync.py │ ├── test_syntax_extensions.py │ ├── test_transaction.py │ ├── test_unitofwork.py │ ├── test_unitofworkv2.py │ ├── test_utils.py │ ├── test_validators.py │ └── test_versioning.py ├── perf │ ├── compiled_extensions │ │ ├── __init__.py │ │ ├── __main__.py │ │ ├── base.py │ │ ├── cache_key.py │ │ ├── collections_.py │ │ ├── command.py │ │ ├── misc.py │ │ ├── result.py │ │ └── row.py │ ├── invalidate_stresstest.py │ ├── many_table_reflection.py │ └── orm2010.py ├── profiles.txt ├── requirements.py ├── sql │ ├── __init__.py │ ├── test_case_statement.py │ ├── test_compare.py │ ├── test_compiler.py │ ├── test_computed.py │ ├── test_constraints.py │ ├── test_cte.py │ ├── test_ddlemit.py │ ├── test_defaults.py │ ├── test_delete.py │ ├── test_deprecations.py │ ├── test_external_traversal.py │ ├── test_from_linter.py │ ├── test_functions.py │ ├── test_identity_column.py │ ├── test_insert.py │ ├── test_insert_exec.py │ ├── test_inspect.py │ ├── test_labels.py │ ├── test_lambdas.py │ ├── test_lateral.py │ ├── test_metadata.py │ ├── test_operators.py │ ├── test_query.py │ ├── test_quote.py │ ├── test_resultset.py │ ├── test_returning.py │ ├── test_roles.py │ ├── test_select.py │ ├── test_selectable.py │ ├── test_sequences.py │ ├── test_syntax_extensions.py │ ├── test_tablesample.py │ ├── test_text.py │ ├── test_type_expressions.py │ ├── test_types.py │ ├── test_update.py │ ├── test_utils.py │ └── test_values.py └── typing │ ├── plain_files │ ├── dialects │ │ ├── mysql │ │ │ └── mysql_stuff.py │ │ ├── postgresql │ │ │ └── pg_stuff.py │ │ └── sqlite │ │ │ └── sqlite_stuff.py │ ├── engine │ │ ├── engine_inspection.py │ │ ├── engine_result.py │ │ └── engines.py │ ├── ext │ │ ├── association_proxy │ │ │ ├── association_proxy_one.py │ │ │ ├── association_proxy_three.py │ │ │ └── association_proxy_two.py │ │ ├── asyncio │ │ │ ├── async_sessionmaker.py │ │ │ ├── async_stuff.py │ │ │ ├── create_proxy_methods.py │ │ │ └── engines.py │ │ ├── hybrid │ │ │ ├── hybrid_four.py │ │ │ ├── hybrid_one.py │ │ │ ├── hybrid_three.py │ │ │ └── hybrid_two.py │ │ └── misc_ext.py │ ├── inspection_inspect.py │ ├── orm │ │ ├── complete_orm_no_plugin.py │ │ ├── composite.py │ │ ├── composite_dc.py │ │ ├── dataclass_transforms_one.py │ │ ├── declared_attr_one.py │ │ ├── declared_attr_two.py │ │ ├── dynamic_rel.py │ │ ├── issue_9340.py │ │ ├── keyfunc_dict.py │ │ ├── mapped_assign_expression.py │ │ ├── mapped_column.py │ │ ├── mapped_covariant.py │ │ ├── orm_config_constructs.py │ │ ├── orm_querying.py │ │ ├── relationship.py │ │ ├── scoped_session.py │ │ ├── session.py │ │ ├── sessionmakers.py │ │ ├── trad_relationship_uselist.py │ │ ├── traditional_relationship.py │ │ ├── typed_queries.py │ │ └── write_only.py │ └── sql │ │ ├── common_sql_element.py │ │ ├── core_ddl.py │ │ ├── dml.py │ │ ├── functions.py │ │ ├── functions_again.py │ │ ├── lambda_stmt.py │ │ ├── lowercase_objects.py │ │ ├── misc.py │ │ ├── operators.py │ │ ├── schema.py │ │ ├── sql_operations.py │ │ ├── sqltypes.py │ │ └── typed_results.py │ ├── test_mypy.py │ └── test_overloads.py ├── tools ├── cython_imports.py ├── format_docs_code.py ├── generate_proxy_methods.py ├── generate_sql_functions.py ├── generate_tuple_map_overloads.py ├── normalize_file_headers.py ├── sync_test_files.py ├── trace_orm_adapter.py └── walk_packages.py └── tox.ini /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # This file contains a list of revisions that the SQLAlchemy maintainers 2 | # consider unimportant for git blame purposes because they are pure refactoring 3 | # changes and unlikely to be the cause of bugs. You can configure git to use 4 | # this file by configuring the 'blame.ignoreRevsFile' setting. For example: 5 | # 6 | # $ git config --local blame.ignoreRevsFile .git-blame-ignore-revs 7 | # 8 | 1e1a38e7801f410f244e4bbb44ec795ae152e04e # initial blackification 9 | 1e278de4cc9a4181e0747640a960e80efcea1ca9 # follow up mass style changes 10 | 058c230cea83811c3bebdd8259988c5c501f4f7e # Update black to v23.3.0 and flake8 to v6 11 | 9b153ff18f12eab7b74a20ce53538666600f8bbf # Update black to 24.1.1 12 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | Above all, SQLAlchemy places great emphasis on polite, thoughtful, and 4 | constructive communication between users and developers. 5 | Please see our current Code of Conduct at 6 | [Code of Conduct](https://www.sqlalchemy.org/codeofconduct.html). -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to SQLAlchemy 2 | 3 | Please see out current Developer Guide at [Develop](https://www.sqlalchemy.org/develop.html) 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: sqlalchemy 4 | patreon: zzzeek 5 | tidelift: "pypi/SQLAlchemy" 6 | 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Usage Questions (GitHub Discussions) 4 | url: https://github.com/sqlalchemy/sqlalchemy/discussions/new?category=Usage-Questions 5 | about: Questions and Answers for SQLAlchemy Users 6 | - name: Live Chat on Gitter 7 | url: https://gitter.im/sqlalchemy/community 8 | about: Searchable Web-Based Chat 9 | - name: SQLAlchemy Mailing List 10 | url: https://groups.google.com/forum/#!forum/sqlalchemy 11 | about: Over a decade of questions and answers are here 12 | - name: Ideas / Feature Proposal (GitHub Discussions) 13 | url: https://github.com/sqlalchemy/sqlalchemy/discussions/new?category=Ideas 14 | about: Use this for initial discussion for new features and suggestions 15 | - name: SQLAlchemy Community Guide 16 | url: https://www.sqlalchemy.org/support.html 17 | about: Start here for an overview of SQLAlchemy's support network and posting guidelines 18 | 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/use_case.yaml: -------------------------------------------------------------------------------- 1 | # docs https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-issue-forms 2 | # https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema 3 | 4 | name: Request a new use case 5 | description: Support for new SQL syntaxes, database capabilities, DBAPIs and DBAPI features 6 | labels: [requires triage,use case] 7 | body: 8 | - type: textarea 9 | attributes: 10 | label: Describe the use case 11 | description: A clear and concise description of what the SQL or database capability is. 12 | validations: 13 | required: true 14 | 15 | - type: textarea 16 | attributes: 17 | label: Databases / Backends / Drivers targeted 18 | description: What database(s) is this for? What drivers? 19 | validations: 20 | required: true 21 | 22 | - type: textarea 23 | attributes: 24 | label: Example Use 25 | description: Provide a clear example of what the SQL looks like, or what the DBAPI code looks like 26 | validations: 27 | required: true 28 | 29 | - type: textarea 30 | attributes: 31 | label: Additional context 32 | description: Add any other context about the use case here. 33 | validations: 34 | required: false 35 | 36 | - type: markdown 37 | attributes: 38 | value: "**Have a nice day!**" 39 | -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | For the current supported version of SQLAlchemy, see "Current Release Series" at 6 | https://www.sqlalchemy.org/download.html#current. 7 | 8 | ## Reporting a Vulnerability 9 | 10 | SQLAlchemy participates in the Tidelift security infrastructure for reporting 11 | potential vulnerabilities reponsibly. Please follow the guidelines at: 12 | 13 | https://tidelift.com/docs/security 14 | 15 | in order to report a security issue. Security-related issues in SQLAlchemy 16 | are extremely rare. Nevertheless, we would ask that you please do not file 17 | CVEs without emailing us first, so that proper disclosure steps may be taken. 18 | 19 | 20 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Description 4 | 5 | 6 | ### Checklist 7 | 10 | 11 | This pull request is: 12 | 13 | - [ ] A documentation / typographical / small typing error fix 14 | - Good to go, no issue or tests are needed 15 | - [ ] A short code fix 16 | - please include the issue number, and create an issue if none exists, which 17 | must include a complete example of the issue. one line code fixes without an 18 | issue and demonstration will not be accepted. 19 | - Please include: `Fixes: #` in the commit message 20 | - please include tests. one line code fixes without tests will not be accepted. 21 | - [ ] A new feature implementation 22 | - please include the issue number, and create an issue if none exists, which must 23 | include a complete example of how the feature would look. 24 | - Please include: `Fixes: #` in the commit message 25 | - please include tests. 26 | 27 | **Have a nice day!** 28 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 5 3 | 4 | # Number of days of inactivity before a stale issue is closed 5 | daysUntilClose: 7 6 | 7 | # Issues with these labels will never be considered stale 8 | exemptLabels: 9 | - requires triage 10 | - bug 11 | - regression 12 | - documentation 13 | - use case 14 | - feature 15 | 16 | # Label to use when marking an issue as stale 17 | staleLabel: stale 18 | # Comment to post when marking an issue as stale. Set to `false` to disable 19 | markComment: > 20 | This issue has been automatically marked as stale and we assume it's 21 | marked as "question". It will be closed if no further activity occurs. Thank you 22 | for your contributions. 23 | # Comment to post when closing a stale issue. Set to `false` to disable 24 | closeComment: true 25 | -------------------------------------------------------------------------------- /.github/workflows/scripts/can_install.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from packaging import tags 4 | 5 | to_check = "--" 6 | found = False 7 | if len(sys.argv) > 1: 8 | to_check = sys.argv[1] 9 | for t in tags.sys_tags(): 10 | start = "-".join(str(t).split("-")[:2]) 11 | if to_check.lower() == start: 12 | print( 13 | "Wheel tag {0} matches installed version {1}.".format( 14 | to_check, t 15 | ) 16 | ) 17 | found = True 18 | break 19 | if not found: 20 | print( 21 | "Wheel tag {0} not found in installed version tags {1}.".format( 22 | to_check, [str(t) for t in tags.sys_tags()] 23 | ) 24 | ) 25 | exit(1) 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.pyd 3 | *.pyo 4 | *.egg 5 | /build/ 6 | /dist/ 7 | /doc/build/output/ 8 | /doc/build/_build/ 9 | /dogpile_data/ 10 | *.orig 11 | *,cover 12 | /.tox 13 | /venv/ 14 | .venv 15 | *.egg-info 16 | .coverage 17 | coverage.xml 18 | .*,cover 19 | *.class 20 | *.so 21 | *.patch 22 | sqlnet.log 23 | /shard?_*.db 24 | /test.cfg 25 | /.cache/ 26 | /.mypy_cache 27 | *.sw[o,p] 28 | *.rej 29 | test/test_schema.db 30 | *test_schema.db 31 | .idea 32 | /Pipfile* 33 | /.pytest_cache/ 34 | /pip-wheel-metadata/ 35 | /.vscode/ 36 | /.ipynb_checkpoints/ 37 | *.ipynb 38 | /querytest.db 39 | /.pytest_cache 40 | /db_idents.txt 41 | .DS_Store 42 | .vs 43 | /scratch 44 | 45 | # cython complied files 46 | /lib/**/*.c 47 | /lib/**/*.cpp 48 | # cython annotated output 49 | /lib/**/*.html 50 | -------------------------------------------------------------------------------- /.gitreview: -------------------------------------------------------------------------------- 1 | [gerrit] 2 | host=gerrit.sqlalchemy.org 3 | project=sqlalchemy/sqlalchemy 4 | defaultbranch=main 5 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # See https://pre-commit.com for more information 2 | # See https://pre-commit.com/hooks.html for more hooks 3 | repos: 4 | - repo: https://github.com/python/black 5 | rev: 25.1.0 6 | hooks: 7 | - id: black 8 | 9 | - repo: https://github.com/sqlalchemyorg/zimports 10 | rev: v0.6.0 11 | hooks: 12 | - id: zimports 13 | 14 | - repo: https://github.com/pycqa/flake8 15 | rev: 7.2.0 16 | hooks: 17 | - id: flake8 18 | additional_dependencies: 19 | - flake8-import-order 20 | - flake8-import-single==0.1.5 21 | - flake8-builtins 22 | - flake8-future-annotations>=0.0.5 23 | - flake8-docstrings>=1.6.0 24 | - flake8-unused-arguments 25 | - flake8-rst-docstrings 26 | # flake8-rst-docstrings dependency, leaving it here 27 | # in case it requires a version pin 28 | - pydocstyle 29 | - pygments 30 | 31 | - repo: local 32 | hooks: 33 | - id: black-docs 34 | name: Format docs code block with black 35 | entry: python tools/format_docs_code.py -f 36 | language: python 37 | types: [rst] 38 | exclude: README.* 39 | additional_dependencies: 40 | - black==25.1.0 41 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | SQLAlchemy was created by Michael Bayer. 2 | 3 | Major contributing authors include: 4 | 5 | - Mike Bayer 6 | - Jason Kirtland 7 | - Michael Trier 8 | - Diana Clarke 9 | - Gaetan de Menten 10 | - Lele Gaifax 11 | - Jonathan Ellis 12 | - Gord Thompson 13 | - Federico Caselli 14 | - Philip Jenvey 15 | - Rick Morrison 16 | - Chris Withers 17 | - Ants Aasma 18 | - Sheila Allen 19 | - Paul Johnston 20 | - Tony Locke 21 | - Hajime Nakagami 22 | - Vraj Mohan 23 | - Robert Leftwich 24 | - Taavi Burns 25 | - Jonathan Vanasco 26 | - Jeff Widman 27 | - Scott Dugas 28 | - Dobes Vandermeer 29 | - Ville Skytta 30 | - Rodrigo Menezes 31 | -------------------------------------------------------------------------------- /CHANGES.rst: -------------------------------------------------------------------------------- 1 | ===== 2 | MOVED 3 | ===== 4 | 5 | For an index of all changelogs, please see: 6 | 7 | * On the web: https://www.sqlalchemy.org/docs/latest/changelog/ 8 | * In the source tree: ``_ 9 | * In the released distribution tree: /doc/changelog/index.html 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2005-2025 SQLAlchemy authors and contributors . 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | # any kind of "*" pulls in __init__.pyc files, 2 | # so all extensions are explicit. 3 | 4 | recursive-include doc *.html *.css *.txt *.js *.png *.py Makefile *.rst *.sty 5 | recursive-include examples *.py *.xml 6 | recursive-include test *.py *.dat *.testpatch 7 | recursive-include tools *.py 8 | 9 | # for some reason in some environments stale Cython .c files 10 | # are being pulled in, these should never be in a dist 11 | exclude lib/sqlalchemy/**/*.c 12 | exclude lib/sqlalchemy/**/*.so 13 | 14 | # include the pxd extensions, which otherwise 15 | # don't come in if --with-cextensions isn't specified. 16 | recursive-include lib *.pxd *.txt *.typed 17 | 18 | include README* AUTHORS LICENSE CHANGES* tox.ini 19 | prune doc/build/output 20 | -------------------------------------------------------------------------------- /doc/build/changelog/README.txt: -------------------------------------------------------------------------------- 1 | Individual per-changelog files are placed into their corresponding release's 2 | directory (for example: changelog files for the `1.4` branch are placed in the 3 | `./unreleased_14/` directory, such as `./unreleased_14/4710.rst`). 4 | 5 | Files are in `.rst` format, which are pulled in by 6 | changelog (https://github.com/sqlalchemyorg/changelog; version 0.4.0 or higher) 7 | to be rendered into their corresponding `changelog_xx.rst` file 8 | (for example: `./changelog_14.rst`). At release time, the files in the 9 | `unreleased_xx/` directory are removed and written directly into the changelog. 10 | 11 | Rationale is so that multiple changes being merged into Gerrit don't produce 12 | conflicts. Note that Gerrit does not support alternate merge handlers unlike 13 | git itself (and the alternate merge handlers don't work that well either). 14 | 15 | Each changelog file should be named `{ID}.rst`, wherein `ID` is the unique 16 | identifier of the issue in the Github issue tracker. 17 | 18 | In the example below, the `tags` and `tickets` contain a comma-separated listing 19 | because there are more than one element. 20 | 21 | ================================================================================ 22 | Example Below 23 | ================================================================================ 24 | 25 | 26 | .. change:: 27 | :tags: bug, sql, orm 28 | :tickets: 4839, 3257 29 | 30 | Please use reStructuredText and Sphinx markup when possible. For example 31 | method :meth:`.Index.create` and parameter 32 | :paramref:`.Index.create.checkfirst`, and :class:`.Table` which will 33 | subject to the relevant markup. Also please note the indentions required 34 | for the text. 35 | -------------------------------------------------------------------------------- /doc/build/changelog/changelog_21.rst: -------------------------------------------------------------------------------- 1 | ============= 2 | 2.1 Changelog 3 | ============= 4 | 5 | .. changelog_imports:: 6 | 7 | .. include:: changelog_20.rst 8 | :start-line: 5 9 | 10 | 11 | .. changelog:: 12 | :version: 2.1.0b1 13 | :include_notes_from: unreleased_21 14 | -------------------------------------------------------------------------------- /doc/build/changelog/index.rst: -------------------------------------------------------------------------------- 1 | .. _changelog_toplevel: 2 | 3 | Changes and Migration 4 | ===================== 5 | 6 | SQLAlchemy changelogs and migration guides are now integrated 7 | within the main documentation. 8 | 9 | Current Migration Guide 10 | ----------------------- 11 | 12 | For SQLAlchemy 2.0, there are two separate documents; the "Major Migration 13 | Guide" details how to update a SQLAlchemy 1.4 application to be compatible 14 | under SQLAlchemy 2.0. The "What's New?" document details major new features, 15 | capabilities and behaviors in SQLAlchemy 2.0. 16 | 17 | .. toctree:: 18 | :titlesonly: 19 | 20 | migration_21 21 | 22 | Change logs 23 | ----------- 24 | 25 | .. toctree:: 26 | :titlesonly: 27 | 28 | changelog_21 29 | changelog_20 30 | changelog_14 31 | changelog_13 32 | changelog_12 33 | changelog_11 34 | changelog_10 35 | changelog_09 36 | changelog_08 37 | changelog_07 38 | changelog_06 39 | changelog_05 40 | changelog_04 41 | changelog_03 42 | changelog_02 43 | changelog_01 44 | 45 | 46 | Older Migration Guides 47 | ---------------------- 48 | 49 | .. toctree:: 50 | :titlesonly: 51 | 52 | migration_20 53 | whatsnew_20 54 | migration_14 55 | migration_13 56 | migration_12 57 | migration_11 58 | migration_10 59 | migration_09 60 | migration_08 61 | migration_07 62 | migration_06 63 | migration_05 64 | migration_04 65 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_11/README.txt: -------------------------------------------------------------------------------- 1 | See doc/build/changelog/README.txt for 2 | information on the doc build system. 3 | 4 | 5 | DO NOT REMOVE THIS FILE!!!! THIS DIRECTORY MUST BE PRESENT 6 | FOR DOCS TO BUILD. 7 | 8 | 9 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_12/README.txt: -------------------------------------------------------------------------------- 1 | See doc/build/changelog/README.txt for 2 | information on the doc build system. 3 | 4 | 5 | DO NOT REMOVE THIS FILE!!!! THIS DIRECTORY MUST BE PRESENT 6 | FOR DOCS TO BUILD. 7 | 8 | 9 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_13/6135.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: schema, bug 3 | :tickets: 6135 4 | :versions: 1.4.6 5 | 6 | The :class:`_schema.Table` object now raises an informative error message if 7 | it is instantiated without passing at least the :paramref:`_schema.Table.name` 8 | and :paramref:`_schema.Table.metadata` arguments positionally. Previously, if 9 | these were passed as keyword arguments, the object would silently fail to 10 | initialize correctly. 11 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_13/6182.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: bug, postgresql, regression 3 | :tickets: 6182 4 | :versions: 1.4.5 5 | 6 | Fixed regression caused by :ticket:`6023` where the PostgreSQL cast 7 | operator applied to elements within an :class:`_types.ARRAY` when using 8 | psycopg2 would fail to use the correct type in the case that the datatype 9 | were also embedded within an instance of the :class:`_types.Variant` 10 | adapter. 11 | 12 | Additionally, repairs support for the correct CREATE TYPE to be emitted 13 | when using a ``Variant(ARRAY(some_schema_type))``. 14 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_13/6392.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: bug, orm 3 | :tickets: 6392 4 | :versions: 1.4.12 5 | 6 | Fixed issue in :meth:`_orm.Session.bulk_save_objects` when used with persistent 7 | objects which would fail to track the primary key of mappings where the 8 | column name of the primary key were different than the attribute name. 9 | 10 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_13/6589.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: bug, sqlite 3 | :tickets: 6589 4 | :versions: 1.4.18 5 | 6 | Add note regarding encryption-related pragmas for pysqlcipher passed in the 7 | url. 8 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_13/7115.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: bug, mysql, mariadb 3 | :tickets: 7115, 7136 4 | :versions: 1.4.26 5 | 6 | Fixes to accommodate for the MariaDB 10.6 series, including backwards 7 | incompatible changes in both the mariadb-connector Python driver (supported 8 | on SQLAlchemy 1.4 only) as well as the native 10.6 client libraries that 9 | are used automatically by the mysqlclient DBAPI (applies to both 1.3 and 10 | 1.4). The "utf8mb3" encoding symbol is now reported by these client 11 | libraries when the encoding is stated as "utf8", leading to lookup and 12 | encoding errors within the MySQL dialect that does not expect this symbol. 13 | Updates to both the MySQL base library to accommodate for this utf8mb3 14 | symbol being reported as well as to the test suite. Thanks to Georg Richter 15 | for support. 16 | 17 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_13/README.txt: -------------------------------------------------------------------------------- 1 | See doc/build/changelog/README.txt for 2 | information on the doc build system. 3 | 4 | 5 | DO NOT REMOVE THIS FILE!!!! THIS DIRECTORY MUST BE PRESENT 6 | FOR DOCS TO BUILD. 7 | 8 | 9 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_14/README.txt: -------------------------------------------------------------------------------- 1 | See doc/build/changelog/README.txt for 2 | information on the doc build system. 3 | 4 | 5 | DO NOT REMOVE THIS FILE!!!! THIS DIRECTORY MUST BE PRESENT 6 | FOR DOCS TO BUILD. 7 | 8 | 9 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_20/12593.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: bug, orm 3 | :tickets: 12593 4 | 5 | Implemented the :func:`_orm.defer`, :func:`_orm.undefer` and 6 | :func:`_orm.load_only` loader options to work for composite attributes, a 7 | use case that had never been supported previously. 8 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_20/12600.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: bug, postgresql, reflection 3 | :tickets: 12600 4 | 5 | Fixed regression caused by :ticket:`10665` where the newly modified 6 | constraint reflection query would fail on older versions of PostgreSQL 7 | such as version 9.6. Pull request courtesy Denis Laxalde. 8 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_20/8664.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: usecase, postgresql 3 | :tickets: 8664 4 | 5 | Added ``postgresql_ops`` key to the ``dialect_options`` entry in reflected 6 | dictionary. This maps names of columns used in the index to respective 7 | operator class, if distinct from the default one for column's data type. 8 | Pull request courtesy Denis Laxalde. 9 | 10 | .. seealso:: 11 | 12 | :ref:`postgresql_operator_classes` 13 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_20/README.txt: -------------------------------------------------------------------------------- 1 | Individual per-changelog files go here 2 | in .rst format, which are pulled in by 3 | changelog (version 0.4.0 or higher) to 4 | be rendered into the changelog_xx.rst file. 5 | At release time, the files here are removed and written 6 | directly into the changelog. 7 | 8 | Rationale is so that multiple changes being merged 9 | into gerrit don't produce conflicts. Note that 10 | gerrit does not support custom merge handlers unlike 11 | git itself. 12 | 13 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/10050.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: feature, orm 3 | :tickets: 10050 4 | 5 | The :paramref:`_orm.relationship.back_populates` argument to 6 | :func:`_orm.relationship` may now be passed as a Python callable, which 7 | resolves to either the direct linked ORM attribute, or a string value as 8 | before. ORM attributes are also accepted directly by 9 | :paramref:`_orm.relationship.back_populates`. This change allows type 10 | checkers and IDEs to confirm the argument for 11 | :paramref:`_orm.relationship.back_populates` is valid. Thanks to Priyanshu 12 | Parikh for the help on suggesting and helping to implement this feature. 13 | 14 | .. seealso:: 15 | 16 | :ref:`change_10050` 17 | 18 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/10197.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: change, installation 3 | :tickets: 10197 4 | 5 | The ``greenlet`` dependency used for asyncio support no longer installs 6 | by default. This dependency does not publish wheel files for every architecture 7 | and is not needed for applications that aren't using asyncio features. 8 | Use the ``sqlalchemy[asyncio]`` install target to include this dependency. 9 | 10 | .. seealso:: 11 | 12 | :ref:`change_10197` 13 | 14 | 15 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/10236.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: change, sql 3 | :tickets: 10236 4 | 5 | The ``.c`` and ``.columns`` attributes on the :class:`.Select` and 6 | :class:`.TextualSelect` constructs, which are not instances of 7 | :class:`.FromClause`, have been removed completely, in addition to the 8 | ``.select()`` method as well as other codepaths which would implicitly 9 | generate a subquery from a :class:`.Select` without the need to explicitly 10 | call the :meth:`.Select.subquery` method. 11 | 12 | In the case of ``.c`` and ``.columns``, these attributes were never useful 13 | in practice and have caused a great deal of confusion, hence were 14 | deprecated back in version 1.4, and have emitted warnings since that 15 | version. Accessing the columns that are specific to a :class:`.Select` 16 | construct is done via the :attr:`.Select.selected_columns` attribute, which 17 | was added in version 1.4 to suit the use case that users often expected 18 | ``.c`` to accomplish. In the larger sense, implicit production of 19 | subqueries works against SQLAlchemy's modern practice of making SQL 20 | structure as explicit as possible. 21 | 22 | Note that this is **not related** to the usual :attr:`.FromClause.c` and 23 | :attr:`.FromClause.columns` attributes, common to objects such as 24 | :class:`.Table` and :class:`.Subquery`, which are unaffected by this 25 | change. 26 | 27 | .. seealso:: 28 | 29 | :ref:`change_4617` - original notes from SQLAlchemy 1.4 30 | 31 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/10247.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: schema 3 | :tickets: 10247 4 | 5 | Deprecate Oracle only parameters :paramref:`_schema.Sequence.order`, 6 | :paramref:`_schema.Identity.order` and :paramref:`_schema.Identity.on_null`. 7 | They should be configured using the dialect kwargs ``oracle_order`` and 8 | ``oracle_on_null``. 9 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/10296.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: change, asyncio 3 | :tickets: 10296 4 | 5 | Added an initialize step to the import of 6 | ``sqlalchemy.ext.asyncio`` so that ``greenlet`` will 7 | be imported only when the asyncio extension is first imported. 8 | Alternatively, the ``greenlet`` library is still imported lazily on 9 | first use to support use case that don't make direct use of the 10 | SQLAlchemy asyncio extension. 11 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/10339.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: usecase, mariadb 3 | :tickets: 10339 4 | 5 | Modified the MariaDB dialect so that when using the :class:`_sqltypes.Uuid` 6 | datatype with MariaDB >= 10.7, leaving the 7 | :paramref:`_sqltypes.Uuid.native_uuid` parameter at its default of True, 8 | the native ``UUID`` datatype will be rendered in DDL and used for database 9 | communication, rather than ``CHAR(32)`` (the non-native UUID type) as was 10 | the case previously. This is a behavioral change since 2.0, where the 11 | generic :class:`_sqltypes.Uuid` datatype delivered ``CHAR(32)`` for all 12 | MySQL and MariaDB variants. Support for all major DBAPIs is implemented 13 | including support for less common "insertmanyvalues" scenarios where UUID 14 | values are generated in different ways for primary keys. Thanks much to 15 | Volodymyr Kochetkov for delivering the PR. 16 | 17 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/10357.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: change, installation 3 | :tickets: 10357, 12029 4 | 5 | Python 3.9 or above is now required; support for Python 3.8 and 3.7 is 6 | dropped as these versions are EOL. 7 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/10415.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: change, asyncio 3 | :tickets: 10415 4 | 5 | Adapted all asyncio dialects, including aiosqlite, aiomysql, asyncmy, 6 | psycopg, asyncpg to use the generic asyncio connection adapter first added 7 | in :ticket:`6521` for the aioodbc DBAPI, allowing these dialects to take 8 | advantage of a common framework. 9 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/10497.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: change, orm 3 | :tickets: 10497 4 | 5 | A sweep through class and function names in the ORM renames many classes 6 | and functions that have no intent of public visibility to be underscored. 7 | This is to reduce ambiguity as to which APIs are intended to be targeted by 8 | third party applications and extensions. Third parties are encouraged to 9 | propose new public APIs in Discussions to the extent they are needed to 10 | replace those that have been clarified as private. 11 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/10500.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: change, orm 3 | :tickets: 10500 4 | 5 | The ``first_init`` ORM event has been removed. This event was 6 | non-functional throughout the 1.4 and 2.0 series and could not be invoked 7 | without raising an internal error, so it is not expected that there is any 8 | real-world use of this event hook. 9 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/10564.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: bug, orm 3 | :tickets: 10564 4 | 5 | The :paramref:`_orm.relationship.secondary` parameter no longer uses Python 6 | ``eval()`` to evaluate the given string. This parameter when passed a 7 | string should resolve to a table name that's present in the local 8 | :class:`.MetaData` collection only, and never needs to be any kind of 9 | Python expression otherwise. To use a real deferred callable based on a 10 | name that may not be locally present yet, use a lambda instead. 11 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/10594.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: change, schema 3 | :tickets: 10594 4 | 5 | Changed the default value of :paramref:`_types.Enum.inherit_schema` to 6 | ``True`` when :paramref:`_types.Enum.schema` and 7 | :paramref:`_types.Enum.metadata` parameters are not provided. 8 | The same behavior has been applied also to PostgreSQL 9 | :class:`_postgresql.DOMAIN` type. 10 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/10635.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: typing, feature 3 | :tickets: 10635 4 | 5 | The :class:`.Row` object now no longer makes use of an intermediary 6 | ``Tuple`` in order to represent its individual element types; instead, 7 | the individual element types are present directly, via new :pep:`646` 8 | integration, now available in more recent versions of Mypy. Mypy 9 | 1.7 or greater is now required for statements, results and rows 10 | to be correctly typed. Pull request courtesy Yurii Karabas. 11 | 12 | .. seealso:: 13 | 14 | :ref:`change_10635` 15 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/10646.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: typing 3 | :tickets: 10646 4 | 5 | The default implementation of :attr:`_sql.TypeEngine.python_type` now 6 | returns ``object`` instead of ``NotImplementedError``, since that's the 7 | base for all types in Python3. 8 | The ``python_type`` of :class:`_sql.JSON` no longer returns ``dict``, 9 | but instead fallbacks to the generic implementation. 10 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/10721.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: change, orm 3 | :tickets: 10721 4 | 5 | Removed legacy signatures dating back to 0.9 release from the 6 | :meth:`_orm.SessionEvents.after_bulk_update` and 7 | :meth:`_orm.SessionEvents.after_bulk_delete`. 8 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/10788.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: bug, sql 3 | :tickets: 10788 4 | 5 | Fixed issue in name normalization (e.g. "uppercase" backends like Oracle) 6 | where using a :class:`.TextualSelect` would not properly maintain as 7 | uppercase column names that were quoted as uppercase, even though 8 | the :class:`.TextualSelect` includes a :class:`.Column` that explicitly 9 | holds this uppercase name. 10 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/10789.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: usecase, engine 3 | :tickets: 10789 4 | 5 | Added new execution option 6 | :paramref:`_engine.Connection.execution_options.driver_column_names`. This 7 | option disables the "name normalize" step that takes place against the 8 | DBAPI ``cursor.description`` for uppercase-default backends like Oracle, 9 | and will cause the keys of a result set (e.g. named tuple names, dictionary 10 | keys in :attr:`.Row._mapping`, etc.) to be exactly what was delivered in 11 | cursor.description. This is mostly useful for plain textual statements 12 | using :func:`_sql.text` or :meth:`_engine.Connection.exec_driver_sql`. 13 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/10816.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: usecase, orm 3 | :tickets: 10816 4 | 5 | The :paramref:`_orm.Session.flush.objects` parameter is now 6 | deprecated. -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/11045.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: orm 3 | :tickets: 11045 4 | 5 | The :func:`_orm.noload` relationship loader option and related 6 | ``lazy='noload'`` setting is deprecated and will be removed in a future 7 | release. This option was originally intended for custom loader patterns 8 | that are no longer applicable in modern SQLAlchemy. 9 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/11163.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: orm 3 | :tickets: 11163 4 | 5 | Ignore :paramref:`_orm.Session.join_transaction_mode` in all cases when 6 | the bind provided to the :class:`_orm.Session` is an 7 | :class:`_engine.Engine`. 8 | Previously if an event that executed before the session logic, 9 | like :meth:`_engine.ConnectionEvents.engine_connect`, 10 | left the connection with an active transaction, the 11 | :paramref:`_orm.Session.join_transaction_mode` behavior took 12 | place, leading to a surprising behavior. 13 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/11234.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: bug, engine 3 | :tickets: 11234 4 | 5 | Adjusted URL parsing and stringification to apply url quoting to the 6 | "database" portion of the URL. This allows a URL where the "database" 7 | portion includes special characters such as question marks to be 8 | accommodated. 9 | 10 | .. seealso:: 11 | 12 | :ref:`change_11234` 13 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/11250.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: bug, mssql 3 | :tickets: 11250 4 | 5 | Fix mssql+pyodbc issue where valid plus signs in an already-unquoted 6 | ``odbc_connect=`` (raw DBAPI) connection string are replaced with spaces. 7 | 8 | The pyodbc connector would unconditionally pass the odbc_connect value 9 | to unquote_plus(), even if it was not required. So, if the (unquoted) 10 | odbc_connect value contained ``PWD=pass+word`` that would get changed to 11 | ``PWD=pass word``, and the login would fail. One workaround was to quote 12 | just the plus sign — ``PWD=pass%2Bword`` — which would then get unquoted 13 | to ``PWD=pass+word``. 14 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/11349.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: bug, orm 3 | :tickets: 11349 4 | 5 | Revised the set "binary" operators for the association proxy ``set()`` 6 | interface to correctly raise ``TypeError`` for invalid use of the ``|``, 7 | ``&``, ``^``, and ``-`` operators, as well as the in-place mutation 8 | versions of these methods, to match the behavior of standard Python 9 | ``set()`` as well as SQLAlchemy ORM's "intstrumented" set implementation. 10 | 11 | 12 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/11515.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: bug, sql 3 | :tickets: 11515 4 | 5 | Enhanced the caching structure of the :paramref:`_expression.over.rows` 6 | and :paramref:`_expression.over.range` so that different numerical 7 | values for the rows / 8 | range fields are cached on the same cache key, to the extent that the 9 | underlying SQL does not actually change (i.e. "unbounded", "current row", 10 | negative/positive status will still change the cache key). This prevents 11 | the use of many different numerical range/rows value for a query that is 12 | otherwise identical from filling up the SQL cache. 13 | 14 | Note that the semi-private compiler method ``_format_frame_clause()`` 15 | is removed by this fix, replaced with a new method 16 | ``visit_frame_clause()``. Third party dialects which may have referred 17 | to this method will need to change the name and revise the approach to 18 | rendering the correct SQL for that dialect. 19 | 20 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/11776.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: orm, usecase 3 | :tickets: 11776 4 | 5 | Added the utility method :meth:`_orm.Session.merge_all` and 6 | :meth:`_orm.Session.delete_all` that operate on a collection 7 | of instances. 8 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/11811.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: bug, schema 3 | :tickets: 11811 4 | 5 | The :class:`.Float` and :class:`.Numeric` types are no longer automatically 6 | considered as auto-incrementing columns when the 7 | :paramref:`_schema.Column.autoincrement` parameter is left at its default 8 | of ``"auto"`` on a :class:`_schema.Column` that is part of the primary key. 9 | When the parameter is set to ``True``, a :class:`.Numeric` type will be 10 | accepted as an auto-incrementing datatype for primary key columns, but only 11 | if its scale is explicitly given as zero; otherwise, an error is raised. 12 | This is a change from 2.0 where all numeric types including floats were 13 | automatically considered as "autoincrement" for primary key columns. 14 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/12168.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: bug, orm 3 | :tickets: 12168 4 | 5 | A significant behavioral change has been made to the behavior of the 6 | :paramref:`_orm.mapped_column.default` and 7 | :paramref:`_orm.relationship.default` parameters, when used with 8 | SQLAlchemy's :ref:`orm_declarative_native_dataclasses` feature introduced 9 | in 2.0, where the given value (assumed to be an immutable scalar value) is 10 | no longer passed to the ``@dataclass`` API as a real default, instead a 11 | token that leaves the value un-set in the object's ``__dict__`` is used, in 12 | conjunction with a descriptor-level default. This prevents an un-set 13 | default value from overriding a default that was actually set elsewhere, 14 | such as in relationship / foreign key assignment patterns as well as in 15 | :meth:`_orm.Session.merge` scenarios. See the full writeup in the 16 | :ref:`whatsnew_21_toplevel` document which includes guidance on how to 17 | re-enable the 2.0 version of the behavior if needed. 18 | 19 | .. seealso:: 20 | 21 | :ref:`change_12168` 22 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/12195.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: feature, sql 3 | :tickets: 12195 4 | 5 | Added the ability to create custom SQL constructs that can define new 6 | clauses within SELECT, INSERT, UPDATE, and DELETE statements without 7 | needing to modify the construction or compilation code of of 8 | :class:`.Select`, :class:`_sql.Insert`, :class:`.Update`, or :class:`.Delete` 9 | directly. Support for testing these constructs, including caching support, 10 | is present along with an example test suite. The use case for these 11 | constructs is expected to be third party dialects for analytical SQL 12 | (so-called NewSQL) or other novel styles of database that introduce new 13 | clauses to these statements. A new example suite is included which 14 | illustrates the ``QUALIFY`` SQL construct used by several NewSQL databases 15 | which includes a cachable implementation as well as a test suite. 16 | 17 | .. seealso:: 18 | 19 | :ref:`examples_syntax_extensions` 20 | 21 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/12218.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: sql 3 | :tickets: 12218 4 | 5 | Removed the automatic coercion of executable objects, such as 6 | :class:`_orm.Query`, when passed into :meth:`_orm.Session.execute`. 7 | This usage raised a deprecation warning since the 1.4 series. 8 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/12240 .rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: reflection, mysql, mariadb 3 | :tickets: 12240 4 | 5 | Updated the reflection logic for indexes in the MariaDB and MySQL 6 | dialect to avoid setting the undocumented ``type`` key in the 7 | :class:`_engine.ReflectedIndex` dicts returned by 8 | :class:`_engine.Inspector.get_indexes` method. 9 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/12293.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: typing, orm 3 | :tickets: 12293 4 | 5 | Removed the deprecated mypy plugin. 6 | The plugin was non-functional with newer version of mypy and it's no 7 | longer needed with modern SQLAlchemy declarative style. 8 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/12342.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: feature, postgresql 3 | :tickets: 12342 4 | 5 | Added syntax extension :func:`_postgresql.distinct_on` to build ``DISTINCT 6 | ON`` clauses. The old api, that passed columns to 7 | :meth:`_sql.Select.distinct`, is now deprecated. 8 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/12346.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: typing, orm 3 | :tickets: 12346 4 | 5 | Deprecated the ``declarative_mixin`` decorator since it was used only 6 | by the now removed mypy plugin. 7 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/12395.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: bug, orm 3 | :tickets: 12395 4 | 5 | The behavior of :func:`_orm.with_polymorphic` when used with a single 6 | inheritance mapping has been changed such that its behavior should match as 7 | closely as possible to that of an equivalent joined inheritance mapping. 8 | Specifically this means that the base class specified in the 9 | :func:`_orm.with_polymorphic` construct will be the basemost class that is 10 | loaded, as well as all descendant classes of that basemost class. 11 | The change includes that the descendant classes named will no longer be 12 | exclusively indicated in "WHERE polymorphic_col IN" criteria; instead, the 13 | whole hierarchy starting with the given basemost class will be loaded. If 14 | the query indicates that rows should only be instances of a specific 15 | subclass within the polymorphic hierarchy, an error is raised if an 16 | incompatible superclass is loaded in the result since it cannot be made to 17 | match the requested class; this behavior is the same as what joined 18 | inheritance has done for many years. The change also allows a single result 19 | set to include column-level results from multiple sibling classes at once 20 | which was not previously possible with single table inheritance. 21 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/12437.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: orm, changed 3 | :tickets: 12437 4 | 5 | The "non primary" mapper feature, long deprecated in SQLAlchemy since 6 | version 1.3, has been removed. The sole use case for "non primary" 7 | mappers was that of using :func:`_orm.relationship` to link to a mapped 8 | class against an alternative selectable; this use case is now suited by the 9 | :doc:`relationship_aliased_class` feature. 10 | 11 | 12 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/12441.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: misc, changed 3 | :tickets: 12441 4 | 5 | Removed multiple api that were deprecated in the 1.3 series and earlier. 6 | The list of removed features includes: 7 | 8 | * The ``force`` parameter of ``IdentifierPreparer.quote`` and 9 | ``IdentifierPreparer.quote_schema``; 10 | * The ``threaded`` parameter of the cx-Oracle dialect; 11 | * The ``_json_serializer`` and ``_json_deserializer`` parameters of the 12 | SQLite dialect; 13 | * The ``collection.converter`` decorator; 14 | * The ``Mapper.mapped_table`` property; 15 | * The ``Session.close_all`` method; 16 | * Support for multiple arguments in :func:`_orm.defer` and 17 | :func:`_orm.undefer`. 18 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/12479.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: core, feature, sql 3 | :tickets: 12479 4 | 5 | The Core operator system now includes the ``matmul`` operator, i.e. the 6 | ``@`` operator in Python as an optional operator. 7 | In addition to the ``__matmul__`` and ``__rmatmul__`` operator support 8 | this change also adds the missing ``__rrshift__`` and ``__rlshift__``. 9 | Pull request courtesy Aramís Segovia. 10 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/5252.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: change, sql 3 | :tickets: 5252 4 | 5 | the :class:`.Numeric` and :class:`.Float` SQL types have been separated out 6 | so that :class:`.Float` no longer inherits from :class:`.Numeric`; instead, 7 | they both extend from a common mixin :class:`.NumericCommon`. This 8 | corrects for some architectural shortcomings where numeric and float types 9 | are typically separate, and establishes more consistency with 10 | :class:`.Integer` also being a distinct type. The change should not have 11 | any end-user implications except for code that may be using 12 | ``isinstance()`` to test for the :class:`.Numeric` datatype; third party 13 | dialects which rely upon specific implementation types for numeric and/or 14 | float may also require adjustment to maintain compatibility. 15 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/8579.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: usecase, sql 3 | :tickets: 8579 4 | 5 | Added support for the pow operator (``**``), with a default SQL 6 | implementation of the ``POW()`` function. On Oracle Database, PostgreSQL 7 | and MSSQL it renders as ``POWER()``. As part of this change, the operator 8 | routes through a new first class ``func`` member :class:`_functions.pow`, 9 | which renders on Oracle Database, PostgreSQL and MSSQL as ``POWER()``. 10 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/9647.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: change, engine 3 | :tickets: 9647 4 | 5 | An empty sequence passed to any ``execute()`` method now 6 | raised a deprecation warning, since such an executemany 7 | is invalid. 8 | Pull request courtesy of Carlos Sousa. 9 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/README.txt: -------------------------------------------------------------------------------- 1 | Individual per-changelog files go here 2 | in .rst format, which are pulled in by 3 | changelog (version 0.4.0 or higher) to 4 | be rendered into the changelog_xx.rst file. 5 | At release time, the files here are removed and written 6 | directly into the changelog. 7 | 8 | Rationale is so that multiple changes being merged 9 | into gerrit don't produce conflicts. Note that 10 | gerrit does not support custom merge handlers unlike 11 | git itself. 12 | 13 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/async_fallback.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: change, asyncio 3 | 4 | Removed the compatibility ``async_fallback`` mode for async dialects, 5 | since it's no longer used by SQLAlchemy tests. 6 | Also removed the internal function ``await_fallback()`` and renamed 7 | the internal function ``await_only()`` to ``await_()``. 8 | No change is expected to user code. 9 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/mysql_limit.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: feature, mysql 3 | 4 | Added new construct :func:`_mysql.limit` which can be applied to any 5 | :func:`_sql.update` or :func:`_sql.delete` to provide the LIMIT keyword to 6 | UPDATE and DELETE. This new construct supersedes the use of the 7 | "mysql_limit" dialect keyword argument. 8 | 9 | -------------------------------------------------------------------------------- /doc/build/changelog/unreleased_21/pep_621.rst: -------------------------------------------------------------------------------- 1 | .. change:: 2 | :tags: change, setup 3 | 4 | Updated the setup manifest definition to use PEP 621-compliant 5 | pyproject.toml. 6 | Also updated the extra install dependency to comply with PEP-685. 7 | Thanks for the help of Matt Oberle and KOLANICH on this change. 8 | -------------------------------------------------------------------------------- /doc/build/contents.rst: -------------------------------------------------------------------------------- 1 | .. _contents: 2 | 3 | Table of Contents 4 | ================= 5 | 6 | Full table of contents. For a high level overview of all 7 | documentation, see :ref:`index_toplevel`. 8 | 9 | .. toctree:: 10 | :titlesonly: 11 | :includehidden: 12 | 13 | intro 14 | tutorial/index 15 | orm/index 16 | core/index 17 | dialects/index 18 | faq/index 19 | errors 20 | changelog/index 21 | 22 | Indices and tables 23 | ------------------ 24 | 25 | * :ref:`glossary` 26 | * :ref:`genindex` 27 | -------------------------------------------------------------------------------- /doc/build/copyright.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | ==================== 4 | Appendix: Copyright 5 | ==================== 6 | 7 | This is the MIT license: ``_ 8 | 9 | Copyright (c) 2005-2025 Michael Bayer and contributors. 10 | SQLAlchemy is a trademark of Michael Bayer. 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 13 | software and associated documentation files (the "Software"), to deal in the Software 14 | without restriction, including without limitation the rights to use, copy, modify, merge, 15 | publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons 16 | to whom the Software is furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in all copies or 19 | substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 22 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 23 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 24 | FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 25 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 | DEALINGS IN THE SOFTWARE. 27 | 28 | -------------------------------------------------------------------------------- /doc/build/core/api_basics.rst: -------------------------------------------------------------------------------- 1 | =============== 2 | Core API Basics 3 | =============== 4 | 5 | .. toctree:: 6 | :maxdepth: 2 7 | 8 | event 9 | inspection 10 | exceptions 11 | internals 12 | -------------------------------------------------------------------------------- /doc/build/core/compiler.rst: -------------------------------------------------------------------------------- 1 | .. _sqlalchemy.ext.compiler_toplevel: 2 | 3 | Custom SQL Constructs and Compilation Extension 4 | =============================================== 5 | 6 | .. automodule:: sqlalchemy.ext.compiler 7 | :members: 8 | 9 | 10 | .. autoclass:: sqlalchemy.sql.SyntaxExtension 11 | :members: 12 | -------------------------------------------------------------------------------- /doc/build/core/dml.rst: -------------------------------------------------------------------------------- 1 | Insert, Updates, Deletes 2 | ======================== 3 | 4 | INSERT, UPDATE and DELETE statements build on a hierarchy starting 5 | with :class:`.UpdateBase`. The :class:`_expression.Insert` and :class:`_expression.Update` 6 | constructs build on the intermediary :class:`.ValuesBase`. 7 | 8 | .. currentmodule:: sqlalchemy.sql.expression 9 | 10 | .. _dml_foundational_consructors: 11 | 12 | DML Foundational Constructors 13 | -------------------------------------- 14 | 15 | Top level "INSERT", "UPDATE", "DELETE" constructors. 16 | 17 | .. autofunction:: delete 18 | 19 | .. autofunction:: insert 20 | 21 | .. autofunction:: update 22 | 23 | 24 | DML Class Documentation Constructors 25 | -------------------------------------- 26 | 27 | Class documentation for the constructors listed at 28 | :ref:`dml_foundational_consructors`. 29 | 30 | .. autoclass:: Delete 31 | :members: 32 | 33 | .. automethod:: Delete.where 34 | 35 | .. automethod:: Delete.with_dialect_options 36 | 37 | .. automethod:: Delete.returning 38 | 39 | .. autoclass:: Insert 40 | :members: 41 | 42 | .. automethod:: Insert.with_dialect_options 43 | 44 | .. automethod:: Insert.values 45 | 46 | .. automethod:: Insert.returning 47 | 48 | .. autoclass:: Update 49 | :members: 50 | 51 | .. automethod:: Update.returning 52 | 53 | .. automethod:: Update.where 54 | 55 | .. automethod:: Update.with_dialect_options 56 | 57 | .. automethod:: Update.values 58 | 59 | .. autoclass:: sqlalchemy.sql.expression.UpdateBase 60 | :members: 61 | 62 | .. autoclass:: sqlalchemy.sql.expression.ValuesBase 63 | :members: 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /doc/build/core/engines_connections.rst: -------------------------------------------------------------------------------- 1 | ========================= 2 | Engine and Connection Use 3 | ========================= 4 | 5 | .. toctree:: 6 | :maxdepth: 3 7 | 8 | engines 9 | connections 10 | pooling 11 | events 12 | -------------------------------------------------------------------------------- /doc/build/core/events.rst: -------------------------------------------------------------------------------- 1 | .. _core_event_toplevel: 2 | 3 | Core Events 4 | =========== 5 | 6 | This section describes the event interfaces provided in 7 | SQLAlchemy Core. 8 | For an introduction to the event listening API, see :ref:`event_toplevel`. 9 | ORM events are described in :ref:`orm_event_toplevel`. 10 | 11 | .. autoclass:: sqlalchemy.event.base.Events 12 | :members: 13 | 14 | Connection Pool Events 15 | ---------------------- 16 | 17 | .. autoclass:: sqlalchemy.events.PoolEvents 18 | :members: 19 | 20 | .. autoclass:: sqlalchemy.events.PoolResetState 21 | :members: 22 | 23 | .. _core_sql_events: 24 | 25 | SQL Execution and Connection Events 26 | ----------------------------------- 27 | 28 | .. autoclass:: sqlalchemy.events.ConnectionEvents 29 | :members: 30 | 31 | .. autoclass:: sqlalchemy.events.DialectEvents 32 | :members: 33 | 34 | Schema Events 35 | ------------- 36 | 37 | .. autoclass:: sqlalchemy.events.DDLEvents 38 | :members: 39 | 40 | .. autoclass:: sqlalchemy.events.SchemaEventTarget 41 | :members: 42 | 43 | -------------------------------------------------------------------------------- /doc/build/core/exceptions.rst: -------------------------------------------------------------------------------- 1 | .. _core_exceptions_toplevel: 2 | 3 | Core Exceptions 4 | =============== 5 | 6 | .. automodule:: sqlalchemy.exc 7 | :members: 8 | -------------------------------------------------------------------------------- /doc/build/core/expression_api.rst: -------------------------------------------------------------------------------- 1 | .. _expression_api_toplevel: 2 | 3 | SQL Statements and Expressions API 4 | ================================== 5 | 6 | .. module:: sqlalchemy.sql.expression 7 | 8 | This section presents the API reference for the SQL Expression Language. 9 | For an introduction, start with :ref:`tutorial_working_with_data` 10 | in the :ref:`unified_tutorial`. 11 | 12 | 13 | .. toctree:: 14 | :maxdepth: 3 15 | 16 | sqlelement 17 | operators 18 | selectable 19 | dml 20 | functions 21 | compiler 22 | serializer 23 | foundation 24 | visitors 25 | -------------------------------------------------------------------------------- /doc/build/core/foundation.rst: -------------------------------------------------------------------------------- 1 | .. _core_foundation_toplevel: 2 | 3 | ================================================= 4 | SQL Expression Language Foundational Constructs 5 | ================================================= 6 | 7 | Base classes and mixins that are used to compose SQL Expression Language 8 | elements. 9 | 10 | .. currentmodule:: sqlalchemy.sql.expression 11 | 12 | .. autoclass:: CacheKey 13 | :members: 14 | 15 | .. autoclass:: ClauseElement 16 | :members: 17 | :inherited-members: 18 | 19 | 20 | .. autoclass:: sqlalchemy.sql.base.DialectKWArgs 21 | :members: 22 | 23 | 24 | .. autoclass:: sqlalchemy.sql.traversals.HasCacheKey 25 | :members: 26 | 27 | .. autoclass:: LambdaElement 28 | :members: 29 | 30 | .. autoclass:: StatementLambdaElement 31 | :members: 32 | 33 | -------------------------------------------------------------------------------- /doc/build/core/future.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | SQLAlchemy 2.0 Future (Core) 4 | ============================ 5 | 6 | .. admonition:: We're 2.0! 7 | 8 | This page described the "future" mode provided in SQLAlchemy 1.4 9 | for the purposes of 1.4 -> 2.0 transition. For 2.0, the "future" 10 | parameter on :func:`_sa.create_engine` and :class:`_orm.Session` 11 | continues to remain available for backwards-compatibility support, however 12 | if specified must be left at the value of ``True``. 13 | 14 | .. seealso:: 15 | 16 | :ref:`migration_20_toplevel` - Introduction to the 2.0 series of SQLAlchemy 17 | 18 | -------------------------------------------------------------------------------- /doc/build/core/index.rst: -------------------------------------------------------------------------------- 1 | .. _core_toplevel: 2 | 3 | SQLAlchemy Core 4 | =============== 5 | 6 | The breadth of SQLAlchemy’s SQL rendering engine, DBAPI integration, 7 | transaction integration, and schema description services are documented here. 8 | In contrast to the ORM’s domain-centric mode of usage, the SQL Expression 9 | Language provides a schema-centric usage paradigm. 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | 14 | expression_api 15 | schema 16 | types 17 | engines_connections 18 | api_basics 19 | 20 | -------------------------------------------------------------------------------- /doc/build/core/inspection.rst: -------------------------------------------------------------------------------- 1 | .. _core_inspection_toplevel: 2 | .. _inspection_toplevel: 3 | 4 | Runtime Inspection API 5 | ====================== 6 | 7 | .. automodule:: sqlalchemy.inspection 8 | 9 | .. autofunction:: sqlalchemy.inspect 10 | 11 | 12 | Available Inspection Targets 13 | ---------------------------- 14 | 15 | Below is a listing of many of the most common inspection targets. 16 | 17 | * :class:`.Connectable` (i.e. :class:`_engine.Engine`, 18 | :class:`_engine.Connection`) - returns an :class:`_reflection.Inspector` object. 19 | * :class:`_expression.ClauseElement` - all SQL expression components, including 20 | :class:`_schema.Table`, :class:`_schema.Column`, serve as their own inspection objects, 21 | meaning any of these objects passed to :func:`_sa.inspect` return themselves. 22 | * ``object`` - an object given will be checked by the ORM for a mapping - 23 | if so, an :class:`.InstanceState` is returned representing the mapped 24 | state of the object. The :class:`.InstanceState` also provides access 25 | to per attribute state via the :class:`.AttributeState` interface as well 26 | as the per-flush "history" of any attribute via the :class:`.History` 27 | object. 28 | 29 | .. seealso:: 30 | 31 | :ref:`orm_mapper_inspection_instancestate` 32 | 33 | * ``type`` (i.e. a class) - a class given will be checked by the ORM for a 34 | mapping - if so, a :class:`_orm.Mapper` for that class is returned. 35 | 36 | .. seealso:: 37 | 38 | :ref:`orm_mapper_inspection_mapper` 39 | 40 | * mapped attribute - passing a mapped attribute to :func:`_sa.inspect`, such 41 | as ``inspect(MyClass.some_attribute)``, returns a :class:`.QueryableAttribute` 42 | object, which is the :term:`descriptor` associated with a mapped class. 43 | This descriptor refers to a :class:`.MapperProperty`, which is usually 44 | an instance of :class:`.ColumnProperty` 45 | or :class:`.RelationshipProperty`, via its :attr:`.QueryableAttribute.property` 46 | attribute. 47 | * :class:`.AliasedClass` - returns an :class:`.AliasedInsp` object. 48 | 49 | 50 | -------------------------------------------------------------------------------- /doc/build/core/internals.rst: -------------------------------------------------------------------------------- 1 | .. _core_internal_toplevel: 2 | 3 | Core Internals 4 | ============== 5 | 6 | Some key internal constructs are listed here. 7 | 8 | .. currentmodule:: sqlalchemy 9 | 10 | .. autoclass:: sqlalchemy.engine.BindTyping 11 | :members: 12 | 13 | .. autoclass:: sqlalchemy.engine.Compiled 14 | :members: 15 | 16 | .. autoclass:: sqlalchemy.engine.interfaces.DBAPIConnection 17 | :members: 18 | :undoc-members: 19 | 20 | .. autoclass:: sqlalchemy.engine.interfaces.DBAPICursor 21 | :members: 22 | :undoc-members: 23 | 24 | .. autoclass:: sqlalchemy.engine.interfaces.DBAPIType 25 | :members: 26 | :undoc-members: 27 | 28 | .. autoclass:: sqlalchemy.sql.compiler.DDLCompiler 29 | :members: 30 | :inherited-members: 31 | 32 | .. autoclass:: sqlalchemy.engine.default.DefaultDialect 33 | :members: 34 | :inherited-members: 35 | 36 | .. autoclass:: sqlalchemy.engine.Dialect 37 | :members: 38 | 39 | .. autoclass:: sqlalchemy.engine.default.DefaultExecutionContext 40 | :members: 41 | 42 | 43 | .. autoclass:: sqlalchemy.engine.ExecutionContext 44 | :members: 45 | 46 | .. autoclass:: sqlalchemy.sql.compiler.ExpandedState 47 | :members: 48 | 49 | 50 | .. autoclass:: sqlalchemy.sql.compiler.GenericTypeCompiler 51 | :members: 52 | :inherited-members: 53 | 54 | 55 | .. autoclass:: sqlalchemy.log.Identified 56 | :members: 57 | 58 | 59 | .. autoclass:: sqlalchemy.sql.compiler.IdentifierPreparer 60 | :members: 61 | 62 | 63 | .. autoclass:: sqlalchemy.sql.compiler.SQLCompiler 64 | :members: 65 | 66 | .. autoclass:: sqlalchemy.sql.compiler.StrSQLCompiler 67 | :members: 68 | 69 | 70 | .. autoclass:: sqlalchemy.engine.AdaptedConnection 71 | :members: 72 | 73 | -------------------------------------------------------------------------------- /doc/build/core/schema.rst: -------------------------------------------------------------------------------- 1 | .. _schema_toplevel: 2 | 3 | ========================== 4 | Schema Definition Language 5 | ========================== 6 | 7 | .. currentmodule:: sqlalchemy.schema 8 | 9 | This section references SQLAlchemy **schema metadata**, a comprehensive system of describing and inspecting 10 | database schemas. 11 | 12 | The core of SQLAlchemy's query and object mapping operations are supported by 13 | *database metadata*, which is comprised of Python objects that describe tables 14 | and other schema-level objects. These objects are at the core of three major 15 | types of operations - issuing CREATE and DROP statements (known as *DDL*), 16 | constructing SQL queries, and expressing information about structures that 17 | already exist within the database. 18 | 19 | Database metadata can be expressed by explicitly naming the various components 20 | and their properties, using constructs such as 21 | :class:`~sqlalchemy.schema.Table`, :class:`~sqlalchemy.schema.Column`, 22 | :class:`~sqlalchemy.schema.ForeignKey` and 23 | :class:`~sqlalchemy.schema.Sequence`, all of which are imported from the 24 | ``sqlalchemy.schema`` package. It can also be generated by SQLAlchemy using a 25 | process called *reflection*, which means you start with a single object such 26 | as :class:`~sqlalchemy.schema.Table`, assign it a name, and then instruct 27 | SQLAlchemy to load all the additional information related to that name from a 28 | particular engine source. 29 | 30 | A key feature of SQLAlchemy's database metadata constructs is that they are 31 | designed to be used in a *declarative* style which closely resembles that of 32 | real DDL. They are therefore most intuitive to those who have some background 33 | in creating real schema generation scripts. 34 | 35 | .. toctree:: 36 | :maxdepth: 3 37 | 38 | metadata 39 | reflection 40 | defaults 41 | constraints 42 | ddl 43 | 44 | -------------------------------------------------------------------------------- /doc/build/core/serializer.rst: -------------------------------------------------------------------------------- 1 | Expression Serializer Extension 2 | =============================== 3 | 4 | .. automodule:: sqlalchemy.ext.serializer 5 | :members: 6 | :undoc-members: 7 | -------------------------------------------------------------------------------- /doc/build/core/sqla_engine_arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/doc/build/core/sqla_engine_arch.png -------------------------------------------------------------------------------- /doc/build/core/tutorial.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | ================================= 4 | SQL Expression Language Tutorial 5 | ================================= 6 | 7 | .. admonition:: We've Moved! 8 | 9 | This page is the previous home of the SQLAlchemy 1.x Tutorial. As of 2.0, 10 | SQLAlchemy presents a revised way of working and an all new tutorial that 11 | presents Core and ORM in an integrated fashion using all the latest usage 12 | patterns. See :ref:`unified_tutorial`. 13 | 14 | 15 | -------------------------------------------------------------------------------- /doc/build/core/type_api.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: sqlalchemy.types 2 | 3 | .. _types_api: 4 | 5 | Base Type API 6 | ------------- 7 | 8 | .. autoclass:: TypeEngine 9 | :members: 10 | 11 | 12 | .. autoclass:: Concatenable 13 | :members: 14 | 15 | 16 | .. autoclass:: Indexable 17 | :members: 18 | 19 | .. autoclass:: NullType 20 | 21 | .. autoclass:: ExternalType 22 | :members: 23 | 24 | .. autoclass:: Variant 25 | :members: with_variant, __init__ 26 | -------------------------------------------------------------------------------- /doc/build/core/types.rst: -------------------------------------------------------------------------------- 1 | .. _types_toplevel: 2 | 3 | SQL Datatype Objects 4 | ===================== 5 | 6 | .. toctree:: 7 | :maxdepth: 3 8 | 9 | type_basics 10 | custom_types 11 | type_api 12 | -------------------------------------------------------------------------------- /doc/build/core/visitors.rst: -------------------------------------------------------------------------------- 1 | Visitor and Traversal Utilities 2 | ================================ 3 | 4 | The :mod:`sqlalchemy.sql.visitors` module consists of classes and functions 5 | that serve the purpose of generically **traversing** a Core SQL expression 6 | structure. This is not unlike the Python ``ast`` module in that is presents 7 | a system by which a program can operate upon each component of a SQL 8 | expression. Common purposes this serves are locating various kinds of 9 | elements such as :class:`_schema.Table` or :class:`.BindParameter` objects, 10 | as well as altering the state of the structure such as replacing certain FROM 11 | clauses with others. 12 | 13 | .. note:: the :mod:`sqlalchemy.sql.visitors` module is an internal API and 14 | is not fully public. It is subject to change and may additionally not 15 | function as expected for use patterns that aren't considered within 16 | SQLAlchemy's own internals. 17 | 18 | The :mod:`sqlalchemy.sql.visitors` module is part of the **internals** of 19 | SQLAlchemy and it is not usually used by calling application code. It is 20 | however used in certain edge cases such as when constructing caching routines 21 | as well as when building out custom SQL expressions using the 22 | :ref:`Custom SQL Constructs and Compilation Extension `. 23 | 24 | .. automodule:: sqlalchemy.sql.visitors 25 | :members: 26 | :private-members: 27 | 28 | -------------------------------------------------------------------------------- /doc/build/dialects/sqlite.rst: -------------------------------------------------------------------------------- 1 | .. _sqlite_toplevel: 2 | 3 | SQLite 4 | ====== 5 | 6 | .. automodule:: sqlalchemy.dialects.sqlite.base 7 | 8 | SQLite Data Types 9 | ----------------- 10 | 11 | As with all SQLAlchemy dialects, all UPPERCASE types that are known to be 12 | valid with SQLite are importable from the top level dialect, whether 13 | they originate from :mod:`sqlalchemy.types` or from the local dialect:: 14 | 15 | from sqlalchemy.dialects.sqlite import ( 16 | BLOB, 17 | BOOLEAN, 18 | CHAR, 19 | DATE, 20 | DATETIME, 21 | DECIMAL, 22 | FLOAT, 23 | INTEGER, 24 | NUMERIC, 25 | JSON, 26 | SMALLINT, 27 | TEXT, 28 | TIME, 29 | TIMESTAMP, 30 | VARCHAR, 31 | ) 32 | 33 | .. module:: sqlalchemy.dialects.sqlite 34 | 35 | .. autoclass:: DATETIME 36 | 37 | .. autoclass:: DATE 38 | 39 | .. autoclass:: JSON 40 | 41 | .. autoclass:: TIME 42 | 43 | SQLite DML Constructs 44 | ------------------------- 45 | 46 | .. autofunction:: sqlalchemy.dialects.sqlite.insert 47 | 48 | .. autoclass:: sqlalchemy.dialects.sqlite.Insert 49 | :members: 50 | 51 | .. _pysqlite: 52 | 53 | Pysqlite 54 | -------- 55 | 56 | .. automodule:: sqlalchemy.dialects.sqlite.pysqlite 57 | 58 | .. _aiosqlite: 59 | 60 | Aiosqlite 61 | --------- 62 | 63 | .. automodule:: sqlalchemy.dialects.sqlite.aiosqlite 64 | 65 | 66 | .. _pysqlcipher: 67 | 68 | Pysqlcipher 69 | ----------- 70 | 71 | .. automodule:: sqlalchemy.dialects.sqlite.pysqlcipher 72 | -------------------------------------------------------------------------------- /doc/build/faq/index.rst: -------------------------------------------------------------------------------- 1 | .. _faq_toplevel: 2 | 3 | ========================== 4 | Frequently Asked Questions 5 | ========================== 6 | 7 | The Frequently Asked Questions section is a growing collection of commonly 8 | observed questions to well-known issues. 9 | 10 | .. toctree:: 11 | :maxdepth: 2 12 | 13 | installation 14 | connections 15 | metadata_schema 16 | sqlexpressions 17 | ormconfiguration 18 | performance 19 | sessions 20 | thirdparty 21 | 22 | -------------------------------------------------------------------------------- /doc/build/faq/installation.rst: -------------------------------------------------------------------------------- 1 | Installation 2 | ================= 3 | 4 | .. contents:: 5 | :local: 6 | :class: faq 7 | :backlinks: none 8 | 9 | .. _faq_asyncio_installation: 10 | 11 | I'm getting an error about greenlet not being installed when I try to use asyncio 12 | ---------------------------------------------------------------------------------- 13 | 14 | The ``greenlet`` dependency does not install by default for CPU architectures 15 | for which ``greenlet`` does not supply a `pre-built binary wheel `_. 16 | Notably, **this includes Apple M1**. To install including ``greenlet``, 17 | add the ``asyncio`` `setuptools extra `_ 18 | to the ``pip install`` command: 19 | 20 | .. sourcecode:: text 21 | 22 | pip install sqlalchemy[asyncio] 23 | 24 | For more background, see :ref:`asyncio_install`. 25 | 26 | 27 | .. seealso:: 28 | 29 | :ref:`asyncio_install` 30 | 31 | 32 | -------------------------------------------------------------------------------- /doc/build/orm/classical.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | Moved! :ref:`orm_imperative_mapping` 4 | 5 | 6 | -------------------------------------------------------------------------------- /doc/build/orm/collections.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | ======================================= 4 | Collection Configuration and Techniques 5 | ======================================= 6 | 7 | This page has been broken into two separate pages: 8 | 9 | :doc:`large_collections` 10 | 11 | :doc:`collection_api` 12 | 13 | -------------------------------------------------------------------------------- /doc/build/orm/constructors.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | .. currentmodule:: sqlalchemy.orm 4 | 5 | .. _mapping_constructors: 6 | 7 | Constructors and Object Initialization 8 | ====================================== 9 | 10 | This document has been removed. See :ref:`orm_mapped_class_behavior` 11 | as well as :meth:`_orm.InstanceEvents.load` for what was covered here. 12 | 13 | -------------------------------------------------------------------------------- /doc/build/orm/declarative_mapping.rst: -------------------------------------------------------------------------------- 1 | .. _declarative_config_toplevel: 2 | 3 | ================================ 4 | Mapping Classes with Declarative 5 | ================================ 6 | 7 | The Declarative mapping style is the primary style of mapping that is used 8 | with SQLAlchemy. See the section :ref:`orm_declarative_mapping` for the 9 | top level introduction. 10 | 11 | 12 | .. toctree:: 13 | :maxdepth: 3 14 | 15 | declarative_styles 16 | declarative_tables 17 | declarative_config 18 | declarative_mixins 19 | -------------------------------------------------------------------------------- /doc/build/orm/exceptions.rst: -------------------------------------------------------------------------------- 1 | .. _orm_exceptions_toplevel: 2 | 3 | ORM Exceptions 4 | ============== 5 | 6 | .. automodule:: sqlalchemy.orm.exc 7 | :members: 8 | -------------------------------------------------------------------------------- /doc/build/orm/extending.rst: -------------------------------------------------------------------------------- 1 | ==================== 2 | Events and Internals 3 | ==================== 4 | 5 | The SQLAlchemy ORM as well as Core are extended generally through the use 6 | of event hooks. Be sure to review the use of the event system in general 7 | at :ref:`event_toplevel`. 8 | 9 | 10 | .. toctree:: 11 | :maxdepth: 2 12 | 13 | events 14 | internals 15 | exceptions 16 | 17 | -------------------------------------------------------------------------------- /doc/build/orm/extensions/automap.rst: -------------------------------------------------------------------------------- 1 | .. _automap_toplevel: 2 | 3 | Automap 4 | ======= 5 | 6 | .. automodule:: sqlalchemy.ext.automap 7 | 8 | API Reference 9 | ------------- 10 | 11 | .. autofunction:: automap_base 12 | 13 | .. autoclass:: AutomapBase 14 | :members: 15 | 16 | .. autofunction:: classname_for_table 17 | 18 | .. autofunction:: name_for_scalar_relationship 19 | 20 | .. autofunction:: name_for_collection_relationship 21 | 22 | .. autofunction:: generate_relationship 23 | -------------------------------------------------------------------------------- /doc/build/orm/extensions/declarative/api.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | .. automodule:: sqlalchemy.ext.declarative 4 | 5 | =============== 6 | Declarative API 7 | =============== 8 | 9 | API Reference 10 | ============= 11 | 12 | .. versionchanged:: 1.4 The fundamental structures of the declarative 13 | system are now part of SQLAlchemy ORM directly. For these components 14 | see: 15 | 16 | * :func:`_orm.declarative_base` 17 | 18 | * :class:`_orm.declared_attr` 19 | 20 | * :func:`_orm.has_inherited_table` 21 | 22 | * :func:`_orm.synonym_for` 23 | 24 | * :meth:`_orm.as_declarative` 25 | 26 | See :ref:`declarative_toplevel` for the remaining Declarative extension 27 | classes. 28 | 29 | -------------------------------------------------------------------------------- /doc/build/orm/extensions/declarative/basic_use.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | ========= 4 | Basic Use 5 | ========= 6 | 7 | This section has moved to :ref:`orm_declarative_mapping`. 8 | 9 | Defining Attributes 10 | =================== 11 | 12 | This section is covered by :ref:`mapping_columns_toplevel` 13 | 14 | 15 | 16 | Accessing the MetaData 17 | ====================== 18 | 19 | This section has moved to :ref:`orm_declarative_metadata`. 20 | 21 | 22 | Class Constructor 23 | ================= 24 | 25 | This section has moved to :ref:`orm_mapper_configuration_overview`. 26 | 27 | Mapper Configuration 28 | ==================== 29 | 30 | This section is moved to :ref:`orm_declarative_mapper_options`. 31 | 32 | 33 | .. _declarative_sql_expressions: 34 | 35 | Defining SQL Expressions 36 | ======================== 37 | 38 | See :ref:`mapper_sql_expressions` for examples on declaratively 39 | mapping attributes to SQL expressions. 40 | 41 | -------------------------------------------------------------------------------- /doc/build/orm/extensions/declarative/index.rst: -------------------------------------------------------------------------------- 1 | .. _declarative_toplevel: 2 | 3 | .. currentmodule:: sqlalchemy.ext.declarative 4 | 5 | ====================== 6 | Declarative Extensions 7 | ====================== 8 | 9 | Extensions specific to the :ref:`Declarative ` 10 | mapping API. 11 | 12 | .. versionchanged:: 1.4 The vast majority of the Declarative extension is now 13 | integrated into the SQLAlchemy ORM and is importable from the 14 | ``sqlalchemy.orm`` namespace. See the documentation at 15 | :ref:`orm_declarative_mapping` for new documentation. 16 | For an overview of the change, see :ref:`change_5508`. 17 | 18 | .. autoclass:: AbstractConcreteBase 19 | 20 | .. autoclass:: ConcreteBase 21 | 22 | .. autoclass:: DeferredReflection 23 | :members: 24 | 25 | -------------------------------------------------------------------------------- /doc/build/orm/extensions/declarative/inheritance.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | .. _declarative_inheritance: 4 | 5 | Declarative Inheritance 6 | ======================= 7 | 8 | See :ref:`inheritance_toplevel` for this section. 9 | -------------------------------------------------------------------------------- /doc/build/orm/extensions/declarative/mixins.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | .. _declarative_mixins: 4 | 5 | Mixin and Custom Base Classes 6 | ============================= 7 | 8 | See :ref:`orm_mixins_toplevel` for this section. 9 | -------------------------------------------------------------------------------- /doc/build/orm/extensions/declarative/relationships.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | .. _declarative_configuring_relationships: 4 | 5 | ========================= 6 | Configuring Relationships 7 | ========================= 8 | 9 | This section is covered by :ref:`orm_declarative_properties`. 10 | 11 | .. _declarative_relationship_eval: 12 | 13 | Evaluation of relationship arguments 14 | ===================================== 15 | 16 | This section is moved to :ref:`orm_declarative_relationship_eval`. 17 | 18 | 19 | .. _declarative_many_to_many: 20 | 21 | Configuring Many-to-Many Relationships 22 | ====================================== 23 | 24 | This section is moved to :ref:`orm_declarative_relationship_secondary_eval`. 25 | 26 | -------------------------------------------------------------------------------- /doc/build/orm/extensions/declarative/table_config.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | .. _declarative_table_args: 4 | 5 | =================== 6 | Table Configuration 7 | =================== 8 | 9 | This section has moved; see :ref:`orm_declarative_table_configuration`. 10 | 11 | 12 | .. _declarative_hybrid_table: 13 | 14 | Using a Hybrid Approach with __table__ 15 | ====================================== 16 | 17 | This section has moved; see :ref:`orm_imperative_table_configuration`. 18 | 19 | 20 | Using Reflection with Declarative 21 | ================================= 22 | 23 | This section has moved to :ref:`orm_declarative_reflected`. 24 | 25 | -------------------------------------------------------------------------------- /doc/build/orm/extensions/horizontal_shard.rst: -------------------------------------------------------------------------------- 1 | .. _horizontal_sharding_toplevel: 2 | 3 | Horizontal Sharding 4 | =================== 5 | 6 | .. automodule:: sqlalchemy.ext.horizontal_shard 7 | 8 | API Documentation 9 | ----------------- 10 | 11 | .. autoclass:: ShardedSession 12 | :members: 13 | 14 | .. autoclass:: set_shard_id 15 | :members: 16 | 17 | .. autoclass:: ShardedQuery 18 | :members: 19 | 20 | -------------------------------------------------------------------------------- /doc/build/orm/extensions/hybrid.rst: -------------------------------------------------------------------------------- 1 | .. _hybrids_toplevel: 2 | 3 | Hybrid Attributes 4 | ================= 5 | 6 | .. automodule:: sqlalchemy.ext.hybrid 7 | 8 | API Reference 9 | ------------- 10 | 11 | .. autoclass:: hybrid_method 12 | :members: 13 | 14 | .. autoclass:: hybrid_property 15 | :members: 16 | 17 | .. autoclass:: Comparator 18 | 19 | 20 | .. autoclass:: HybridExtensionType 21 | :members: 22 | -------------------------------------------------------------------------------- /doc/build/orm/extensions/index.rst: -------------------------------------------------------------------------------- 1 | .. _plugins: 2 | .. _sqlalchemy.ext: 3 | 4 | ORM Extensions 5 | ============== 6 | 7 | SQLAlchemy has a variety of ORM extensions available, which add additional 8 | functionality to the core behavior. 9 | 10 | The extensions build almost entirely on public core and ORM APIs and users should 11 | be encouraged to read their source code to further their understanding of their 12 | behavior. In particular the "Horizontal Sharding", "Hybrid Attributes", and 13 | "Mutation Tracking" extensions are very succinct. 14 | 15 | .. toctree:: 16 | :maxdepth: 1 17 | 18 | asyncio 19 | associationproxy 20 | automap 21 | baked 22 | declarative/index 23 | mutable 24 | orderinglist 25 | horizontal_shard 26 | hybrid 27 | indexable 28 | instrumentation 29 | 30 | -------------------------------------------------------------------------------- /doc/build/orm/extensions/indexable.rst: -------------------------------------------------------------------------------- 1 | .. _indexable_toplevel: 2 | 3 | Indexable 4 | ========= 5 | 6 | .. automodule:: sqlalchemy.ext.indexable 7 | 8 | API Reference 9 | ------------- 10 | 11 | .. autoclass:: sqlalchemy.ext.indexable.index_property 12 | :members: 13 | 14 | -------------------------------------------------------------------------------- /doc/build/orm/extensions/instrumentation.rst: -------------------------------------------------------------------------------- 1 | .. _instrumentation_toplevel: 2 | 3 | Alternate Class Instrumentation 4 | =============================== 5 | 6 | .. automodule:: sqlalchemy.ext.instrumentation 7 | 8 | API Reference 9 | ------------- 10 | 11 | .. autodata:: INSTRUMENTATION_MANAGER 12 | 13 | .. autoclass:: sqlalchemy.orm.instrumentation.InstrumentationFactory 14 | 15 | .. autoclass:: InstrumentationManager 16 | :members: 17 | :undoc-members: 18 | 19 | .. autodata:: instrumentation_finders 20 | 21 | .. autoclass:: ExtendedInstrumentationRegistry 22 | :members: 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /doc/build/orm/extensions/mutable.rst: -------------------------------------------------------------------------------- 1 | .. _mutable_toplevel: 2 | 3 | Mutation Tracking 4 | ================= 5 | 6 | .. automodule:: sqlalchemy.ext.mutable 7 | 8 | API Reference 9 | ------------- 10 | 11 | .. autoclass:: MutableBase 12 | :members: _parents, coerce 13 | 14 | .. autoclass:: Mutable 15 | :members: 16 | :inherited-members: 17 | :private-members: 18 | 19 | .. autoclass:: MutableComposite 20 | :members: 21 | 22 | .. autoclass:: MutableDict 23 | :members: 24 | :undoc-members: 25 | 26 | .. autoclass:: MutableList 27 | :members: 28 | :undoc-members: 29 | 30 | .. autoclass:: MutableSet 31 | :members: 32 | :undoc-members: 33 | 34 | 35 | -------------------------------------------------------------------------------- /doc/build/orm/extensions/orderinglist.rst: -------------------------------------------------------------------------------- 1 | Ordering List 2 | ============= 3 | 4 | .. automodule:: sqlalchemy.ext.orderinglist 5 | 6 | API Reference 7 | ------------- 8 | 9 | .. autofunction:: ordering_list 10 | 11 | .. autofunction:: count_from_0 12 | 13 | .. autofunction:: count_from_1 14 | 15 | .. autofunction:: count_from_n_factory 16 | 17 | .. autoclass:: OrderingList 18 | :members: 19 | -------------------------------------------------------------------------------- /doc/build/orm/index.rst: -------------------------------------------------------------------------------- 1 | .. _orm_toplevel: 2 | 3 | SQLAlchemy ORM 4 | ============== 5 | 6 | Here, the Object Relational Mapper is introduced and fully described. If you 7 | want to work with higher-level SQL which is constructed automatically for you, 8 | as well as automated persistence of Python objects, proceed first to the 9 | tutorial. 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | 14 | quickstart 15 | mapper_config 16 | relationships 17 | queryguide/index 18 | session 19 | extending 20 | extensions/index 21 | examples 22 | 23 | -------------------------------------------------------------------------------- /doc/build/orm/inheritance_loading.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | This document has moved to :doc:`queryguide/inheritance` 4 | 5 | -------------------------------------------------------------------------------- /doc/build/orm/internals.rst: -------------------------------------------------------------------------------- 1 | .. _orm_internal_toplevel: 2 | 3 | ORM Internals 4 | ============= 5 | 6 | Key ORM constructs, not otherwise covered in other 7 | sections, are listed here. 8 | 9 | .. currentmodule:: sqlalchemy.orm 10 | 11 | .. autoclass:: AttributeState 12 | :members: 13 | 14 | .. autoclass:: CascadeOptions 15 | :members: 16 | 17 | .. autoclass:: ClassManager 18 | :members: 19 | 20 | .. autoclass:: ColumnProperty 21 | :members: 22 | 23 | .. autoclass:: Composite 24 | 25 | .. autoclass:: CompositeProperty 26 | :members: 27 | 28 | .. autoclass:: AttributeEventToken 29 | :members: 30 | 31 | .. autoclass:: IdentityMap 32 | :members: 33 | 34 | .. autoclass:: InspectionAttr 35 | :members: 36 | 37 | .. autoclass:: InspectionAttrInfo 38 | :members: 39 | 40 | .. autoclass:: InstanceState 41 | :members: 42 | 43 | 44 | .. autoclass:: InstrumentedAttribute 45 | :members: 46 | 47 | .. autoclass:: LoaderCallableStatus 48 | :members: 49 | 50 | .. autoclass:: Mapped 51 | 52 | .. autoclass:: MappedColumn 53 | 54 | .. autoclass:: MapperProperty 55 | :members: 56 | 57 | .. autoclass:: MappedSQLExpression 58 | 59 | .. autoclass:: InspectionAttrExtensionType 60 | :members: 61 | 62 | .. autoclass:: NotExtension 63 | :members: 64 | 65 | .. autofunction:: merge_result 66 | 67 | .. autofunction:: merge_frozen_result 68 | 69 | 70 | .. autoclass:: PropComparator 71 | :members: 72 | :inherited-members: 73 | 74 | .. autoclass:: Relationship 75 | 76 | .. autoclass:: RelationshipDirection 77 | :members: 78 | 79 | .. autoclass:: RelationshipProperty 80 | :members: 81 | 82 | .. autoclass:: SQLORMExpression 83 | 84 | .. autoclass:: Synonym 85 | 86 | .. autoclass:: SynonymProperty 87 | :members: 88 | 89 | .. autoclass:: QueryContext 90 | :members: 91 | 92 | 93 | .. autoclass:: QueryableAttribute 94 | :members: 95 | 96 | .. autoclass:: UOWTransaction 97 | :members: 98 | 99 | -------------------------------------------------------------------------------- /doc/build/orm/loading.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | Moved! :doc:`/orm/loading_relationships` 4 | -------------------------------------------------------------------------------- /doc/build/orm/loading_columns.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | This document has moved to :doc:`queryguide/columns` 4 | 5 | -------------------------------------------------------------------------------- /doc/build/orm/loading_objects.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | This document has moved to :doc:`queryguide/index` 4 | 5 | -------------------------------------------------------------------------------- /doc/build/orm/loading_relationships.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | This document has moved to :doc:`queryguide/relationships` 4 | 5 | -------------------------------------------------------------------------------- /doc/build/orm/mapper_config.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _mapper_config_toplevel: 3 | 4 | =============================== 5 | ORM Mapped Class Configuration 6 | =============================== 7 | 8 | Detailed reference for ORM configuration, not including 9 | relationships, which are detailed at 10 | :ref:`relationship_config_toplevel`. 11 | 12 | For a quick look at a typical ORM configuration, start with 13 | :ref:`orm_quickstart`. 14 | 15 | For an introduction to the concept of object relational mapping as implemented 16 | in SQLAlchemy, it's first introduced in the :ref:`unified_tutorial` at 17 | :ref:`tutorial_orm_table_metadata`. 18 | 19 | 20 | .. toctree:: 21 | :maxdepth: 4 22 | 23 | mapping_styles 24 | declarative_mapping 25 | dataclasses 26 | mapped_sql_expr 27 | mapped_attributes 28 | composites 29 | inheritance 30 | nonstandard_mappings 31 | versioning 32 | mapping_api 33 | 34 | .. toctree:: 35 | :hidden: 36 | 37 | scalar_mapping 38 | -------------------------------------------------------------------------------- /doc/build/orm/mapping_columns.rst: -------------------------------------------------------------------------------- 1 | .. _mapping_columns_toplevel: 2 | 3 | Mapping Table Columns 4 | ===================== 5 | 6 | This section has been integrated into the 7 | :ref:`orm_declarative_table_config_toplevel` section. 8 | 9 | 10 | -------------------------------------------------------------------------------- /doc/build/orm/query.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | This document has moved to :doc:`queryguide/query` 4 | -------------------------------------------------------------------------------- /doc/build/orm/queryguide.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | This document has moved to :doc:`queryguide/index`. 4 | 5 | -------------------------------------------------------------------------------- /doc/build/orm/queryguide/_end_doctest.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | .. Setup code, not for display 4 | 5 | >>> session.close() 6 | >>> conn.close() 7 | -------------------------------------------------------------------------------- /doc/build/orm/queryguide/index.rst: -------------------------------------------------------------------------------- 1 | .. highlight:: pycon+sql 2 | 3 | .. _queryguide_toplevel: 4 | 5 | ================== 6 | ORM Querying Guide 7 | ================== 8 | 9 | This section provides an overview of emitting queries with the 10 | SQLAlchemy ORM using :term:`2.0 style` usage. 11 | 12 | Readers of this section should be familiar with the SQLAlchemy overview 13 | at :ref:`unified_tutorial`, and in particular most of the content here expands 14 | upon the content at :ref:`tutorial_selecting_data`. 15 | 16 | .. admonition:: For users of SQLAlchemy 1.x 17 | 18 | In the SQLAlchemy 2.x series, SQL SELECT statements for the ORM are 19 | constructed using the same :func:`_sql.select` construct as is used in 20 | Core, which is then invoked in terms of a :class:`_orm.Session` using the 21 | :meth:`_orm.Session.execute` method (as are the :func:`_sql.update` and 22 | :func:`_sql.delete` constructs now used for the 23 | :ref:`orm_expression_update_delete` feature). However, the legacy 24 | :class:`_query.Query` object, which performs these same steps as more of an 25 | "all-in-one" object, continues to remain available as a thin facade over 26 | this new system, to support applications that were built on the 1.x series 27 | without the need for wholesale replacement of all queries. For reference on 28 | this object, see the section :ref:`query_api_toplevel`. 29 | 30 | 31 | 32 | 33 | .. toctree:: 34 | :maxdepth: 3 35 | 36 | select 37 | inheritance 38 | dml 39 | columns 40 | relationships 41 | api 42 | query 43 | -------------------------------------------------------------------------------- /doc/build/orm/queryguide/queryguide_nav_include.rst: -------------------------------------------------------------------------------- 1 | .. note *_include.rst is a naming convention in conf.py 2 | 3 | .. |tutorial_title| replace:: ORM Querying Guide 4 | 5 | .. topic:: |tutorial_title| 6 | 7 | This page is part of the :doc:`index`. 8 | 9 | Previous: |prev| | Next: |next| 10 | 11 | .. footer_topic:: |tutorial_title| 12 | 13 | Next Query Guide Section: |next| 14 | 15 | -------------------------------------------------------------------------------- /doc/build/orm/relationship_api.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: sqlalchemy.orm 2 | 3 | Relationships API 4 | ----------------- 5 | 6 | .. autofunction:: relationship 7 | 8 | .. autofunction:: backref 9 | 10 | .. autofunction:: dynamic_loader 11 | 12 | .. autofunction:: foreign 13 | 14 | .. autofunction:: remote 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /doc/build/orm/relationships.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: sqlalchemy.orm 2 | 3 | .. _relationship_config_toplevel: 4 | 5 | Relationship Configuration 6 | ========================== 7 | 8 | This section describes the :func:`relationship` function and in depth discussion 9 | of its usage. For an introduction to relationships, start with 10 | :ref:`tutorial_orm_related_objects` in the :ref:`unified_tutorial`. 11 | 12 | .. toctree:: 13 | :maxdepth: 3 14 | 15 | basic_relationships 16 | self_referential 17 | join_conditions 18 | large_collections 19 | collection_api 20 | relationship_persistence 21 | backref 22 | relationship_api 23 | 24 | -------------------------------------------------------------------------------- /doc/build/orm/scalar_mapping.rst: -------------------------------------------------------------------------------- 1 | =============================== 2 | Mapping SQL Expressions 3 | =============================== 4 | 5 | This page has been merged into the 6 | :ref:`mapper_config_toplevel` index. 7 | 8 | 9 | .. toctree:: 10 | :hidden: 11 | 12 | mapping_columns 13 | 14 | -------------------------------------------------------------------------------- /doc/build/orm/session.rst: -------------------------------------------------------------------------------- 1 | .. _session_toplevel: 2 | 3 | ================= 4 | Using the Session 5 | ================= 6 | 7 | .. module:: sqlalchemy.orm.session 8 | 9 | The declarative base and ORM mapping functions described at 10 | :ref:`mapper_config_toplevel` are the primary configurational interface for the 11 | ORM. Once mappings are configured, the primary usage interface for 12 | persistence operations is the 13 | :class:`.Session`. 14 | 15 | .. toctree:: 16 | :maxdepth: 3 17 | 18 | session_basics 19 | session_state_management 20 | cascades 21 | session_transaction 22 | persistence_techniques 23 | contextual 24 | session_events 25 | session_api 26 | 27 | -------------------------------------------------------------------------------- /doc/build/orm/session_api.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: sqlalchemy.orm 2 | 3 | Session API 4 | =========== 5 | 6 | Session and sessionmaker() 7 | -------------------------- 8 | 9 | .. autoclass:: sessionmaker 10 | :members: 11 | :inherited-members: 12 | 13 | .. autoclass:: ORMExecuteState 14 | :members: 15 | 16 | .. autoclass:: Session 17 | :members: 18 | :inherited-members: 19 | 20 | .. autoclass:: SessionTransaction 21 | :members: 22 | 23 | .. autoclass:: SessionTransactionOrigin 24 | :members: 25 | 26 | Session Utilities 27 | ----------------- 28 | 29 | .. autofunction:: close_all_sessions 30 | 31 | .. autofunction:: make_transient 32 | 33 | .. autofunction:: make_transient_to_detached 34 | 35 | .. autofunction:: object_session 36 | 37 | .. autofunction:: sqlalchemy.orm.util.was_deleted 38 | 39 | Attribute and State Management Utilities 40 | ---------------------------------------- 41 | 42 | These functions are provided by the SQLAlchemy attribute 43 | instrumentation API to provide a detailed interface for dealing 44 | with instances, attribute values, and history. Some of them 45 | are useful when constructing event listener functions, such as 46 | those described in :doc:`/orm/events`. 47 | 48 | .. currentmodule:: sqlalchemy.orm.util 49 | 50 | .. autofunction:: object_state 51 | 52 | .. currentmodule:: sqlalchemy.orm.attributes 53 | 54 | .. autofunction:: del_attribute 55 | 56 | .. autofunction:: get_attribute 57 | 58 | .. autofunction:: get_history 59 | 60 | .. autofunction:: init_collection 61 | 62 | .. autofunction:: flag_modified 63 | 64 | .. autofunction:: flag_dirty 65 | 66 | .. function:: instance_state 67 | 68 | Return the :class:`.InstanceState` for a given 69 | mapped object. 70 | 71 | This function is the internal version 72 | of :func:`.object_state`. The 73 | :func:`.object_state` and/or the 74 | :func:`_sa.inspect` function is preferred here 75 | as they each emit an informative exception 76 | if the given object is not mapped. 77 | 78 | .. autofunction:: sqlalchemy.orm.instrumentation.is_instrumented 79 | 80 | .. autofunction:: set_attribute 81 | 82 | .. autofunction:: set_committed_value 83 | 84 | .. autoclass:: History 85 | :members: 86 | 87 | -------------------------------------------------------------------------------- /doc/build/orm/space_invaders.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/doc/build/orm/space_invaders.jpg -------------------------------------------------------------------------------- /doc/build/orm/tutorial.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | ========================== 4 | Object Relational Tutorial 5 | ========================== 6 | 7 | .. admonition:: We've Moved! 8 | 9 | This page is the previous home of the SQLAlchemy 1.x Tutorial. As of 2.0, 10 | SQLAlchemy presents a revised way of working and an all new tutorial that 11 | presents Core and ORM in an integrated fashion using all the latest usage 12 | patterns. See :ref:`unified_tutorial`. 13 | -------------------------------------------------------------------------------- /doc/build/requirements.txt: -------------------------------------------------------------------------------- 1 | git+https://github.com/sqlalchemyorg/changelog.git#egg=changelog 2 | git+https://github.com/sqlalchemyorg/sphinx-paramlinks.git#egg=sphinx-paramlinks 3 | git+https://github.com/sqlalchemyorg/zzzeeksphinx.git#egg=zzzeeksphinx 4 | sphinx-copybutton==0.5.1 5 | sphinx-autobuild 6 | typing-extensions # for autodoc to be able to import source files 7 | greenlet # for autodoc to be able to import sqlalchemy source files 8 | -------------------------------------------------------------------------------- /doc/build/sqla_arch_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/doc/build/sqla_arch_small.png -------------------------------------------------------------------------------- /doc/build/texinputs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx LaTeX output 2 | 3 | ALLDOCS = $(basename $(wildcard *.tex)) 4 | ALLPDF = $(addsuffix .pdf,$(ALLDOCS)) 5 | ALLDVI = $(addsuffix .dvi,$(ALLDOCS)) 6 | 7 | # Prefix for archive names 8 | ARCHIVEPRREFIX = 9 | # Additional LaTeX options 10 | LATEXOPTS = -interaction=nonstopmode 11 | 12 | all: $(ALLPDF) 13 | all-pdf: $(ALLPDF) 14 | all-dvi: $(ALLDVI) 15 | all-ps: all-dvi 16 | for f in *.dvi; do dvips $$f; done 17 | all-pdf-ja: $(wildcard *.tex) 18 | ebb $(wildcard *.pdf *.png *.gif *.jpeg) 19 | platex -kanji=utf8 $(LATEXOPTS) '$<' 20 | platex -kanji=utf8 $(LATEXOPTS) '$<' 21 | platex -kanji=utf8 $(LATEXOPTS) '$<' 22 | -mendex -U -f -d '$(basename $<).dic' -s python.ist '$(basename $<).idx' 23 | platex -kanji=utf8 $(LATEXOPTS) '$<' 24 | platex -kanji=utf8 $(LATEXOPTS) '$<' 25 | dvipdfmx '$(basename $<).dvi' 26 | 27 | zip: all-$(FMT) 28 | mkdir $(ARCHIVEPREFIX)docs-$(FMT) 29 | cp $(ALLPDF) $(ARCHIVEPREFIX)docs-$(FMT) 30 | zip -q -r -9 $(ARCHIVEPREFIX)docs-$(FMT).zip $(ARCHIVEPREFIX)docs-$(FMT) 31 | rm -r $(ARCHIVEPREFIX)docs-$(FMT) 32 | 33 | tar: all-$(FMT) 34 | mkdir $(ARCHIVEPREFIX)docs-$(FMT) 35 | cp $(ALLPDF) $(ARCHIVEPREFIX)docs-$(FMT) 36 | tar cf $(ARCHIVEPREFIX)docs-$(FMT).tar $(ARCHIVEPREFIX)docs-$(FMT) 37 | rm -r $(ARCHIVEPREFIX)docs-$(FMT) 38 | 39 | bz2: tar 40 | bzip2 -9 -k $(ARCHIVEPREFIX)docs-$(FMT).tar 41 | 42 | # The number of LaTeX runs is quite conservative, but I don't expect it 43 | # to get run often, so the little extra time won't hurt. 44 | %.dvi: %.tex 45 | -latex $(LATEXOPTS) '$<' 46 | -latex $(LATEXOPTS) '$<' 47 | -latex $(LATEXOPTS) '$<' 48 | -makeindex -s python.ist '$(basename $<).idx' 49 | -latex $(LATEXOPTS) '$<' 50 | -latex $(LATEXOPTS) '$<' 51 | 52 | %.pdf: %.tex 53 | -pdflatex $(LATEXOPTS) '$<' 54 | -pdflatex $(LATEXOPTS) '$<' 55 | -pdflatex $(LATEXOPTS) '$<' 56 | -makeindex -s python.ist '$(basename $<).idx' 57 | -pdflatex $(LATEXOPTS) '$<' 58 | -pdflatex $(LATEXOPTS) '$<' 59 | 60 | clean: 61 | rm -f *.dvi *.log *.ind *.aux *.toc *.syn *.idx *.out *.ilg *.pla 62 | 63 | .PHONY: all all-pdf all-dvi all-ps clean 64 | 65 | -------------------------------------------------------------------------------- /doc/build/tutorial/further_reading.rst: -------------------------------------------------------------------------------- 1 | .. |prev| replace:: :doc:`orm_related_objects` 2 | 3 | .. |tutorial_title| replace:: SQLAlchemy 1.4 / 2.0 Tutorial 4 | 5 | .. topic:: |tutorial_title| 6 | 7 | This page is part of the :doc:`index`. 8 | 9 | Previous: |prev| 10 | 11 | 12 | .. _tutorial_further_reading: 13 | 14 | Further Reading 15 | =============== 16 | 17 | The sections below are the major top-level sections that discuss the concepts 18 | in this tutorial in much more detail, as well as describe many more features 19 | of each subsystem. 20 | 21 | Core Essential Reference 22 | 23 | * :ref:`connections_toplevel` 24 | 25 | * :ref:`schema_toplevel` 26 | 27 | * :ref:`expression_api_toplevel` 28 | 29 | * :ref:`types_toplevel` 30 | 31 | ORM Essential Reference 32 | 33 | * :ref:`mapper_config_toplevel` 34 | 35 | * :ref:`relationship_config_toplevel` 36 | 37 | * :ref:`session_toplevel` 38 | 39 | * :doc:`../orm/queryguide/index` 40 | -------------------------------------------------------------------------------- /doc/build/tutorial/tutorial_nav_include.rst: -------------------------------------------------------------------------------- 1 | .. note *_include.rst is a naming convention in conf.py 2 | 3 | .. |tutorial_title| replace:: SQLAlchemy 1.4 / 2.0 Tutorial 4 | 5 | .. topic:: |tutorial_title| 6 | 7 | This page is part of the :doc:`index`. 8 | 9 | Previous: |prev| | Next: |next| 10 | 11 | .. footer_topic:: |tutorial_title| 12 | 13 | Next Tutorial Section: |next| 14 | 15 | -------------------------------------------------------------------------------- /examples/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/examples/__init__.py -------------------------------------------------------------------------------- /examples/adjacency_list/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | An example of a dictionary-of-dictionaries structure mapped using 3 | an adjacency list model. 4 | 5 | E.g.:: 6 | 7 | node = TreeNode("rootnode") 8 | node.append("node1") 9 | node.append("node3") 10 | session.add(node) 11 | session.commit() 12 | 13 | dump_tree(node) 14 | 15 | .. autosource:: 16 | 17 | """ 18 | -------------------------------------------------------------------------------- /examples/association/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Examples illustrating the usage of the "association object" pattern, 3 | where an intermediary class mediates the relationship between two 4 | classes that are associated in a many-to-many pattern. 5 | 6 | .. autosource:: 7 | 8 | """ 9 | -------------------------------------------------------------------------------- /examples/asyncio/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Examples illustrating the asyncio engine feature of SQLAlchemy. 3 | 4 | .. autosource:: 5 | 6 | """ 7 | -------------------------------------------------------------------------------- /examples/custom_attributes/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Examples illustrating modifications to SQLAlchemy's attribute management 3 | system. 4 | 5 | .. autosource:: 6 | 7 | """ 8 | -------------------------------------------------------------------------------- /examples/dogpile_caching/fixture_data.py: -------------------------------------------------------------------------------- 1 | """Installs some sample data. Here we have a handful of postal codes for 2 | a few US/Canadian cities. Then, 100 Person records are installed, each 3 | with a randomly selected postal code. 4 | 5 | """ 6 | 7 | import random 8 | 9 | from .environment import Base 10 | from .environment import Session 11 | from .model import Address 12 | from .model import City 13 | from .model import Country 14 | from .model import Person 15 | from .model import PostalCode 16 | 17 | 18 | def install(): 19 | Base.metadata.create_all(Session().bind) 20 | 21 | data = [ 22 | ("Chicago", "United States", ("60601", "60602", "60603", "60604")), 23 | ("Montreal", "Canada", ("H2S 3K9", "H2B 1V4", "H7G 2T8")), 24 | ("Edmonton", "Canada", ("T5J 1R9", "T5J 1Z4", "T5H 1P6")), 25 | ( 26 | "New York", 27 | "United States", 28 | ("10001", "10002", "10003", "10004", "10005", "10006"), 29 | ), 30 | ( 31 | "San Francisco", 32 | "United States", 33 | ("94102", "94103", "94104", "94105", "94107", "94108"), 34 | ), 35 | ] 36 | 37 | countries = {} 38 | all_post_codes = [] 39 | for city, country, postcodes in data: 40 | try: 41 | country = countries[country] 42 | except KeyError: 43 | countries[country] = country = Country(country) 44 | 45 | city = City(city, country) 46 | pc = [PostalCode(code, city) for code in postcodes] 47 | Session.add_all(pc) 48 | all_post_codes.extend(pc) 49 | 50 | for i in range(1, 51): 51 | person = Person( 52 | "person %.2d" % i, 53 | Address( 54 | street="street %.2d" % i, 55 | postal_code=all_post_codes[ 56 | random.randint(0, len(all_post_codes) - 1) 57 | ], 58 | ), 59 | ) 60 | Session.add(person) 61 | 62 | Session.commit() 63 | 64 | # start the demo fresh 65 | Session.remove() 66 | -------------------------------------------------------------------------------- /examples/dogpile_caching/relationship_caching.py: -------------------------------------------------------------------------------- 1 | """Illustrates how to add cache options on 2 | relationship endpoints, so that lazyloads load from cache. 3 | 4 | Load a set of Person and Address objects, specifying that 5 | related PostalCode, City, Country objects should be pulled from long 6 | term cache. 7 | 8 | """ 9 | 10 | import os 11 | 12 | from sqlalchemy import select 13 | from sqlalchemy.orm import joinedload 14 | from .environment import root 15 | from .environment import Session 16 | from .model import cache_address_bits 17 | from .model import Person 18 | 19 | 20 | for p in Session.scalars( 21 | select(Person).options(joinedload(Person.addresses), cache_address_bits) 22 | ).unique(): 23 | print(p.format_full()) 24 | 25 | 26 | print( 27 | "\n\nIf this was the first run of relationship_caching.py, " 28 | "SQL was likely emitted to " 29 | "load postal codes, cities, countries.\n" 30 | "If run a second time, assuming the cache is still valid, " 31 | "only a single SQL statement will run - all " 32 | "related data is pulled from cache.\n" 33 | "To clear the cache, delete the file %r. \n" 34 | "This will cause a re-load of cities, postal codes and countries on " 35 | "the next run.\n" % os.path.join(root, "cache.dbm") 36 | ) 37 | -------------------------------------------------------------------------------- /examples/dynamic_dict/__init__.py: -------------------------------------------------------------------------------- 1 | """Illustrates how to place a dictionary-like facade on top of a 2 | "dynamic" relation, so that dictionary operations (assuming simple 3 | string keys) can operate upon a large collection without loading the 4 | full collection at once. 5 | 6 | .. autosource:: 7 | 8 | """ 9 | -------------------------------------------------------------------------------- /examples/extending_query/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Recipes which illustrate augmentation of ORM SELECT behavior as used by 3 | :meth:`_orm.Session.execute` with :term:`2.0 style` use of 4 | :func:`_sql.select`, as well as the :term:`1.x style` :class:`_orm.Query` 5 | object. 6 | 7 | Examples include demonstrations of the :func:`_orm.with_loader_criteria` 8 | option as well as the :meth:`_orm.SessionEvents.do_orm_execute` hook. 9 | 10 | As of SQLAlchemy 1.4, the :class:`_orm.Query` construct is unified 11 | with the :class:`_expression.Select` construct, so that these two objects 12 | are mostly the same. 13 | 14 | 15 | .. autosource:: 16 | 17 | """ # noqa 18 | -------------------------------------------------------------------------------- /examples/generic_associations/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Illustrates various methods of associating multiple types of 3 | parents with a particular child object. 4 | 5 | The examples all use the declarative extension along with 6 | declarative mixins. Each one presents the identical use 7 | case at the end - two classes, ``Customer`` and ``Supplier``, both 8 | subclassing the ``HasAddresses`` mixin, which ensures that the 9 | parent class is provided with an ``addresses`` collection 10 | which contains ``Address`` objects. 11 | 12 | The :viewsource:`.discriminator_on_association` and :viewsource:`.generic_fk` scripts 13 | are modernized versions of recipes presented in the 2007 blog post 14 | `Polymorphic Associations with SQLAlchemy `_. 15 | 16 | .. autosource:: 17 | 18 | """ # noqa 19 | -------------------------------------------------------------------------------- /examples/graphs/__init__.py: -------------------------------------------------------------------------------- 1 | """An example of persistence for a directed graph structure. The 2 | graph is stored as a collection of edges, each referencing both a 3 | "lower" and an "upper" node in a table of nodes. Basic persistence 4 | and querying for lower- and upper- neighbors are illustrated:: 5 | 6 | n2 = Node(2) 7 | n5 = Node(5) 8 | n2.add_neighbor(n5) 9 | print(n2.higher_neighbors()) 10 | 11 | .. autosource:: 12 | 13 | """ 14 | -------------------------------------------------------------------------------- /examples/graphs/directed_graph.py: -------------------------------------------------------------------------------- 1 | """a directed graph example.""" 2 | 3 | from sqlalchemy import Column 4 | from sqlalchemy import create_engine 5 | from sqlalchemy import ForeignKey 6 | from sqlalchemy import Integer 7 | from sqlalchemy.ext.declarative import declarative_base 8 | from sqlalchemy.orm import relationship 9 | from sqlalchemy.orm import sessionmaker 10 | 11 | 12 | Base = declarative_base() 13 | 14 | 15 | class Node(Base): 16 | __tablename__ = "node" 17 | 18 | node_id = Column(Integer, primary_key=True) 19 | 20 | def higher_neighbors(self): 21 | return [x.higher_node for x in self.lower_edges] 22 | 23 | def lower_neighbors(self): 24 | return [x.lower_node for x in self.higher_edges] 25 | 26 | 27 | class Edge(Base): 28 | __tablename__ = "edge" 29 | 30 | lower_id = Column(Integer, ForeignKey("node.node_id"), primary_key=True) 31 | 32 | higher_id = Column(Integer, ForeignKey("node.node_id"), primary_key=True) 33 | 34 | lower_node = relationship( 35 | Node, primaryjoin=lower_id == Node.node_id, backref="lower_edges" 36 | ) 37 | 38 | higher_node = relationship( 39 | Node, primaryjoin=higher_id == Node.node_id, backref="higher_edges" 40 | ) 41 | 42 | def __init__(self, n1, n2): 43 | self.lower_node = n1 44 | self.higher_node = n2 45 | 46 | 47 | engine = create_engine("sqlite://", echo=True) 48 | Base.metadata.create_all(engine) 49 | 50 | session = sessionmaker(engine)() 51 | 52 | # create a directed graph like this: 53 | # n1 -> n2 -> n1 54 | # -> n5 55 | # -> n7 56 | # -> n3 -> n6 57 | 58 | n1 = Node() 59 | n2 = Node() 60 | n3 = Node() 61 | n4 = Node() 62 | n5 = Node() 63 | n6 = Node() 64 | n7 = Node() 65 | 66 | Edge(n1, n2) 67 | Edge(n1, n3) 68 | Edge(n2, n1) 69 | Edge(n2, n5) 70 | Edge(n2, n7) 71 | Edge(n3, n6) 72 | 73 | session.add_all([n1, n2, n3, n4, n5, n6, n7]) 74 | session.commit() 75 | 76 | assert [x for x in n3.higher_neighbors()] == [n6] 77 | assert [x for x in n3.lower_neighbors()] == [n1] 78 | assert [x for x in n2.lower_neighbors()] == [n1] 79 | assert [x for x in n2.higher_neighbors()] == [n1, n5, n7] 80 | -------------------------------------------------------------------------------- /examples/inheritance/__init__.py: -------------------------------------------------------------------------------- 1 | """Working examples of single-table, joined-table, and concrete-table 2 | inheritance as described in :ref:`inheritance_toplevel`. 3 | 4 | .. autosource:: 5 | 6 | """ 7 | -------------------------------------------------------------------------------- /examples/materialized_paths/__init__.py: -------------------------------------------------------------------------------- 1 | """Illustrates the "materialized paths" pattern for hierarchical data using the 2 | SQLAlchemy ORM. 3 | 4 | .. autosource:: 5 | 6 | """ 7 | -------------------------------------------------------------------------------- /examples/nested_sets/__init__.py: -------------------------------------------------------------------------------- 1 | """Illustrates a rudimentary way to implement the "nested sets" 2 | pattern for hierarchical data using the SQLAlchemy ORM. 3 | 4 | .. autosource:: 5 | 6 | """ 7 | -------------------------------------------------------------------------------- /examples/performance/__main__.py: -------------------------------------------------------------------------------- 1 | """Allows the examples/performance package to be run as a script.""" 2 | 3 | from . import Profiler 4 | 5 | 6 | if __name__ == "__main__": 7 | Profiler.main() 8 | -------------------------------------------------------------------------------- /examples/performance/bulk_updates.py: -------------------------------------------------------------------------------- 1 | """This series of tests will illustrate different ways to UPDATE a large number 2 | of rows in bulk (under construction! there's just one test at the moment) 3 | 4 | 5 | """ 6 | 7 | from sqlalchemy import Column 8 | from sqlalchemy import create_engine 9 | from sqlalchemy import Identity 10 | from sqlalchemy import Integer 11 | from sqlalchemy import String 12 | from sqlalchemy.ext.declarative import declarative_base 13 | from sqlalchemy.orm import Session 14 | from . import Profiler 15 | 16 | 17 | Base = declarative_base() 18 | engine = None 19 | 20 | 21 | class Customer(Base): 22 | __tablename__ = "customer" 23 | id = Column(Integer, Identity(), primary_key=True) 24 | name = Column(String(255)) 25 | description = Column(String(255)) 26 | 27 | 28 | Profiler.init("bulk_updates", num=100000) 29 | 30 | 31 | @Profiler.setup 32 | def setup_database(dburl, echo, num): 33 | global engine 34 | engine = create_engine(dburl, echo=echo) 35 | Base.metadata.drop_all(engine) 36 | Base.metadata.create_all(engine) 37 | 38 | s = Session(engine) 39 | for chunk in range(0, num, 10000): 40 | s.bulk_insert_mappings( 41 | Customer, 42 | [ 43 | { 44 | "name": "customer name %d" % i, 45 | "description": "customer description %d" % i, 46 | } 47 | for i in range(chunk, chunk + 10000) 48 | ], 49 | ) 50 | s.commit() 51 | 52 | 53 | @Profiler.profile 54 | def test_orm_flush(n): 55 | """UPDATE statements via the ORM flush process.""" 56 | session = Session(bind=engine) 57 | for chunk in range(0, n, 1000): 58 | customers = ( 59 | session.query(Customer) 60 | .filter(Customer.id.between(chunk, chunk + 1000)) 61 | .all() 62 | ) 63 | for customer in customers: 64 | customer.description += "updated" 65 | session.flush() 66 | session.commit() 67 | -------------------------------------------------------------------------------- /examples/sharding/__init__.py: -------------------------------------------------------------------------------- 1 | """A basic example of using the SQLAlchemy Sharding API. 2 | Sharding refers to horizontally scaling data across multiple 3 | databases. 4 | 5 | The basic components of a "sharded" mapping are: 6 | 7 | * multiple :class:`_engine.Engine` instances, each assigned a "shard id". 8 | These :class:`_engine.Engine` instances may refer to different databases, 9 | or different schemas / accounts within the same database, or they can 10 | even be differentiated only by options that will cause them to access 11 | different schemas or tables when used. 12 | 13 | * a function which can return a single shard id, given an instance 14 | to be saved; this is called "shard_chooser" 15 | 16 | * a function which can return a list of shard ids which apply to a particular 17 | instance identifier; this is called "id_chooser".If it returns all shard ids, 18 | all shards will be searched. 19 | 20 | * a function which can return a list of shard ids to try, given a particular 21 | Query ("query_chooser"). If it returns all shard ids, all shards will be 22 | queried and the results joined together. 23 | 24 | In these examples, different kinds of shards are used against the same basic 25 | example which accommodates weather data on a per-continent basis. We provide 26 | example shard_chooser, id_chooser and query_chooser functions. The 27 | query_chooser illustrates inspection of the SQL expression element in order to 28 | attempt to determine a single shard being requested. 29 | 30 | The construction of generic sharding routines is an ambitious approach 31 | to the issue of organizing instances among multiple databases. For a 32 | more plain-spoken alternative, the "distinct entity" approach 33 | is a simple method of assigning objects to different tables (and potentially 34 | database nodes) in an explicit way - described on the wiki at 35 | `EntityName `_. 36 | 37 | .. autosource:: 38 | 39 | """ 40 | -------------------------------------------------------------------------------- /examples/space_invaders/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | A Space Invaders game using SQLite as the state machine. 3 | 4 | Originally developed in 2012. Adapted to work in Python 3. 5 | 6 | Runs in a textual console using ASCII art. 7 | 8 | 9 | .. image:: space_invaders.jpg 10 | 11 | 12 | To run:: 13 | 14 | $ python -m examples.space_invaders.space_invaders 15 | 16 | While it runs, watch the SQL output in the log:: 17 | 18 | $ tail -f space_invaders.log 19 | 20 | enjoy! 21 | 22 | .. autosource:: 23 | 24 | """ 25 | -------------------------------------------------------------------------------- /examples/syntax_extensions/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | A detailed example of extending the :class:`.Select` construct to include 3 | a new non-SQL standard clause ``QUALIFY``. 4 | 5 | This example illustrates both the :ref:`sqlalchemy.ext.compiler_toplevel` 6 | as well as an extension known as :class:`.SyntaxExtension`. 7 | 8 | .. autosource:: 9 | 10 | """ 11 | -------------------------------------------------------------------------------- /examples/versioned_rows/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Several examples that illustrate the technique of intercepting changes 3 | that would be first interpreted as an UPDATE on a row, and instead turning 4 | it into an INSERT of a new row, leaving the previous row intact as 5 | a historical version. 6 | 7 | Compare to the :ref:`examples_versioned_history` example which writes a 8 | history row to a separate history table. 9 | 10 | .. autosource:: 11 | 12 | """ 13 | -------------------------------------------------------------------------------- /examples/vertical/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Illustrates "vertical table" mappings. 3 | 4 | A "vertical table" refers to a technique where individual attributes 5 | of an object are stored as distinct rows in a table. The "vertical 6 | table" technique is used to persist objects which can have a varied 7 | set of attributes, at the expense of simple query control and brevity. 8 | It is commonly found in content/document management systems in order 9 | to represent user-created structures flexibly. 10 | 11 | Two variants on the approach are given. In the second, each row 12 | references a "datatype" which contains information about the type of 13 | information stored in the attribute, such as integer, string, or date. 14 | 15 | 16 | Example:: 17 | 18 | shrew = Animal("shrew") 19 | shrew["cuteness"] = 5 20 | shrew["weasel-like"] = False 21 | shrew["poisonous"] = True 22 | 23 | session.add(shrew) 24 | session.flush() 25 | 26 | q = session.query(Animal).filter( 27 | Animal.facts.any( 28 | and_(AnimalFact.key == "weasel-like", AnimalFact.value == True) 29 | ) 30 | ) 31 | print("weasel-like animals", q.all()) 32 | 33 | .. autosource:: 34 | 35 | """ 36 | -------------------------------------------------------------------------------- /lib/sqlalchemy/connectors/__init__.py: -------------------------------------------------------------------------------- 1 | # connectors/__init__.py 2 | # Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 3 | # 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: https://www.opensource.org/licenses/mit-license.php 7 | 8 | 9 | from ..engine.interfaces import Dialect 10 | 11 | 12 | class Connector(Dialect): 13 | """Base class for dialect mixins, for DBAPIs that work 14 | across entirely different database backends. 15 | 16 | Currently the only such mixin is pyodbc. 17 | 18 | """ 19 | -------------------------------------------------------------------------------- /lib/sqlalchemy/dialects/__init__.py: -------------------------------------------------------------------------------- 1 | # dialects/__init__.py 2 | # Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 3 | # 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: https://www.opensource.org/licenses/mit-license.php 7 | 8 | from __future__ import annotations 9 | 10 | from typing import Any 11 | from typing import Callable 12 | from typing import Optional 13 | from typing import Type 14 | from typing import TYPE_CHECKING 15 | 16 | from .. import util 17 | 18 | if TYPE_CHECKING: 19 | from ..engine.interfaces import Dialect 20 | 21 | __all__ = ("mssql", "mysql", "oracle", "postgresql", "sqlite") 22 | 23 | 24 | def _auto_fn(name: str) -> Optional[Callable[[], Type[Dialect]]]: 25 | """default dialect importer. 26 | 27 | plugs into the :class:`.PluginLoader` 28 | as a first-hit system. 29 | 30 | """ 31 | if "." in name: 32 | dialect, driver = name.split(".") 33 | else: 34 | dialect = name 35 | driver = "base" 36 | 37 | try: 38 | if dialect == "mariadb": 39 | # it's "OK" for us to hardcode here since _auto_fn is already 40 | # hardcoded. if mysql / mariadb etc were third party dialects 41 | # they would just publish all the entrypoints, which would actually 42 | # look much nicer. 43 | module: Any = __import__( 44 | "sqlalchemy.dialects.mysql.mariadb" 45 | ).dialects.mysql.mariadb 46 | return module.loader(driver) # type: ignore 47 | else: 48 | module = __import__("sqlalchemy.dialects.%s" % (dialect,)).dialects 49 | module = getattr(module, dialect) 50 | except ImportError: 51 | return None 52 | 53 | if hasattr(module, driver): 54 | module = getattr(module, driver) 55 | return lambda: module.dialect 56 | else: 57 | return None 58 | 59 | 60 | registry = util.PluginLoader("sqlalchemy.dialects", auto_fn=_auto_fn) 61 | 62 | plugins = util.PluginLoader("sqlalchemy.plugins") 63 | -------------------------------------------------------------------------------- /lib/sqlalchemy/dialects/_typing.py: -------------------------------------------------------------------------------- 1 | # dialects/_typing.py 2 | # Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 3 | # 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: https://www.opensource.org/licenses/mit-license.php 7 | from __future__ import annotations 8 | 9 | from typing import Any 10 | from typing import Iterable 11 | from typing import Mapping 12 | from typing import Optional 13 | from typing import Union 14 | 15 | from ..sql import roles 16 | from ..sql.base import ColumnCollection 17 | from ..sql.schema import Column 18 | from ..sql.schema import ColumnCollectionConstraint 19 | from ..sql.schema import Index 20 | 21 | 22 | _OnConflictConstraintT = Union[str, ColumnCollectionConstraint, Index, None] 23 | _OnConflictIndexElementsT = Optional[ 24 | Iterable[Union[Column[Any], str, roles.DDLConstraintColumnRole]] 25 | ] 26 | _OnConflictIndexWhereT = Optional[roles.WhereHavingRole] 27 | _OnConflictSetT = Optional[ 28 | Union[Mapping[Any, Any], ColumnCollection[Any, Any]] 29 | ] 30 | _OnConflictWhereT = Optional[roles.WhereHavingRole] 31 | -------------------------------------------------------------------------------- /lib/sqlalchemy/dialects/oracle/__init__.py: -------------------------------------------------------------------------------- 1 | # dialects/oracle/__init__.py 2 | # Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 3 | # 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: https://www.opensource.org/licenses/mit-license.php 7 | # mypy: ignore-errors 8 | from types import ModuleType 9 | 10 | from . import base # noqa 11 | from . import cx_oracle # noqa 12 | from . import oracledb # noqa 13 | from .base import BFILE 14 | from .base import BINARY_DOUBLE 15 | from .base import BINARY_FLOAT 16 | from .base import BLOB 17 | from .base import CHAR 18 | from .base import CLOB 19 | from .base import DATE 20 | from .base import DOUBLE_PRECISION 21 | from .base import FLOAT 22 | from .base import INTERVAL 23 | from .base import LONG 24 | from .base import NCHAR 25 | from .base import NCLOB 26 | from .base import NUMBER 27 | from .base import NVARCHAR 28 | from .base import NVARCHAR2 29 | from .base import RAW 30 | from .base import REAL 31 | from .base import ROWID 32 | from .base import TIMESTAMP 33 | from .base import VARCHAR 34 | from .base import VARCHAR2 35 | from .base import VECTOR 36 | from .base import VectorIndexConfig 37 | from .base import VectorIndexType 38 | from .vector import VectorDistanceType 39 | from .vector import VectorStorageFormat 40 | 41 | # Alias oracledb also as oracledb_async 42 | oracledb_async = type( 43 | "oracledb_async", (ModuleType,), {"dialect": oracledb.dialect_async} 44 | ) 45 | 46 | base.dialect = dialect = cx_oracle.dialect 47 | 48 | __all__ = ( 49 | "VARCHAR", 50 | "NVARCHAR", 51 | "CHAR", 52 | "NCHAR", 53 | "DATE", 54 | "NUMBER", 55 | "BLOB", 56 | "BFILE", 57 | "CLOB", 58 | "NCLOB", 59 | "TIMESTAMP", 60 | "RAW", 61 | "FLOAT", 62 | "DOUBLE_PRECISION", 63 | "BINARY_DOUBLE", 64 | "BINARY_FLOAT", 65 | "LONG", 66 | "dialect", 67 | "INTERVAL", 68 | "VARCHAR2", 69 | "NVARCHAR2", 70 | "ROWID", 71 | "REAL", 72 | "VECTOR", 73 | "VectorDistanceType", 74 | "VectorIndexType", 75 | "VectorIndexConfig", 76 | "VectorStorageFormat", 77 | ) 78 | -------------------------------------------------------------------------------- /lib/sqlalchemy/dialects/postgresql/psycopg2cffi.py: -------------------------------------------------------------------------------- 1 | # dialects/postgresql/psycopg2cffi.py 2 | # Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 3 | # 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: https://www.opensource.org/licenses/mit-license.php 7 | # mypy: ignore-errors 8 | 9 | r""" 10 | .. dialect:: postgresql+psycopg2cffi 11 | :name: psycopg2cffi 12 | :dbapi: psycopg2cffi 13 | :connectstring: postgresql+psycopg2cffi://user:password@host:port/dbname[?key=value&key=value...] 14 | :url: https://pypi.org/project/psycopg2cffi/ 15 | 16 | ``psycopg2cffi`` is an adaptation of ``psycopg2``, using CFFI for the C 17 | layer. This makes it suitable for use in e.g. PyPy. Documentation 18 | is as per ``psycopg2``. 19 | 20 | .. seealso:: 21 | 22 | :mod:`sqlalchemy.dialects.postgresql.psycopg2` 23 | 24 | """ # noqa 25 | from .psycopg2 import PGDialect_psycopg2 26 | from ... import util 27 | 28 | 29 | class PGDialect_psycopg2cffi(PGDialect_psycopg2): 30 | driver = "psycopg2cffi" 31 | supports_unicode_statements = True 32 | supports_statement_cache = True 33 | 34 | # psycopg2cffi's first release is 2.5.0, but reports 35 | # __version__ as 2.4.4. Subsequent releases seem to have 36 | # fixed this. 37 | 38 | FEATURE_VERSION_MAP = dict( 39 | native_json=(2, 4, 4), 40 | native_jsonb=(2, 7, 1), 41 | sane_multi_rowcount=(2, 4, 4), 42 | array_oid=(2, 4, 4), 43 | hstore_adapter=(2, 4, 4), 44 | ) 45 | 46 | @classmethod 47 | def import_dbapi(cls): 48 | return __import__("psycopg2cffi") 49 | 50 | @util.memoized_property 51 | def _psycopg2_extensions(cls): 52 | root = __import__("psycopg2cffi", fromlist=["extensions"]) 53 | return root.extensions 54 | 55 | @util.memoized_property 56 | def _psycopg2_extras(cls): 57 | root = __import__("psycopg2cffi", fromlist=["extras"]) 58 | return root.extras 59 | 60 | 61 | dialect = PGDialect_psycopg2cffi 62 | -------------------------------------------------------------------------------- /lib/sqlalchemy/dialects/sqlite/__init__.py: -------------------------------------------------------------------------------- 1 | # dialects/sqlite/__init__.py 2 | # Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 3 | # 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: https://www.opensource.org/licenses/mit-license.php 7 | # mypy: ignore-errors 8 | 9 | 10 | from . import aiosqlite # noqa 11 | from . import base # noqa 12 | from . import pysqlcipher # noqa 13 | from . import pysqlite # noqa 14 | from .base import BLOB 15 | from .base import BOOLEAN 16 | from .base import CHAR 17 | from .base import DATE 18 | from .base import DATETIME 19 | from .base import DECIMAL 20 | from .base import FLOAT 21 | from .base import INTEGER 22 | from .base import JSON 23 | from .base import NUMERIC 24 | from .base import REAL 25 | from .base import SMALLINT 26 | from .base import TEXT 27 | from .base import TIME 28 | from .base import TIMESTAMP 29 | from .base import VARCHAR 30 | from .dml import Insert 31 | from .dml import insert 32 | 33 | # default dialect 34 | base.dialect = dialect = pysqlite.dialect 35 | 36 | 37 | __all__ = ( 38 | "BLOB", 39 | "BOOLEAN", 40 | "CHAR", 41 | "DATE", 42 | "DATETIME", 43 | "DECIMAL", 44 | "FLOAT", 45 | "INTEGER", 46 | "JSON", 47 | "NUMERIC", 48 | "SMALLINT", 49 | "TEXT", 50 | "TIME", 51 | "TIMESTAMP", 52 | "VARCHAR", 53 | "REAL", 54 | "Insert", 55 | "insert", 56 | "dialect", 57 | ) 58 | -------------------------------------------------------------------------------- /lib/sqlalchemy/engine/strategies.py: -------------------------------------------------------------------------------- 1 | # engine/strategies.py 2 | # Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 3 | # 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: https://www.opensource.org/licenses/mit-license.php 7 | 8 | """Deprecated mock engine strategy used by Alembic.""" 9 | 10 | from __future__ import annotations 11 | 12 | from .mock import MockConnection # noqa 13 | 14 | 15 | class MockEngineStrategy: 16 | MockConnection = MockConnection 17 | -------------------------------------------------------------------------------- /lib/sqlalchemy/event/__init__.py: -------------------------------------------------------------------------------- 1 | # event/__init__.py 2 | # Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 3 | # 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: https://www.opensource.org/licenses/mit-license.php 7 | 8 | from __future__ import annotations 9 | 10 | from .api import CANCEL as CANCEL 11 | from .api import contains as contains 12 | from .api import listen as listen 13 | from .api import listens_for as listens_for 14 | from .api import NO_RETVAL as NO_RETVAL 15 | from .api import remove as remove 16 | from .attr import _InstanceLevelDispatch as _InstanceLevelDispatch 17 | from .attr import RefCollection as RefCollection 18 | from .base import _Dispatch as _Dispatch 19 | from .base import _DispatchCommon as _DispatchCommon 20 | from .base import dispatcher as dispatcher 21 | from .base import Events as Events 22 | from .legacy import _legacy_signature as _legacy_signature 23 | from .registry import _EventKey as _EventKey 24 | from .registry import _ListenerFnType as _ListenerFnType 25 | from .registry import EventTarget as EventTarget 26 | -------------------------------------------------------------------------------- /lib/sqlalchemy/events.py: -------------------------------------------------------------------------------- 1 | # events.py 2 | # Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 3 | # 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: https://www.opensource.org/licenses/mit-license.php 7 | 8 | """Core event interfaces.""" 9 | 10 | from __future__ import annotations 11 | 12 | from .engine.events import ConnectionEvents 13 | from .engine.events import DialectEvents 14 | from .pool import PoolResetState 15 | from .pool.events import PoolEvents 16 | from .sql.base import SchemaEventTarget 17 | from .sql.events import DDLEvents 18 | -------------------------------------------------------------------------------- /lib/sqlalchemy/ext/__init__.py: -------------------------------------------------------------------------------- 1 | # ext/__init__.py 2 | # Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 3 | # 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: https://www.opensource.org/licenses/mit-license.php 7 | 8 | from .. import util as _sa_util 9 | 10 | 11 | _sa_util.preloaded.import_prefix("sqlalchemy.ext") 12 | -------------------------------------------------------------------------------- /lib/sqlalchemy/ext/asyncio/__init__.py: -------------------------------------------------------------------------------- 1 | # ext/asyncio/__init__.py 2 | # Copyright (C) 2020-2025 the SQLAlchemy authors and contributors 3 | # 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: https://www.opensource.org/licenses/mit-license.php 7 | 8 | from .engine import async_engine_from_config as async_engine_from_config 9 | from .engine import AsyncConnection as AsyncConnection 10 | from .engine import AsyncEngine as AsyncEngine 11 | from .engine import AsyncTransaction as AsyncTransaction 12 | from .engine import create_async_engine as create_async_engine 13 | from .engine import create_async_pool_from_url as create_async_pool_from_url 14 | from .result import AsyncMappingResult as AsyncMappingResult 15 | from .result import AsyncResult as AsyncResult 16 | from .result import AsyncScalarResult as AsyncScalarResult 17 | from .result import AsyncTupleResult as AsyncTupleResult 18 | from .scoping import async_scoped_session as async_scoped_session 19 | from .session import async_object_session as async_object_session 20 | from .session import async_session as async_session 21 | from .session import async_sessionmaker as async_sessionmaker 22 | from .session import AsyncAttrs as AsyncAttrs 23 | from .session import AsyncSession as AsyncSession 24 | from .session import AsyncSessionTransaction as AsyncSessionTransaction 25 | from .session import close_all_sessions as close_all_sessions 26 | from ...util import concurrency 27 | 28 | concurrency._concurrency_shim._initialize() 29 | del concurrency 30 | -------------------------------------------------------------------------------- /lib/sqlalchemy/ext/asyncio/exc.py: -------------------------------------------------------------------------------- 1 | # ext/asyncio/exc.py 2 | # Copyright (C) 2020-2025 the SQLAlchemy authors and contributors 3 | # 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: https://www.opensource.org/licenses/mit-license.php 7 | 8 | from ... import exc 9 | 10 | 11 | class AsyncMethodRequired(exc.InvalidRequestError): 12 | """an API can't be used because its result would not be 13 | compatible with async""" 14 | 15 | 16 | class AsyncContextNotStarted(exc.InvalidRequestError): 17 | """a startable context manager has not been started.""" 18 | 19 | 20 | class AsyncContextAlreadyStarted(exc.InvalidRequestError): 21 | """a startable context manager is already started.""" 22 | -------------------------------------------------------------------------------- /lib/sqlalchemy/ext/declarative/__init__.py: -------------------------------------------------------------------------------- 1 | # ext/declarative/__init__.py 2 | # Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 3 | # 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: https://www.opensource.org/licenses/mit-license.php 7 | # mypy: ignore-errors 8 | 9 | 10 | from .extensions import AbstractConcreteBase 11 | from .extensions import ConcreteBase 12 | from .extensions import DeferredReflection 13 | from ... import util 14 | from ...orm.decl_api import as_declarative as _as_declarative 15 | from ...orm.decl_api import declarative_base as _declarative_base 16 | from ...orm.decl_api import DeclarativeMeta 17 | from ...orm.decl_api import declared_attr 18 | from ...orm.decl_api import has_inherited_table as _has_inherited_table 19 | from ...orm.decl_api import synonym_for as _synonym_for 20 | 21 | 22 | @util.moved_20( 23 | "The ``declarative_base()`` function is now available as " 24 | ":func:`sqlalchemy.orm.declarative_base`." 25 | ) 26 | def declarative_base(*arg, **kw): 27 | return _declarative_base(*arg, **kw) 28 | 29 | 30 | @util.moved_20( 31 | "The ``as_declarative()`` function is now available as " 32 | ":func:`sqlalchemy.orm.as_declarative`" 33 | ) 34 | def as_declarative(*arg, **kw): 35 | return _as_declarative(*arg, **kw) 36 | 37 | 38 | @util.moved_20( 39 | "The ``has_inherited_table()`` function is now available as " 40 | ":func:`sqlalchemy.orm.has_inherited_table`." 41 | ) 42 | def has_inherited_table(*arg, **kw): 43 | return _has_inherited_table(*arg, **kw) 44 | 45 | 46 | @util.moved_20( 47 | "The ``synonym_for()`` function is now available as " 48 | ":func:`sqlalchemy.orm.synonym_for`" 49 | ) 50 | def synonym_for(*arg, **kw): 51 | return _synonym_for(*arg, **kw) 52 | 53 | 54 | __all__ = [ 55 | "declarative_base", 56 | "synonym_for", 57 | "has_inherited_table", 58 | "instrument_declarative", 59 | "declared_attr", 60 | "as_declarative", 61 | "ConcreteBase", 62 | "AbstractConcreteBase", 63 | "DeclarativeMeta", 64 | "DeferredReflection", 65 | ] 66 | -------------------------------------------------------------------------------- /lib/sqlalchemy/future/__init__.py: -------------------------------------------------------------------------------- 1 | # future/__init__.py 2 | # Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 3 | # 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: https://www.opensource.org/licenses/mit-license.php 7 | 8 | """2.0 API features. 9 | 10 | this module is legacy as 2.0 APIs are now standard. 11 | 12 | """ 13 | from .engine import Connection as Connection 14 | from .engine import create_engine as create_engine 15 | from .engine import Engine as Engine 16 | from ..sql._selectable_constructors import select as select 17 | -------------------------------------------------------------------------------- /lib/sqlalchemy/future/engine.py: -------------------------------------------------------------------------------- 1 | # future/engine.py 2 | # Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 3 | # 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: https://www.opensource.org/licenses/mit-license.php 7 | """2.0 API features. 8 | 9 | this module is legacy as 2.0 APIs are now standard. 10 | 11 | """ 12 | 13 | from ..engine import Connection as Connection # noqa: F401 14 | from ..engine import create_engine as create_engine # noqa: F401 15 | from ..engine import Engine as Engine # noqa: F401 16 | -------------------------------------------------------------------------------- /lib/sqlalchemy/pool/__init__.py: -------------------------------------------------------------------------------- 1 | # pool/__init__.py 2 | # Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 3 | # 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: https://www.opensource.org/licenses/mit-license.php 7 | 8 | 9 | """Connection pooling for DB-API connections. 10 | 11 | Provides a number of connection pool implementations for a variety of 12 | usage scenarios and thread behavior requirements imposed by the 13 | application, DB-API or database itself. 14 | 15 | Also provides a DB-API 2.0 connection proxying mechanism allowing 16 | regular DB-API connect() methods to be transparently managed by a 17 | SQLAlchemy connection pool. 18 | """ 19 | 20 | from . import events 21 | from .base import _AdhocProxiedConnection as _AdhocProxiedConnection 22 | from .base import _ConnectionFairy as _ConnectionFairy 23 | from .base import _ConnectionRecord 24 | from .base import _CreatorFnType as _CreatorFnType 25 | from .base import _CreatorWRecFnType as _CreatorWRecFnType 26 | from .base import _finalize_fairy 27 | from .base import _ResetStyleArgType as _ResetStyleArgType 28 | from .base import ConnectionPoolEntry as ConnectionPoolEntry 29 | from .base import ManagesConnection as ManagesConnection 30 | from .base import Pool as Pool 31 | from .base import PoolProxiedConnection as PoolProxiedConnection 32 | from .base import PoolResetState as PoolResetState 33 | from .base import reset_commit as reset_commit 34 | from .base import reset_none as reset_none 35 | from .base import reset_rollback as reset_rollback 36 | from .impl import AssertionPool as AssertionPool 37 | from .impl import AsyncAdaptedQueuePool as AsyncAdaptedQueuePool 38 | from .impl import NullPool as NullPool 39 | from .impl import QueuePool as QueuePool 40 | from .impl import SingletonThreadPool as SingletonThreadPool 41 | from .impl import StaticPool as StaticPool 42 | -------------------------------------------------------------------------------- /lib/sqlalchemy/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/lib/sqlalchemy/py.typed -------------------------------------------------------------------------------- /lib/sqlalchemy/sql/_orm_types.py: -------------------------------------------------------------------------------- 1 | # sql/_orm_types.py 2 | # Copyright (C) 2022-2025 the SQLAlchemy authors and contributors 3 | # 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: https://www.opensource.org/licenses/mit-license.php 7 | 8 | """ORM types that need to present specifically for **documentation only** of 9 | the Executable.execution_options() method, which includes options that 10 | are meaningful to the ORM. 11 | 12 | """ 13 | 14 | 15 | from __future__ import annotations 16 | 17 | from ..util.typing import Literal 18 | 19 | SynchronizeSessionArgument = Literal[False, "auto", "evaluate", "fetch"] 20 | DMLStrategyArgument = Literal["bulk", "raw", "orm", "auto"] 21 | -------------------------------------------------------------------------------- /lib/sqlalchemy/testing/fixtures/__init__.py: -------------------------------------------------------------------------------- 1 | # testing/fixtures/__init__.py 2 | # Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 3 | # 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: https://www.opensource.org/licenses/mit-license.php 7 | # mypy: ignore-errors 8 | from .base import FutureEngineMixin as FutureEngineMixin 9 | from .base import TestBase as TestBase 10 | from .mypy import MypyTest as MypyTest 11 | from .orm import after_test as after_test 12 | from .orm import close_all_sessions as close_all_sessions 13 | from .orm import DeclarativeMappedTest as DeclarativeMappedTest 14 | from .orm import fixture_session as fixture_session 15 | from .orm import MappedTest as MappedTest 16 | from .orm import ORMTest as ORMTest 17 | from .orm import RemoveORMEventsGlobally as RemoveORMEventsGlobally 18 | from .orm import ( 19 | stop_test_class_inside_fixtures as stop_test_class_inside_fixtures, 20 | ) 21 | from .sql import CacheKeyFixture as CacheKeyFixture 22 | from .sql import CacheKeySuite as CacheKeySuite 23 | from .sql import ( 24 | ComputedReflectionFixtureTest as ComputedReflectionFixtureTest, 25 | ) 26 | from .sql import DistinctOnFixture as DistinctOnFixture 27 | from .sql import insertmanyvalues_fixture as insertmanyvalues_fixture 28 | from .sql import NoCache as NoCache 29 | from .sql import RemovesEvents as RemovesEvents 30 | from .sql import TablesTest as TablesTest 31 | -------------------------------------------------------------------------------- /lib/sqlalchemy/testing/plugin/__init__.py: -------------------------------------------------------------------------------- 1 | # testing/plugin/__init__.py 2 | # Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 3 | # 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: https://www.opensource.org/licenses/mit-license.php 7 | -------------------------------------------------------------------------------- /lib/sqlalchemy/testing/plugin/bootstrap.py: -------------------------------------------------------------------------------- 1 | # testing/plugin/bootstrap.py 2 | # Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 3 | # 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: https://www.opensource.org/licenses/mit-license.php 7 | # mypy: ignore-errors 8 | 9 | """ 10 | Bootstrapper for test framework plugins. 11 | 12 | The entire rationale for this system is to get the modules in plugin/ 13 | imported without importing all of the supporting library, so that we can 14 | set up things for testing before coverage starts. 15 | 16 | The rationale for all of plugin/ being *in* the supporting library in the 17 | first place is so that the testing and plugin suite is available to other 18 | libraries, mainly external SQLAlchemy and Alembic dialects, to make use 19 | of the same test environment and standard suites available to 20 | SQLAlchemy/Alembic themselves without the need to ship/install a separate 21 | package outside of SQLAlchemy. 22 | 23 | 24 | """ 25 | 26 | import importlib.util 27 | import os 28 | import sys 29 | 30 | 31 | bootstrap_file = locals()["bootstrap_file"] 32 | to_bootstrap = locals()["to_bootstrap"] 33 | 34 | 35 | def load_file_as_module(name): 36 | path = os.path.join(os.path.dirname(bootstrap_file), "%s.py" % name) 37 | 38 | spec = importlib.util.spec_from_file_location(name, path) 39 | assert spec is not None 40 | assert spec.loader is not None 41 | mod = importlib.util.module_from_spec(spec) 42 | spec.loader.exec_module(mod) 43 | return mod 44 | 45 | 46 | if to_bootstrap == "pytest": 47 | sys.modules["sqla_plugin_base"] = load_file_as_module("plugin_base") 48 | sys.modules["sqla_plugin_base"].bootstrapped_as_sqlalchemy = True 49 | sys.modules["sqla_pytestplugin"] = load_file_as_module("pytestplugin") 50 | else: 51 | raise Exception("unknown bootstrap: %s" % to_bootstrap) # noqa 52 | -------------------------------------------------------------------------------- /lib/sqlalchemy/testing/suite/__init__.py: -------------------------------------------------------------------------------- 1 | # testing/suite/__init__.py 2 | # Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 3 | # 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: https://www.opensource.org/licenses/mit-license.php 7 | from .test_cte import * # noqa 8 | from .test_ddl import * # noqa 9 | from .test_dialect import * # noqa 10 | from .test_insert import * # noqa 11 | from .test_reflection import * # noqa 12 | from .test_results import * # noqa 13 | from .test_rowcount import * # noqa 14 | from .test_select import * # noqa 15 | from .test_sequence import * # noqa 16 | from .test_types import * # noqa 17 | from .test_unicode_ddl import * # noqa 18 | from .test_update_delete import * # noqa 19 | -------------------------------------------------------------------------------- /lib/sqlalchemy/testing/warnings.py: -------------------------------------------------------------------------------- 1 | # testing/warnings.py 2 | # Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 3 | # 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: https://www.opensource.org/licenses/mit-license.php 7 | # mypy: ignore-errors 8 | 9 | from __future__ import annotations 10 | 11 | import warnings 12 | 13 | from . import assertions 14 | from .. import exc 15 | from .. import exc as sa_exc 16 | from ..exc import SATestSuiteWarning 17 | from ..util.langhelpers import _warnings_warn 18 | 19 | 20 | def warn_test_suite(message): 21 | _warnings_warn(message, category=SATestSuiteWarning) 22 | 23 | 24 | def setup_filters(): 25 | """hook for setting up warnings filters. 26 | 27 | SQLAlchemy-specific classes must only be here and not in pytest config, 28 | as we need to delay importing SQLAlchemy until conftest.py has been 29 | processed. 30 | 31 | NOTE: filters on subclasses of DeprecationWarning or 32 | PendingDeprecationWarning have no effect if added here, since pytest 33 | will add at each test the following filters 34 | ``always::PendingDeprecationWarning`` and ``always::DeprecationWarning`` 35 | that will take precedence over any added here. 36 | 37 | """ 38 | warnings.filterwarnings("error", category=exc.SAWarning) 39 | warnings.filterwarnings("always", category=exc.SATestSuiteWarning) 40 | 41 | 42 | def assert_warnings(fn, warning_msgs, regex=False): 43 | """Assert that each of the given warnings are emitted by fn. 44 | 45 | Deprecated. Please use assertions.expect_warnings(). 46 | 47 | """ 48 | 49 | with assertions._expect_warnings( 50 | sa_exc.SAWarning, warning_msgs, regex=regex 51 | ): 52 | return fn() 53 | -------------------------------------------------------------------------------- /lib/sqlalchemy/util/_collections_cy.pxd: -------------------------------------------------------------------------------- 1 | # util/_collections_cy.pxd 2 | # Copyright (C) 2005-2024 the SQLAlchemy authors and contributors 3 | # 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: https://www.opensource.org/licenses/mit-license.php 7 | 8 | cdef unsigned long long _get_id(item: object) -------------------------------------------------------------------------------- /lib/sqlalchemy/util/_has_cython.py: -------------------------------------------------------------------------------- 1 | # util/_has_cython.py 2 | # Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 3 | # 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: https://www.opensource.org/licenses/mit-license.php 7 | # mypy: ignore-errors 8 | 9 | import typing 10 | 11 | 12 | def _all_cython_modules(): 13 | """Returns all modules that can be compiled using cython. 14 | Call ``_is_compiled()`` to check if the module is compiled or not. 15 | """ 16 | from . import _collections_cy 17 | from . import _immutabledict_cy 18 | from ..engine import _processors_cy 19 | from ..engine import _row_cy 20 | from ..engine import _util_cy as engine_util 21 | from ..sql import _util_cy as sql_util 22 | 23 | return ( 24 | _collections_cy, 25 | _immutabledict_cy, 26 | _processors_cy, 27 | _row_cy, 28 | engine_util, 29 | sql_util, 30 | ) 31 | 32 | 33 | _CYEXTENSION_MSG: str 34 | if not typing.TYPE_CHECKING: 35 | HAS_CYEXTENSION = all(m._is_compiled() for m in _all_cython_modules()) 36 | if HAS_CYEXTENSION: 37 | _CYEXTENSION_MSG = "Loaded" 38 | else: 39 | _CYEXTENSION_MSG = ", ".join( 40 | m.__name__ for m in _all_cython_modules() if not m._is_compiled() 41 | ) 42 | _CYEXTENSION_MSG = f"Modules {_CYEXTENSION_MSG} are not compiled" 43 | else: 44 | HAS_CYEXTENSION = False 45 | -------------------------------------------------------------------------------- /lib/sqlalchemy/util/cython.py: -------------------------------------------------------------------------------- 1 | # util/cython.py 2 | # Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 3 | # 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: https://www.opensource.org/licenses/mit-license.php 7 | from __future__ import annotations 8 | 9 | from typing import Any 10 | from typing import Callable 11 | from typing import Type 12 | from typing import TypeVar 13 | 14 | _T = TypeVar("_T") 15 | _NO_OP = Callable[[_T], _T] 16 | 17 | # cython module shims 18 | # -- 19 | IS_SHIM = True 20 | # constants 21 | compiled = False 22 | 23 | # types 24 | int = int # noqa: A001 25 | bint = bool 26 | longlong = int 27 | ulonglong = int 28 | Py_ssize_t = int 29 | uint = int 30 | float = float # noqa: A001 31 | double = float 32 | void = Any 33 | 34 | 35 | # functions 36 | def _no_op(fn: _T) -> _T: 37 | return fn 38 | 39 | 40 | cclass = _no_op # equivalent to "cdef class" 41 | ccall = _no_op # equivalent to "cpdef" function 42 | cfunc = _no_op # equivalent to "cdef" function 43 | inline = _no_op 44 | final = _no_op 45 | pointer = _no_op # not sure how to express a pointer to a type 46 | 47 | 48 | def declare(t: Type[_T], value: Any = None, **kw: Any) -> _T: 49 | return value # type: ignore[no-any-return] 50 | 51 | 52 | def annotation_typing(_: bool) -> _NO_OP[_T]: 53 | return _no_op 54 | 55 | 56 | def exceptval(value: Any = None, *, check: bool = False) -> _NO_OP[_T]: 57 | return _no_op 58 | 59 | 60 | def cast(type_: Type[_T], value: Any, *, typecheck: bool = False) -> _T: 61 | return value # type: ignore[no-any-return] 62 | -------------------------------------------------------------------------------- /mypy_plugin.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | plugins = sqlalchemy.ext.mypy.plugin 3 | show_error_codes = True 4 | mypy_path=./lib/ 5 | strict = True 6 | raise_exceptions=True 7 | 8 | [mypy-sqlalchemy.*] 9 | ignore_errors = True 10 | -------------------------------------------------------------------------------- /reap_dbs.py: -------------------------------------------------------------------------------- 1 | """Drop Oracle Database, SQL Server databases that are left over from a 2 | multiprocessing test run. 3 | 4 | Currently the cx_Oracle driver seems to sometimes not release a 5 | TCP connection even if close() is called, which prevents the provisioning 6 | system from dropping a database in-process. 7 | 8 | For SQL Server, databases still remain in use after tests run and 9 | running a kill of all detected sessions does not seem to release the 10 | database in process. 11 | 12 | """ 13 | 14 | import logging 15 | import sys 16 | 17 | from sqlalchemy.testing import provision 18 | 19 | 20 | logging.basicConfig() 21 | logging.getLogger(provision.__name__).setLevel(logging.INFO) 22 | 23 | provision.reap_dbs(sys.argv[1]) 24 | -------------------------------------------------------------------------------- /regen_callcounts.tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py{311,312}-sqla_{cext,nocext}-db_{sqlite,postgresql,mysql,oracle,mssql} 3 | 4 | [testenv] 5 | deps=pytest 6 | pytest-xdist 7 | mock 8 | db_postgresql: .[postgresql] 9 | db_mysql: .[mysql] 10 | db_oracle: .[oracle_oracledb] 11 | db_mssql: .[mssql] 12 | 13 | 14 | allowlist_externals=sh 15 | 16 | commands= 17 | db_{mysql}: {env:BASECOMMAND} {env:MYSQL:} {posargs} 18 | db_{postgresql}: {env:BASECOMMAND} {env:POSTGRESQL:} {posargs} 19 | db_{sqlite}: {env:BASECOMMAND} {env:SQLITE:} {posargs} 20 | db_{oracle}: {env:BASECOMMAND} {env:ORACLE:} {posargs} 21 | db_{mssql}: {env:BASECOMMAND} {env:MSSQL:} {posargs} 22 | 23 | passenv= 24 | ORACLE_HOME 25 | NLS_LANG 26 | TOX_POSTGRESQL 27 | TOX_MYSQL 28 | TOX_ORACLE 29 | TOX_MSSQL 30 | TOX_SQLITE 31 | TOX_WORKERS 32 | 33 | # -E : ignore PYTHON* environment variables (such as PYTHONPATH) 34 | # -s : don't add user site directory to sys.path; also PYTHONNOUSERSITE 35 | setenv= 36 | BASECOMMAND=python -m pytest test/aaa_profiling -x --nomemory --force-write-profiles 37 | PYTHONPATH= 38 | PYTHONNOUSERSITE=1 39 | sqla_nocext: DISABLE_SQLALCHEMY_CEXT=1 40 | sqla_cext: REQUIRE_SQLALCHEMY_CEXT=1 41 | db_sqlite: SQLITE={env:TOX_SQLITE:--db sqlite} 42 | db_postgresql: POSTGRESQL={env:TOX_POSTGRESQL:--db postgresql} 43 | db_mysql: MYSQL={env:TOX_MYSQL:--db mysql} 44 | db_oracle: ORACLE={env:TOX_ORACLE:--db oracledb} 45 | db_mssql: MSSQL={env:TOX_MSSQL:--db mssql} 46 | 47 | 48 | -------------------------------------------------------------------------------- /test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/test/__init__.py -------------------------------------------------------------------------------- /test/aaa_profiling/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/test/aaa_profiling/__init__.py -------------------------------------------------------------------------------- /test/aaa_profiling/test_pool.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import event 2 | from sqlalchemy.pool import QueuePool 3 | from sqlalchemy.testing import AssertsExecutionResults 4 | from sqlalchemy.testing import fixtures 5 | from sqlalchemy.testing import profiling 6 | 7 | pool = None 8 | 9 | 10 | class QueuePoolTest(fixtures.TestBase, AssertsExecutionResults): 11 | __requires__ = ("cpython", "python_profiling_backend") 12 | 13 | class Connection: 14 | def rollback(self): 15 | pass 16 | 17 | def close(self): 18 | pass 19 | 20 | def setup_test(self): 21 | # create a throwaway pool which 22 | # has the effect of initializing 23 | # class-level event listeners on Pool, 24 | # if not present already. 25 | p1 = QueuePool(creator=self.Connection, pool_size=3, max_overflow=-1) 26 | p1.connect() 27 | 28 | global pool 29 | pool = QueuePool(creator=self.Connection, pool_size=3, max_overflow=-1) 30 | 31 | # make this a real world case where we have a "connect" handler 32 | @event.listens_for(pool, "connect") 33 | def do_connect(dbapi_conn, conn_record): 34 | pass 35 | 36 | @profiling.function_call_count() 37 | def test_first_connect(self): 38 | pool.connect() 39 | 40 | def test_second_connect(self): 41 | conn = pool.connect() 42 | conn.close() 43 | 44 | @profiling.function_call_count() 45 | def go(): 46 | conn2 = pool.connect() 47 | return conn2 48 | 49 | go() 50 | -------------------------------------------------------------------------------- /test/base/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/test/base/__init__.py -------------------------------------------------------------------------------- /test/base/_concurrency_fixtures.py: -------------------------------------------------------------------------------- 1 | """Module that defines function that are run in a separate process. 2 | NOTE: the module must not import sqlalchemy at the top level. 3 | """ 4 | 5 | import asyncio # noqa: F401 6 | import sys 7 | 8 | 9 | def greenlet_not_imported(): 10 | assert "greenlet" not in sys.modules 11 | assert "sqlalchemy" not in sys.modules 12 | 13 | import sqlalchemy 14 | import sqlalchemy.util.concurrency # noqa: F401 15 | from sqlalchemy.util import greenlet_spawn # noqa: F401 16 | from sqlalchemy.util.concurrency import await_ # noqa: F401 17 | 18 | assert "greenlet" not in sys.modules 19 | 20 | 21 | def greenlet_setup_in_ext(): 22 | assert "greenlet" not in sys.modules 23 | assert "sqlalchemy" not in sys.modules 24 | 25 | import sqlalchemy.ext.asyncio # noqa: F401 26 | from sqlalchemy.util import greenlet_spawn 27 | 28 | assert "greenlet" in sys.modules 29 | value = -1 30 | 31 | def go(arg): 32 | nonlocal value 33 | value = arg 34 | 35 | async def call(): 36 | await greenlet_spawn(go, 42) 37 | 38 | asyncio.run(call()) 39 | 40 | assert value == 42 41 | 42 | 43 | def greenlet_setup_on_call(): 44 | from sqlalchemy.util import greenlet_spawn 45 | 46 | assert "greenlet" not in sys.modules 47 | value = -1 48 | 49 | def go(arg): 50 | nonlocal value 51 | value = arg 52 | 53 | async def call(): 54 | await greenlet_spawn(go, 42) 55 | 56 | asyncio.run(call()) 57 | 58 | assert "greenlet" in sys.modules 59 | assert value == 42 60 | -------------------------------------------------------------------------------- /test/base/test_examples.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | from sqlalchemy.testing import fixtures 5 | 6 | 7 | here = os.path.dirname(__file__) 8 | sqla_base = os.path.normpath(os.path.join(here, "..", "..")) 9 | 10 | 11 | sys.path.insert(0, sqla_base) 12 | 13 | test_versioning = __import__( 14 | "examples.versioned_history.test_versioning" 15 | ).versioned_history.test_versioning 16 | 17 | 18 | class VersionedRowsTestLegacyBase( 19 | test_versioning.TestVersioning, 20 | fixtures.RemoveORMEventsGlobally, 21 | fixtures.TestBase, 22 | ): 23 | pass 24 | 25 | 26 | class VersionedRowsTestNewBase( 27 | test_versioning.TestVersioningNewBase, 28 | fixtures.RemoveORMEventsGlobally, 29 | fixtures.TestBase, 30 | ): 31 | pass 32 | 33 | 34 | test_qualify = __import__( 35 | "examples.syntax_extensions.test_qualify" 36 | ).syntax_extensions.test_qualify 37 | 38 | 39 | class QualifyCompileTest(test_qualify.QualifyCompileTest, fixtures.TestBase): 40 | pass 41 | -------------------------------------------------------------------------------- /test/base/test_inspect.py: -------------------------------------------------------------------------------- 1 | """test the inspection registry system.""" 2 | 3 | from sqlalchemy import exc 4 | from sqlalchemy import inspect 5 | from sqlalchemy import inspection 6 | from sqlalchemy.testing import assert_raises_message 7 | from sqlalchemy.testing import eq_ 8 | from sqlalchemy.testing import fixtures 9 | 10 | 11 | class TestFixture: 12 | pass 13 | 14 | 15 | class TestInspection(fixtures.TestBase): 16 | def teardown_test(self): 17 | for type_ in list(inspection._registrars): 18 | if issubclass(type_, TestFixture): 19 | del inspection._registrars[type_] 20 | 21 | def test_def_insp(self): 22 | class SomeFoo(TestFixture): 23 | pass 24 | 25 | @inspection._inspects(SomeFoo) 26 | def insp_somefoo(subject): 27 | return {"insp": subject} 28 | 29 | somefoo = SomeFoo() 30 | insp = inspect(somefoo) 31 | assert insp["insp"] is somefoo 32 | 33 | def test_no_inspect(self): 34 | class SomeFoo(TestFixture): 35 | pass 36 | 37 | assert_raises_message( 38 | exc.NoInspectionAvailable, 39 | "No inspection system is available for object of type ", 40 | inspect, 41 | SomeFoo, 42 | ) 43 | 44 | def test_class_insp(self): 45 | class SomeFoo(TestFixture): 46 | pass 47 | 48 | class SomeFooInspect: 49 | def __init__(self, target): 50 | self.target = target 51 | 52 | SomeFooInspect = inspection._inspects(SomeFoo)(SomeFooInspect) 53 | 54 | somefoo = SomeFoo() 55 | insp = inspect(somefoo) 56 | assert isinstance(insp, SomeFooInspect) 57 | assert insp.target is somefoo 58 | 59 | def test_hierarchy_insp(self): 60 | class SomeFoo(TestFixture): 61 | pass 62 | 63 | class SomeSubFoo(SomeFoo): 64 | pass 65 | 66 | @inspection._inspects(SomeFoo) 67 | def insp_somefoo(subject): 68 | return 1 69 | 70 | @inspection._inspects(SomeSubFoo) 71 | def insp_somesubfoo(subject): 72 | return 2 73 | 74 | SomeFoo() 75 | eq_(inspect(SomeFoo()), 1) 76 | eq_(inspect(SomeSubFoo()), 2) 77 | -------------------------------------------------------------------------------- /test/base/test_misc_py3k.py: -------------------------------------------------------------------------------- 1 | import operator 2 | from typing import cast 3 | 4 | from sqlalchemy import Column 5 | from sqlalchemy.testing import eq_ 6 | from sqlalchemy.testing import fixtures 7 | 8 | 9 | class TestGenerics(fixtures.TestBase): 10 | def test_traversible_is_generic(self): 11 | """test #6759""" 12 | col = Column[int] 13 | 14 | # looked in the source for typing._GenericAlias. 15 | # col.__origin__ is Column, but it's not public API. 16 | # __reduce__ could change too but seems good enough for now 17 | eq_(cast(object, col).__reduce__(), (operator.getitem, (Column, int))) 18 | -------------------------------------------------------------------------------- /test/binary_data_one.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/test/binary_data_one.dat -------------------------------------------------------------------------------- /test/binary_data_two.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/test/binary_data_two.dat -------------------------------------------------------------------------------- /test/conftest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | pytest plugin script. 4 | 5 | This script is an extension to pytest which 6 | installs SQLAlchemy's testing plugin into the local environment. 7 | 8 | """ 9 | import os 10 | import sys 11 | 12 | import pytest 13 | 14 | 15 | os.environ["SQLALCHEMY_WARN_20"] = "true" 16 | 17 | collect_ignore_glob = [] 18 | 19 | # this requires that sqlalchemy.testing was not already 20 | # imported in order to work 21 | pytest.register_assert_rewrite("sqlalchemy.testing.assertions") 22 | 23 | 24 | if not sys.flags.no_user_site: 25 | # this is needed so that test scenarios like "python setup.py test" 26 | # work correctly, as well as plain "pytest". These commands assume 27 | # that the package in question is locally present, but since we have 28 | # ./lib/, we need to punch that in. 29 | # We check no_user_site to honor the use of this flag. 30 | sys.path.insert( 31 | 0, 32 | os.path.abspath( 33 | os.path.join( 34 | os.path.dirname(os.path.abspath(__file__)), "..", "lib" 35 | ) 36 | ), 37 | ) 38 | 39 | # use bootstrapping so that test plugins are loaded 40 | # without touching the main library before coverage starts 41 | bootstrap_file = os.path.join( 42 | os.path.dirname(__file__), 43 | "..", 44 | "lib", 45 | "sqlalchemy", 46 | "testing", 47 | "plugin", 48 | "bootstrap.py", 49 | ) 50 | 51 | with open(bootstrap_file) as f: 52 | code = compile(f.read(), "bootstrap.py", "exec") 53 | to_bootstrap = "pytest" 54 | exec(code, globals(), locals()) 55 | from sqla_pytestplugin import * # noqa 56 | -------------------------------------------------------------------------------- /test/dialect/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/test/dialect/__init__.py -------------------------------------------------------------------------------- /test/dialect/mssql/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/test/dialect/mssql/__init__.py -------------------------------------------------------------------------------- /test/dialect/mysql/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/test/dialect/mysql/__init__.py -------------------------------------------------------------------------------- /test/dialect/mysql/test_deprecations.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import select 2 | from sqlalchemy import table 3 | from sqlalchemy.dialects.mysql import base as mysql 4 | from sqlalchemy.testing import AssertsCompiledSQL 5 | from sqlalchemy.testing import expect_deprecated 6 | from sqlalchemy.testing import fixtures 7 | 8 | 9 | class CompileTest(AssertsCompiledSQL, fixtures.TestBase): 10 | __dialect__ = mysql.dialect() 11 | 12 | def test_distinct_string(self): 13 | s = select("*").select_from(table("foo")) 14 | s._distinct = "foo" 15 | 16 | with expect_deprecated( 17 | "Sending string values for 'distinct' is deprecated in the MySQL " 18 | "dialect and will be removed in a future release" 19 | ): 20 | self.assert_compile(s, "SELECT FOO * FROM foo") 21 | -------------------------------------------------------------------------------- /test/dialect/oracle/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/test/dialect/oracle/__init__.py -------------------------------------------------------------------------------- /test/dialect/oracle/_oracledb_mode.py: -------------------------------------------------------------------------------- 1 | # do not import sqlalchemy testing feature in this file, since it's 2 | # run directly, not passing through pytest 3 | from sqlalchemy import create_engine 4 | 5 | 6 | def _get_version(conn): 7 | # this is the suggested way of finding the mode, from 8 | # https://python-oracledb.readthedocs.io/en/latest/user_guide/tracing.html#finding-the-python-oracledb-mode 9 | sql = ( 10 | "SELECT UNIQUE CLIENT_DRIVER " 11 | "FROM V$SESSION_CONNECT_INFO " 12 | "WHERE SID = SYS_CONTEXT('USERENV', 'SID')" 13 | ) 14 | return conn.exec_driver_sql(sql).scalar() 15 | 16 | 17 | def run_thin_mode(url, queue, **kw): 18 | e = create_engine(url, **kw) 19 | with e.connect() as conn: 20 | res = _get_version(conn) 21 | queue.put((res, e.dialect.is_thin_mode(conn))) 22 | e.dispose() 23 | 24 | 25 | def run_thick_mode(url, queue, **kw): 26 | e = create_engine(url, **kw) 27 | with e.connect() as conn: 28 | res = _get_version(conn) 29 | queue.put((res, e.dialect.is_thin_mode(conn))) 30 | e.dispose() 31 | -------------------------------------------------------------------------------- /test/dialect/postgresql/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/test/dialect/postgresql/__init__.py -------------------------------------------------------------------------------- /test/dialect/test_all.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import dialects 2 | from sqlalchemy.testing import fixtures 3 | from sqlalchemy.testing import is_not 4 | 5 | 6 | class ImportStarTest(fixtures.TestBase): 7 | def _all_dialect_packages(self): 8 | return [ 9 | getattr(__import__("sqlalchemy.dialects.%s" % d).dialects, d) 10 | for d in dialects.__all__ 11 | if not d.startswith("_") 12 | ] 13 | 14 | def test_all_import(self): 15 | for package in self._all_dialect_packages(): 16 | for item_name in package.__all__: 17 | is_not(None, getattr(package, item_name)) 18 | -------------------------------------------------------------------------------- /test/dialect/test_pyodbc.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy.connectors import pyodbc 2 | from sqlalchemy.testing import eq_ 3 | from sqlalchemy.testing import fixtures 4 | 5 | 6 | class PyODBCTest(fixtures.TestBase): 7 | def test_pyodbc_version(self): 8 | connector = pyodbc.PyODBCConnector() 9 | for vers, expected in [ 10 | ("2.1.8", (2, 1, 8)), 11 | ("py3-3.0.1-beta4", (3, 0, 1, "beta4")), 12 | ("10.15.17", (10, 15, 17)), 13 | ("crap.crap.crap", ()), 14 | ]: 15 | eq_(connector._parse_dbapi_version(vers), expected) 16 | -------------------------------------------------------------------------------- /test/dialect/test_suite.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy.testing.suite import * # noqa 2 | -------------------------------------------------------------------------------- /test/engine/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/test/engine/__init__.py -------------------------------------------------------------------------------- /test/ext/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/test/ext/__init__.py -------------------------------------------------------------------------------- /test/ext/asyncio/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/test/ext/asyncio/__init__.py -------------------------------------------------------------------------------- /test/ext/declarative/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/test/ext/declarative/__init__.py -------------------------------------------------------------------------------- /test/orm/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/test/orm/__init__.py -------------------------------------------------------------------------------- /test/orm/declarative/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/test/orm/declarative/__init__.py -------------------------------------------------------------------------------- /test/orm/dml/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/test/orm/dml/__init__.py -------------------------------------------------------------------------------- /test/orm/inheritance/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/test/orm/inheritance/__init__.py -------------------------------------------------------------------------------- /test/orm/inheritance/test_deprecations.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/test/orm/inheritance/test_deprecations.py -------------------------------------------------------------------------------- /test/perf/compiled_extensions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/test/perf/compiled_extensions/__init__.py -------------------------------------------------------------------------------- /test/perf/compiled_extensions/__main__.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | import sys 3 | 4 | parent_dir = Path(__file__).parent.parent 5 | sys.path.insert(0, str(parent_dir.absolute())) 6 | if True: 7 | from compiled_extensions import command 8 | 9 | 10 | if __name__ == "__main__": 11 | command.main() 12 | -------------------------------------------------------------------------------- /test/perf/invalidate_stresstest.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import random 3 | import sys 4 | 5 | import gevent.monkey 6 | 7 | from sqlalchemy import create_engine 8 | from sqlalchemy import event 9 | 10 | 11 | gevent.monkey.patch_all() # noqa 12 | 13 | logging.basicConfig() # noqa 14 | # logging.getLogger("sqlalchemy.pool").setLevel(logging.INFO) 15 | 16 | engine = create_engine( 17 | "mysql+pymysql://scott:tiger@localhost/test", pool_size=50, max_overflow=0 18 | ) 19 | 20 | 21 | @event.listens_for(engine, "connect") 22 | def conn(*arg): 23 | print("new connection!") 24 | 25 | 26 | def worker(): 27 | while True: 28 | conn = engine.connect() 29 | try: 30 | conn.begin() 31 | for i in range(5): 32 | conn.exec_driver_sql("SELECT 1+1") 33 | gevent.sleep(random.random() * 1.01) 34 | 35 | except Exception: 36 | # traceback.print_exc() 37 | sys.stderr.write("X") 38 | else: 39 | conn.close() 40 | sys.stderr.write(".") 41 | 42 | 43 | def main(): 44 | for i in range(40): 45 | gevent.spawn(worker) 46 | 47 | gevent.sleep(3) 48 | 49 | while True: 50 | result = list(engine.exec_driver_sql("show processlist")) 51 | engine.exec_driver_sql("kill %d" % result[-2][0]) 52 | print("\n\n\n BOOM!!!!! \n\n\n") 53 | gevent.sleep(5) 54 | print(engine.pool.status()) 55 | 56 | 57 | main() 58 | -------------------------------------------------------------------------------- /test/sql/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzeek/sqlalchemy/742a3a6f9b320514e51e8f882143665a8edf31b9/test/sql/__init__.py -------------------------------------------------------------------------------- /test/sql/test_inspect.py: -------------------------------------------------------------------------------- 1 | """test the inspection registry system.""" 2 | 3 | from sqlalchemy import Column 4 | from sqlalchemy import inspect 5 | from sqlalchemy import Integer 6 | from sqlalchemy import MetaData 7 | from sqlalchemy import Table 8 | from sqlalchemy.sql import ClauseElement 9 | from sqlalchemy.testing import fixtures 10 | from sqlalchemy.testing import is_ 11 | 12 | 13 | class TestCoreInspection(fixtures.TestBase): 14 | def test_table(self): 15 | t = Table("t", MetaData(), Column("x", Integer)) 16 | 17 | is_(inspect(t), t) 18 | assert t.is_selectable 19 | is_(t.selectable, t) 20 | 21 | def test_select(self): 22 | t = Table("t", MetaData(), Column("x", Integer)) 23 | s = t.select() 24 | 25 | is_(inspect(s), s) 26 | assert s.is_selectable 27 | is_(s.selectable, s) 28 | 29 | def test_column_expr(self): 30 | c = Column("x", Integer) 31 | is_(inspect(c), c) 32 | assert not c.is_selectable 33 | assert not hasattr(c, "selectable") 34 | 35 | def test_no_clause_element_on_clauseelement(self): 36 | # re [ticket:3802], there are in the wild examples 37 | # of looping over __clause_element__, therefore the 38 | # absence of __clause_element__ as a test for "this is the clause 39 | # element" must be maintained 40 | 41 | class Foo(ClauseElement): 42 | pass 43 | 44 | assert not hasattr(Foo(), "__clause_element__") 45 | 46 | def test_col_now_has_a_clauseelement(self): 47 | x = Column("foo", Integer) 48 | 49 | assert hasattr(x, "__clause_element__") 50 | -------------------------------------------------------------------------------- /test/typing/plain_files/dialects/mysql/mysql_stuff.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import Integer 2 | from sqlalchemy.dialects.mysql import insert 3 | from sqlalchemy.orm import DeclarativeBase 4 | from sqlalchemy.orm import Mapped 5 | from sqlalchemy.orm import mapped_column 6 | 7 | 8 | class Base(DeclarativeBase): 9 | pass 10 | 11 | 12 | class Test(Base): 13 | __tablename__ = "test_table_json" 14 | 15 | id = mapped_column(Integer, primary_key=True) 16 | data: Mapped[str] = mapped_column() 17 | 18 | 19 | insert(Test).on_duplicate_key_update( 20 | {"id": 42, Test.data: 99}, [("foo", 44)], data=99, id="foo" 21 | ).inserted.foo.desc() 22 | -------------------------------------------------------------------------------- /test/typing/plain_files/dialects/sqlite/sqlite_stuff.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import Integer 2 | from sqlalchemy import UniqueConstraint 3 | from sqlalchemy.dialects.sqlite import insert 4 | from sqlalchemy.orm import DeclarativeBase 5 | from sqlalchemy.orm import Mapped 6 | from sqlalchemy.orm import mapped_column 7 | 8 | 9 | class Base(DeclarativeBase): 10 | pass 11 | 12 | 13 | class Test(Base): 14 | __tablename__ = "test_table_json" 15 | 16 | id = mapped_column(Integer, primary_key=True) 17 | data: Mapped[str] = mapped_column() 18 | 19 | 20 | unique = UniqueConstraint(name="my_constraint") 21 | insert(Test).on_conflict_do_nothing("foo", Test.id > 0).on_conflict_do_update( 22 | unique, Test.id > 0, {"id": 42, Test.data: 99}, Test.id == 22 23 | ).excluded.foo.desc() 24 | 25 | s1 = insert(Test) 26 | s1.on_conflict_do_update(set_=s1.excluded) 27 | -------------------------------------------------------------------------------- /test/typing/plain_files/engine/engine_inspection.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | from sqlalchemy import create_engine 4 | from sqlalchemy import inspect 5 | 6 | 7 | e = create_engine("sqlite://") 8 | 9 | insp = inspect(e) 10 | 11 | cols = insp.get_columns("some_table") 12 | 13 | c1 = cols[0] 14 | 15 | if typing.TYPE_CHECKING: 16 | # EXPECTED_RE_TYPE: sqlalchemy.engine.base.Engine 17 | reveal_type(e) 18 | 19 | # EXPECTED_RE_TYPE: sqlalchemy.engine.reflection.Inspector.* 20 | reveal_type(insp) 21 | 22 | # EXPECTED_RE_TYPE: .*list.*TypedDict.*ReflectedColumn.* 23 | reveal_type(cols) 24 | -------------------------------------------------------------------------------- /test/typing/plain_files/engine/engines.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | from sqlalchemy import Pool 3 | from sqlalchemy import select 4 | from sqlalchemy import text 5 | 6 | 7 | def regular() -> None: 8 | e = create_engine("sqlite://") 9 | 10 | # EXPECTED_TYPE: Engine 11 | reveal_type(e) 12 | 13 | with e.connect() as conn: 14 | # EXPECTED_TYPE: Connection 15 | reveal_type(conn) 16 | 17 | result = conn.execute(text("select * from table")) 18 | 19 | # EXPECTED_TYPE: CursorResult[Unpack[.*tuple[Any, ...]]] 20 | reveal_type(result) 21 | 22 | with e.begin() as conn: 23 | # EXPECTED_TYPE: Connection 24 | reveal_type(conn) 25 | 26 | result = conn.execute(text("select * from table")) 27 | 28 | # EXPECTED_TYPE: CursorResult[Unpack[.*tuple[Any, ...]]] 29 | reveal_type(result) 30 | 31 | engine = create_engine("postgresql://scott:tiger@localhost/test") 32 | status: str = engine.pool.status() 33 | other_pool: Pool = engine.pool.recreate() 34 | ce = select(1).compile(e) 35 | ce.statement 36 | cc = select(1).compile(conn) 37 | cc.statement 38 | 39 | print(status, other_pool) 40 | -------------------------------------------------------------------------------- /test/typing/plain_files/ext/association_proxy/association_proxy_one.py: -------------------------------------------------------------------------------- 1 | import typing 2 | from typing import Set 3 | 4 | from sqlalchemy import ForeignKey 5 | from sqlalchemy import Integer 6 | from sqlalchemy import String 7 | from sqlalchemy.ext.associationproxy import association_proxy 8 | from sqlalchemy.ext.associationproxy import AssociationProxy 9 | from sqlalchemy.orm import DeclarativeBase 10 | from sqlalchemy.orm import Mapped 11 | from sqlalchemy.orm import mapped_column 12 | from sqlalchemy.orm import relationship 13 | 14 | 15 | class Base(DeclarativeBase): 16 | pass 17 | 18 | 19 | class User(Base): 20 | __tablename__ = "user" 21 | 22 | id = mapped_column(Integer, primary_key=True) 23 | name = mapped_column(String, nullable=False) 24 | 25 | addresses: Mapped[Set["Address"]] = relationship() 26 | 27 | email_addresses: AssociationProxy[Set[str]] = association_proxy( 28 | "addresses", "email" 29 | ) 30 | 31 | 32 | class Address(Base): 33 | __tablename__ = "address" 34 | 35 | id = mapped_column(Integer, primary_key=True) 36 | user_id = mapped_column(ForeignKey("user.id")) 37 | email = mapped_column(String, nullable=False) 38 | 39 | 40 | u1 = User() 41 | 42 | if typing.TYPE_CHECKING: 43 | # EXPECTED_RE_TYPE: sqlalchemy.*.associationproxy.AssociationProxyInstance\[builtins.set\*?\[builtins.str\]\] 44 | reveal_type(User.email_addresses) 45 | 46 | # EXPECTED_RE_TYPE: builtins.set\*?\[builtins.str\] 47 | reveal_type(u1.email_addresses) 48 | -------------------------------------------------------------------------------- /test/typing/plain_files/ext/association_proxy/association_proxy_three.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import List 4 | 5 | from sqlalchemy import ForeignKey 6 | from sqlalchemy.ext.associationproxy import association_proxy 7 | from sqlalchemy.ext.associationproxy import AssociationProxy 8 | from sqlalchemy.orm import DeclarativeBase 9 | from sqlalchemy.orm import declared_attr 10 | from sqlalchemy.orm import Mapped 11 | from sqlalchemy.orm import mapped_column 12 | from sqlalchemy.orm import relationship 13 | 14 | 15 | class Base(DeclarativeBase): 16 | pass 17 | 18 | 19 | class Milestone: 20 | id: Mapped[int] = mapped_column(primary_key=True) 21 | 22 | @declared_attr 23 | def users(self) -> Mapped[List["User"]]: 24 | return relationship("User") 25 | 26 | @declared_attr 27 | def user_ids(self) -> AssociationProxy[List[int]]: 28 | return association_proxy("users", "id") 29 | 30 | 31 | class BranchMilestone(Milestone, Base): 32 | __tablename__ = "branch_milestones" 33 | 34 | 35 | class User(Base): 36 | __tablename__ = "user" 37 | id: Mapped[int] = mapped_column(primary_key=True) 38 | branch_id: Mapped[int] = mapped_column(ForeignKey("branch_milestones.id")) 39 | 40 | 41 | bm = BranchMilestone() 42 | 43 | x1 = bm.user_ids 44 | 45 | # EXPECTED_TYPE: list[int] 46 | reveal_type(x1) 47 | -------------------------------------------------------------------------------- /test/typing/plain_files/ext/association_proxy/association_proxy_two.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import Final 4 | 5 | from sqlalchemy import Column 6 | from sqlalchemy import ForeignKey 7 | from sqlalchemy import Integer 8 | from sqlalchemy import String 9 | from sqlalchemy import Table 10 | from sqlalchemy.ext.associationproxy import association_proxy 11 | from sqlalchemy.ext.associationproxy import AssociationProxy 12 | from sqlalchemy.orm import DeclarativeBase 13 | from sqlalchemy.orm import Mapped 14 | from sqlalchemy.orm import mapped_column 15 | from sqlalchemy.orm import relationship 16 | 17 | 18 | class Base(DeclarativeBase): 19 | pass 20 | 21 | 22 | class User(Base): 23 | __tablename__ = "user" 24 | id: Mapped[int] = mapped_column(primary_key=True) 25 | name: Mapped[str] = mapped_column(String(64)) 26 | kw: Mapped[list[Keyword]] = relationship( 27 | secondary=lambda: user_keyword_table 28 | ) 29 | 30 | def __init__(self, name: str): 31 | self.name = name 32 | 33 | # proxy the 'keyword' attribute from the 'kw' relationship 34 | keywords: AssociationProxy[list[str]] = association_proxy("kw", "keyword") 35 | 36 | 37 | class Keyword(Base): 38 | __tablename__ = "keyword" 39 | id: Mapped[int] = mapped_column(primary_key=True) 40 | keyword: Mapped[str] = mapped_column(String(64)) 41 | 42 | def __init__(self, keyword: str): 43 | self.keyword = keyword 44 | 45 | 46 | user_keyword_table: Final[Table] = Table( 47 | "user_keyword", 48 | Base.metadata, 49 | Column("user_id", Integer, ForeignKey("user.id"), primary_key=True), 50 | Column("keyword_id", Integer, ForeignKey("keyword.id"), primary_key=True), 51 | ) 52 | 53 | user = User("jek") 54 | 55 | # EXPECTED_TYPE: list[Keyword] 56 | reveal_type(user.kw) 57 | 58 | user.kw.append(Keyword("cheese-inspector")) 59 | 60 | user.keywords.append("cheese-inspector") 61 | 62 | # EXPECTED_TYPE: list[str] 63 | reveal_type(user.keywords) 64 | 65 | user.keywords.append("snack ninja") 66 | -------------------------------------------------------------------------------- /test/typing/plain_files/ext/asyncio/async_stuff.py: -------------------------------------------------------------------------------- 1 | from asyncio import current_task 2 | 3 | from sqlalchemy import text 4 | from sqlalchemy.ext.asyncio import async_scoped_session 5 | from sqlalchemy.ext.asyncio import async_sessionmaker 6 | from sqlalchemy.ext.asyncio import AsyncSession 7 | from sqlalchemy.ext.asyncio import create_async_engine 8 | 9 | 10 | engine = create_async_engine("") 11 | SM = async_sessionmaker(engine, class_=AsyncSession) 12 | 13 | async_session = AsyncSession(engine) 14 | 15 | as_session = async_scoped_session(SM, current_task) 16 | 17 | 18 | async def go() -> None: 19 | r = await async_session.scalars(text("select 1"), params=[]) 20 | r.first() 21 | sr = await async_session.stream_scalars(text("select 1"), params=[]) 22 | await sr.all() 23 | r = await as_session.scalars(text("select 1"), params=[]) 24 | r.first() 25 | sr = await as_session.stream_scalars(text("select 1"), params=[]) 26 | await sr.all() 27 | 28 | async with engine.connect() as conn: 29 | cr = await conn.scalars(text("select 1")) 30 | cr.first() 31 | scr = await conn.stream_scalars(text("select 1")) 32 | await scr.all() 33 | 34 | ast = async_session.get_transaction() 35 | if ast: 36 | ast.is_active 37 | nt = async_session.get_nested_transaction() 38 | if nt: 39 | nt.is_active 40 | -------------------------------------------------------------------------------- /test/typing/plain_files/ext/hybrid/hybrid_four.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import Any 4 | 5 | from sqlalchemy import ColumnElement 6 | from sqlalchemy import func 7 | from sqlalchemy.ext.hybrid import Comparator 8 | from sqlalchemy.ext.hybrid import hybrid_property 9 | from sqlalchemy.orm import DeclarativeBase 10 | from sqlalchemy.orm import Mapped 11 | from sqlalchemy.orm import mapped_column 12 | 13 | 14 | class Base(DeclarativeBase): 15 | pass 16 | 17 | 18 | class CaseInsensitiveComparator(Comparator[str]): 19 | def __eq__(self, other: Any) -> ColumnElement[bool]: # type: ignore[override] # noqa: E501 20 | return func.lower(self.__clause_element__()) == func.lower(other) 21 | 22 | 23 | class SearchWord(Base): 24 | __tablename__ = "searchword" 25 | 26 | id: Mapped[int] = mapped_column(primary_key=True) 27 | word: Mapped[str] 28 | 29 | @hybrid_property 30 | def word_insensitive(self) -> str: 31 | return self.word.lower() 32 | 33 | @word_insensitive.inplace.comparator 34 | @classmethod 35 | def _word_insensitive_comparator(cls) -> CaseInsensitiveComparator: 36 | return CaseInsensitiveComparator(cls.word) 37 | 38 | 39 | class FirstNameOnly(Base): 40 | __tablename__ = "f" 41 | 42 | id: Mapped[int] = mapped_column(primary_key=True) 43 | first_name: Mapped[str] 44 | 45 | @hybrid_property 46 | def name(self) -> str: 47 | return self.first_name 48 | 49 | @name.inplace.setter 50 | def _name_setter(self, value: str) -> None: 51 | self.first_name = value 52 | 53 | @name.inplace.deleter 54 | def _name_del(self) -> None: 55 | self.first_name = "" 56 | 57 | @name.inplace.expression 58 | @classmethod 59 | def _name_expr(cls) -> ColumnElement[str]: 60 | return cls.first_name + "-" 61 | 62 | 63 | class FirstNameLastName(FirstNameOnly): 64 | last_name: Mapped[str] 65 | 66 | @FirstNameOnly.name.getter 67 | def name(self) -> str: 68 | return self.first_name + " " + self.last_name 69 | 70 | @name.inplace.setter 71 | def _name_setter(self, value: str) -> None: 72 | self.first_name, self.last_name = value.split(" ", 1) 73 | -------------------------------------------------------------------------------- /test/typing/plain_files/ext/misc_ext.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | from sqlalchemy import JSON 4 | from sqlalchemy import Select 5 | from sqlalchemy.ext.compiler import compiles 6 | from sqlalchemy.ext.mutable import MutableDict 7 | from sqlalchemy.ext.mutable import MutableList 8 | from sqlalchemy.sql.compiler import SQLCompiler 9 | 10 | 11 | @compiles(Select[Any], "my_cool_driver") 12 | def go(sel: Select[Any], compiler: SQLCompiler, **kw: Any) -> str: 13 | return "select 42" 14 | 15 | 16 | MutableList.as_mutable(JSON) 17 | MutableDict.as_mutable(JSON()) 18 | -------------------------------------------------------------------------------- /test/typing/plain_files/inspection_inspect.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | from sqlalchemy import create_engine 4 | from sqlalchemy import inspect 5 | from sqlalchemy.engine.reflection import Inspector 6 | from sqlalchemy.orm import DeclarativeBase 7 | from sqlalchemy.orm import DeclarativeBaseNoMeta 8 | from sqlalchemy.orm import Mapped 9 | from sqlalchemy.orm import mapped_column 10 | from sqlalchemy.orm import Mapper 11 | 12 | 13 | class Base(DeclarativeBase): 14 | pass 15 | 16 | 17 | class A(Base): 18 | __tablename__ = "a" 19 | 20 | id: Mapped[int] = mapped_column(primary_key=True) 21 | data: Mapped[str] 22 | 23 | 24 | class BaseNoMeta(DeclarativeBaseNoMeta): 25 | pass 26 | 27 | 28 | class B(BaseNoMeta): 29 | __tablename__ = "b" 30 | 31 | id: Mapped[int] = mapped_column(primary_key=True) 32 | data: Mapped[str] 33 | 34 | 35 | # EXPECTED_TYPE: Mapper[Any] 36 | reveal_type(A.__mapper__) 37 | # EXPECTED_TYPE: Mapper[Any] 38 | reveal_type(B.__mapper__) 39 | 40 | a1 = A(data="d") 41 | b1 = B(data="d") 42 | 43 | e = create_engine("sqlite://") 44 | 45 | insp_a1 = inspect(a1) 46 | 47 | t: bool = insp_a1.transient 48 | # EXPECTED_TYPE: InstanceState[A] 49 | reveal_type(insp_a1) 50 | # EXPECTED_TYPE: InstanceState[B] 51 | reveal_type(inspect(b1)) 52 | 53 | m: Mapper[A] = inspect(A) 54 | # EXPECTED_TYPE: Mapper[A] 55 | reveal_type(inspect(A)) 56 | # EXPECTED_TYPE: Mapper[B] 57 | reveal_type(inspect(B)) 58 | 59 | tables: List[str] = inspect(e).get_table_names() 60 | 61 | i: Inspector = inspect(e) 62 | # EXPECTED_TYPE: Inspector 63 | reveal_type(inspect(e)) 64 | 65 | 66 | with e.connect() as conn: 67 | inspect(conn).get_table_names() 68 | -------------------------------------------------------------------------------- /test/typing/plain_files/orm/composite.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | from typing import Tuple 3 | 4 | from sqlalchemy import select 5 | from sqlalchemy.orm import composite 6 | from sqlalchemy.orm import DeclarativeBase 7 | from sqlalchemy.orm import Mapped 8 | from sqlalchemy.orm import mapped_column 9 | 10 | 11 | class Base(DeclarativeBase): 12 | pass 13 | 14 | 15 | class Point: 16 | def __init__(self, x: int, y: int): 17 | self.x = x 18 | self.y = y 19 | 20 | def __composite_values__(self) -> Tuple[int, int]: 21 | return self.x, self.y 22 | 23 | def __repr__(self) -> str: 24 | return "Point(x=%r, y=%r)" % (self.x, self.y) 25 | 26 | def __eq__(self, other: Any) -> bool: 27 | return ( 28 | isinstance(other, Point) 29 | and other.x == self.x 30 | and other.y == self.y 31 | ) 32 | 33 | def __ne__(self, other: Any) -> bool: 34 | return not self.__eq__(other) 35 | 36 | @classmethod 37 | def _generate(cls, x1: int, y1: int) -> "Point": 38 | return Point(x1, y1) 39 | 40 | 41 | class Vertex(Base): 42 | __tablename__ = "vertices" 43 | 44 | id: Mapped[int] = mapped_column(primary_key=True) 45 | x1: Mapped[int] 46 | y1: Mapped[int] 47 | x2: Mapped[int] 48 | y2: Mapped[int] 49 | 50 | # inferred from right hand side 51 | start = composite(Point, "x1", "y1") 52 | 53 | # taken from left hand side 54 | end: Mapped[Point] = composite(Point._generate, "x2", "y2") 55 | 56 | 57 | v1 = Vertex(start=Point(3, 4), end=Point(5, 6)) 58 | 59 | stmt = select(Vertex).where(Vertex.start.in_([Point(3, 4)])) 60 | 61 | # EXPECTED_TYPE: Select[Vertex] 62 | reveal_type(stmt) 63 | 64 | # EXPECTED_TYPE: composite.Point 65 | reveal_type(v1.start) 66 | 67 | # EXPECTED_TYPE: composite.Point 68 | reveal_type(v1.end) 69 | 70 | # EXPECTED_TYPE: int 71 | reveal_type(v1.end.y) 72 | -------------------------------------------------------------------------------- /test/typing/plain_files/orm/composite_dc.py: -------------------------------------------------------------------------------- 1 | import dataclasses 2 | 3 | from sqlalchemy import select 4 | from sqlalchemy.orm import composite 5 | from sqlalchemy.orm import DeclarativeBase 6 | from sqlalchemy.orm import Mapped 7 | from sqlalchemy.orm import mapped_column 8 | 9 | 10 | class Base(DeclarativeBase): 11 | pass 12 | 13 | 14 | @dataclasses.dataclass 15 | class Point: 16 | def __init__(self, x: int, y: int): 17 | self.x = x 18 | self.y = y 19 | 20 | 21 | class Vertex(Base): 22 | __tablename__ = "vertices" 23 | 24 | id: Mapped[int] = mapped_column(primary_key=True) 25 | x1: Mapped[int] 26 | y1: Mapped[int] 27 | x2: Mapped[int] 28 | y2: Mapped[int] 29 | 30 | # inferred from right hand side 31 | start = composite(Point, "x1", "y1") 32 | 33 | # taken from left hand side 34 | end: Mapped[Point] = composite(Point, "x2", "y2") 35 | 36 | 37 | v1 = Vertex(start=Point(3, 4), end=Point(5, 6)) 38 | 39 | stmt = select(Vertex).where(Vertex.start.in_([Point(3, 4)])) 40 | 41 | # EXPECTED_TYPE: Select[Vertex] 42 | reveal_type(stmt) 43 | 44 | # EXPECTED_TYPE: composite.Point 45 | reveal_type(v1.start) 46 | 47 | # EXPECTED_TYPE: composite.Point 48 | reveal_type(v1.end) 49 | 50 | # EXPECTED_TYPE: int 51 | reveal_type(v1.end.y) 52 | -------------------------------------------------------------------------------- /test/typing/plain_files/orm/dataclass_transforms_one.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import Optional 4 | 5 | from sqlalchemy.orm import column_property 6 | from sqlalchemy.orm import DeclarativeBase 7 | from sqlalchemy.orm import Mapped 8 | from sqlalchemy.orm import mapped_column 9 | from sqlalchemy.orm import MappedAsDataclass 10 | from sqlalchemy.orm import query_expression 11 | 12 | 13 | class Base(DeclarativeBase): 14 | pass 15 | 16 | 17 | class TestInitialSupport(Base): 18 | __tablename__ = "a" 19 | 20 | id: Mapped[int] = mapped_column(primary_key=True, init=False) 21 | data: Mapped[str] 22 | x: Mapped[Optional[int]] = mapped_column(default=None) 23 | y: Mapped[Optional[int]] = mapped_column(kw_only=True) 24 | 25 | 26 | tis = TestInitialSupport(data="some data", y=5) 27 | 28 | # EXPECTED_TYPE: str 29 | reveal_type(tis.data) 30 | 31 | # EXPECTED_RE_TYPE: .*Union\[builtins.int, None\] 32 | reveal_type(tis.y) 33 | 34 | tis.data = "some other data" 35 | 36 | 37 | class TestTicket9628(MappedAsDataclass, Base): 38 | __tablename__ = "ticket_9628" 39 | 40 | id: Mapped[int] = mapped_column(primary_key=True, init=False) 41 | data: Mapped[str] = mapped_column() 42 | 43 | d2: Mapped[str] = column_property(data + "Asdf") 44 | d3: Mapped[str] = query_expression(data + "Asdf") 45 | 46 | 47 | # d2 and d3 are not required, as these have init=False. We omit 48 | # them from dataclass transforms entirely as these are never intended 49 | # to be writeable fields in a 2.0 declarative mapping 50 | t9628 = TestTicket9628(data="asf") 51 | -------------------------------------------------------------------------------- /test/typing/plain_files/orm/declared_attr_two.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | from sqlalchemy import Integer 4 | from sqlalchemy import Text 5 | from sqlalchemy.orm import DeclarativeBase 6 | from sqlalchemy.orm import declared_attr 7 | from sqlalchemy.orm import Mapped 8 | from sqlalchemy.orm import mapped_column 9 | 10 | 11 | class Base(DeclarativeBase): 12 | pass 13 | 14 | 15 | class HasRelatedDataMixin: 16 | @declared_attr 17 | def related_data(cls) -> Mapped[str]: 18 | return mapped_column(Text(), deferred=True) 19 | 20 | 21 | class User(HasRelatedDataMixin, Base): 22 | @declared_attr.directive 23 | def __tablename__(cls) -> str: 24 | return "user" 25 | 26 | @declared_attr.directive 27 | def __mapper_args__(cls) -> typing.Dict[str, typing.Any]: 28 | return {} 29 | 30 | id = mapped_column(Integer, primary_key=True) 31 | 32 | 33 | class Foo(Base): 34 | __tablename__ = "foo" 35 | 36 | id = mapped_column(Integer, primary_key=True) 37 | 38 | 39 | u1 = User() 40 | 41 | if typing.TYPE_CHECKING: 42 | # EXPECTED_TYPE: str 43 | reveal_type(User.__tablename__) 44 | 45 | # EXPECTED_TYPE: str 46 | reveal_type(Foo.__tablename__) 47 | 48 | # EXPECTED_TYPE: str 49 | reveal_type(u1.related_data) 50 | 51 | # EXPECTED_TYPE: InstrumentedAttribute[str] 52 | reveal_type(User.related_data) 53 | -------------------------------------------------------------------------------- /test/typing/plain_files/orm/issue_9340.py: -------------------------------------------------------------------------------- 1 | from typing import Sequence 2 | from typing import TYPE_CHECKING 3 | 4 | from sqlalchemy import create_engine 5 | from sqlalchemy import select 6 | from sqlalchemy.orm import DeclarativeBase 7 | from sqlalchemy.orm import Mapped 8 | from sqlalchemy.orm import mapped_column 9 | from sqlalchemy.orm import Session 10 | from sqlalchemy.orm import with_polymorphic 11 | 12 | 13 | class Base(DeclarativeBase): ... 14 | 15 | 16 | class Message(Base): 17 | __tablename__ = "message" 18 | __mapper_args__ = { 19 | "polymorphic_on": "message_type", 20 | "polymorphic_identity": __tablename__, 21 | } 22 | id: Mapped[int] = mapped_column(primary_key=True) 23 | text: Mapped[str] 24 | message_type: Mapped[str] 25 | 26 | 27 | class UserComment(Message): 28 | __mapper_args__ = { 29 | "polymorphic_identity": "user_comment", 30 | } 31 | username: Mapped[str] = mapped_column(nullable=True) 32 | 33 | 34 | engine = create_engine("postgresql+psycopg2://scott:tiger@localhost/") 35 | 36 | 37 | def get_messages() -> Sequence[Message]: 38 | with Session(engine) as session: 39 | message_query = select(Message) 40 | 41 | if TYPE_CHECKING: 42 | # EXPECTED_TYPE: Select[Message] 43 | reveal_type(message_query) 44 | 45 | return session.scalars(message_query).all() 46 | 47 | 48 | def get_poly_messages() -> Sequence[Message]: 49 | with Session(engine) as session: 50 | PolymorphicMessage = with_polymorphic(Message, (UserComment,)) 51 | 52 | if TYPE_CHECKING: 53 | # EXPECTED_TYPE: AliasedClass[Message] 54 | reveal_type(PolymorphicMessage) 55 | 56 | poly_query = select(PolymorphicMessage) 57 | 58 | if TYPE_CHECKING: 59 | # EXPECTED_TYPE: Select[Message] 60 | reveal_type(poly_query) 61 | 62 | return session.scalars(poly_query).all() 63 | -------------------------------------------------------------------------------- /test/typing/plain_files/orm/keyfunc_dict.py: -------------------------------------------------------------------------------- 1 | import typing 2 | from typing import Dict 3 | from typing import Optional 4 | 5 | from sqlalchemy import ForeignKey 6 | from sqlalchemy.orm import attribute_keyed_dict 7 | from sqlalchemy.orm import DeclarativeBase 8 | from sqlalchemy.orm import Mapped 9 | from sqlalchemy.orm import mapped_column 10 | from sqlalchemy.orm import relationship 11 | 12 | 13 | class Base(DeclarativeBase): 14 | pass 15 | 16 | 17 | class Item(Base): 18 | __tablename__ = "item" 19 | 20 | id: Mapped[int] = mapped_column(primary_key=True) 21 | 22 | notes: Mapped[Dict[str, "Note"]] = relationship( 23 | collection_class=attribute_keyed_dict("keyword"), 24 | cascade="all, delete-orphan", 25 | ) 26 | 27 | 28 | class Note(Base): 29 | __tablename__ = "note" 30 | 31 | id: Mapped[int] = mapped_column(primary_key=True) 32 | item_id: Mapped[int] = mapped_column(ForeignKey("item.id")) 33 | keyword: Mapped[str] 34 | text: Mapped[Optional[str]] 35 | 36 | def __init__(self, keyword: str, text: str): 37 | self.keyword = keyword 38 | self.text = text 39 | 40 | 41 | item = Item() 42 | item.notes["a"] = Note("a", "atext") 43 | 44 | if typing.TYPE_CHECKING: 45 | # EXPECTED_TYPE: dict_items[str, Note] 46 | reveal_type(item.notes.items()) 47 | -------------------------------------------------------------------------------- /test/typing/plain_files/orm/mapped_assign_expression.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | from sqlalchemy import create_engine 4 | from sqlalchemy.orm import Mapped 5 | from sqlalchemy.orm import mapped_column 6 | from sqlalchemy.orm import registry 7 | from sqlalchemy.orm import Session 8 | from sqlalchemy.sql.functions import now 9 | 10 | mapper_registry: registry = registry() 11 | e = create_engine("sqlite:///database.db", echo=True) 12 | 13 | 14 | @mapper_registry.mapped 15 | class A: 16 | __tablename__ = "a" 17 | id: Mapped[int] = mapped_column(primary_key=True) 18 | date_time: Mapped[datetime] 19 | 20 | 21 | mapper_registry.metadata.create_all(e) 22 | 23 | with Session(e) as s: 24 | a = A() 25 | a.date_time = now() 26 | s.add(a) 27 | s.commit() 28 | -------------------------------------------------------------------------------- /test/typing/plain_files/orm/orm_config_constructs.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import String 2 | from sqlalchemy.orm import column_property 3 | from sqlalchemy.orm import DeclarativeBase 4 | from sqlalchemy.orm import deferred 5 | from sqlalchemy.orm import Mapped 6 | from sqlalchemy.orm import mapped_column 7 | from sqlalchemy.orm import query_expression 8 | from sqlalchemy.orm import validates 9 | 10 | 11 | class Base(DeclarativeBase): 12 | pass 13 | 14 | 15 | class User(Base): 16 | __tablename__ = "User" 17 | 18 | id: Mapped[int] = mapped_column(primary_key=True) 19 | name: Mapped[str] 20 | 21 | @validates("name", include_removes=True) 22 | def validate_name(self, name: str) -> str: 23 | """test #8577""" 24 | return name + "hi" 25 | 26 | # test #9536 27 | _password: Mapped[str] = mapped_column("Password", String) 28 | password1: Mapped[str] = column_property( 29 | _password.collate("SQL_Latin1_General_CP1_CS_AS"), deferred=True 30 | ) 31 | password2: Mapped[str] = deferred( 32 | _password.collate("SQL_Latin1_General_CP1_CS_AS") 33 | ) 34 | password3: Mapped[str] = query_expression( 35 | _password.collate("SQL_Latin1_General_CP1_CS_AS") 36 | ) 37 | -------------------------------------------------------------------------------- /test/typing/plain_files/orm/scoped_session.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import inspect 2 | from sqlalchemy import text 3 | from sqlalchemy.orm import DeclarativeBase 4 | from sqlalchemy.orm import Mapped 5 | from sqlalchemy.orm import mapped_column 6 | from sqlalchemy.orm import scoped_session 7 | from sqlalchemy.orm import sessionmaker 8 | 9 | 10 | class Base(DeclarativeBase): 11 | pass 12 | 13 | 14 | class X(Base): 15 | __tablename__ = "x" 16 | id: Mapped[int] = mapped_column(primary_key=True) 17 | 18 | 19 | scoped_session.object_session(object()) 20 | scoped_session.identity_key() 21 | ss = scoped_session(sessionmaker()) 22 | value: bool = "foo" in ss 23 | list(ss) 24 | ss.add(object()) 25 | ss.add_all([]) 26 | ss.begin() 27 | ss.begin_nested() 28 | ss.close() 29 | ss.commit() 30 | ss.connection() 31 | ss.delete(object()) 32 | ss.execute(text("select 1")) 33 | ss.expire(object()) 34 | ss.expire_all() 35 | ss.expunge(object()) 36 | ss.expunge_all() 37 | ss.flush() 38 | ss.get(object, 1) 39 | b = ss.get_bind() 40 | ss.is_modified(object()) 41 | ss.bulk_save_objects([]) 42 | ss.bulk_insert_mappings(inspect(X), []) 43 | ss.bulk_update_mappings(inspect(X), []) 44 | ss.merge(object()) 45 | q = (ss.query(object),) 46 | ss.refresh(object()) 47 | ss.rollback() 48 | ss.scalar(text("select 1")) 49 | ss.bind 50 | ss.dirty 51 | ss.deleted 52 | ss.new 53 | ss.identity_map 54 | ss.is_active 55 | ss.autoflush 56 | ss.no_autoflush 57 | ss.info 58 | -------------------------------------------------------------------------------- /test/typing/plain_files/orm/write_only.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import typing 4 | 5 | from sqlalchemy import ForeignKey 6 | from sqlalchemy import select 7 | from sqlalchemy.orm import DeclarativeBase 8 | from sqlalchemy.orm import Mapped 9 | from sqlalchemy.orm import mapped_column 10 | from sqlalchemy.orm import relationship 11 | from sqlalchemy.orm import Session 12 | from sqlalchemy.orm import WriteOnlyMapped 13 | 14 | 15 | class Base(DeclarativeBase): 16 | pass 17 | 18 | 19 | class Address(Base): 20 | __tablename__ = "address" 21 | id: Mapped[int] = mapped_column(primary_key=True) 22 | user_id: Mapped[int] = mapped_column(ForeignKey("user.id")) 23 | email_address: Mapped[str] 24 | 25 | 26 | class User(Base): 27 | __tablename__ = "user" 28 | id: Mapped[int] = mapped_column(primary_key=True) 29 | addresses: WriteOnlyMapped[Address] = relationship() 30 | 31 | 32 | with Session() as session: 33 | u = User() 34 | session.add(u) 35 | session.commit() 36 | 37 | if typing.TYPE_CHECKING: 38 | # EXPECTED_TYPE: WriteOnlyCollection[Address] 39 | reveal_type(u.addresses) 40 | 41 | address = session.scalars( 42 | u.addresses.select().filter(Address.email_address.like("xyz")) 43 | ).one() 44 | 45 | if typing.TYPE_CHECKING: 46 | # EXPECTED_TYPE: Address 47 | reveal_type(address) 48 | 49 | u.addresses.add(Address()) 50 | u.addresses.add_all([Address(), Address()]) 51 | 52 | # this should emit an error, because __iter__ is NoReturn, 53 | # however typing tools don't pick up on that right now 54 | current_addresses = list(u.addresses) 55 | 56 | u.addresses.add(Address()) 57 | 58 | session.commit() 59 | 60 | # test #9985 61 | stmt = select(User).join(User.addresses) 62 | -------------------------------------------------------------------------------- /test/typing/plain_files/sql/dml.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import Any 4 | from typing import Dict 5 | 6 | from sqlalchemy import Column 7 | from sqlalchemy import insert 8 | from sqlalchemy import Integer 9 | from sqlalchemy import MetaData 10 | from sqlalchemy import select 11 | from sqlalchemy import String 12 | from sqlalchemy import Table 13 | from sqlalchemy import update 14 | from sqlalchemy.orm import DeclarativeBase 15 | from sqlalchemy.orm import Mapped 16 | from sqlalchemy.orm import mapped_column 17 | 18 | 19 | class Base(DeclarativeBase): 20 | pass 21 | 22 | 23 | user_table = Table( 24 | "user", 25 | MetaData(), 26 | Column("id", Integer, primary_key=True), 27 | Column("data", String), 28 | ) 29 | 30 | 31 | class User(Base): 32 | __tablename__ = "user" 33 | 34 | id: Mapped[int] = mapped_column(primary_key=True) 35 | name: Mapped[str] 36 | data: Mapped[str] 37 | 38 | 39 | # test #9376 40 | d1: dict[str, Any] = {} 41 | stmt1 = insert(User).values(d1) 42 | 43 | 44 | d2: Dict[str, Any] = {} 45 | stmt2 = insert(User).values(d2) 46 | 47 | 48 | d3: Dict[Column[str], Any] = {} 49 | stmt3 = insert(User).values(d3) 50 | 51 | stmt4 = insert(User).from_select( 52 | [User.id, "name", User.__table__.c.data], 53 | select(User.id, User.name, User.data), 54 | ) 55 | 56 | 57 | # test #10353 58 | stmt5 = update(User).values({User.id: 123, User.data: "value"}) 59 | 60 | stmt6 = user_table.update().values( 61 | {user_table.c.d: 123, user_table.c.data: "value"} 62 | ) 63 | -------------------------------------------------------------------------------- /test/typing/plain_files/sql/lambda_stmt.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | from sqlalchemy import Column 6 | from sqlalchemy import create_engine 7 | from sqlalchemy import Integer 8 | from sqlalchemy import lambda_stmt 9 | from sqlalchemy import MetaData 10 | from sqlalchemy import Result 11 | from sqlalchemy import select 12 | from sqlalchemy import String 13 | from sqlalchemy import Table 14 | from sqlalchemy.orm import DeclarativeBase 15 | from sqlalchemy.orm import Mapped 16 | from sqlalchemy.orm import mapped_column 17 | 18 | 19 | class Base(DeclarativeBase): 20 | pass 21 | 22 | 23 | class User(Base): 24 | __tablename__ = "a" 25 | 26 | id: Mapped[int] = mapped_column(primary_key=True) 27 | email: Mapped[str] 28 | 29 | 30 | user_table = Table( 31 | "user_table", MetaData(), Column("id", Integer), Column("email", String) 32 | ) 33 | 34 | 35 | s1 = select(user_table).where(lambda: user_table.c.id == 5) 36 | 37 | s2 = select(User).where(lambda: User.id == 5) 38 | 39 | s3 = lambda_stmt(lambda: select(user_table).where(user_table.c.id == 5)) 40 | 41 | s4 = lambda_stmt(lambda: select(User).where(User.id == 5)) 42 | 43 | s5 = lambda_stmt(lambda: select(user_table)) + ( 44 | lambda s: s.where(user_table.c.id == 5) 45 | ) 46 | 47 | s6 = lambda_stmt(lambda: select(User)) + (lambda s: s.where(User.id == 5)) 48 | 49 | 50 | if TYPE_CHECKING: 51 | # EXPECTED_TYPE: StatementLambdaElement 52 | reveal_type(s5) 53 | 54 | # EXPECTED_TYPE: StatementLambdaElement 55 | reveal_type(s6) 56 | 57 | 58 | e = create_engine("sqlite://") 59 | 60 | with e.connect() as conn: 61 | result = conn.execute(s6) 62 | 63 | if TYPE_CHECKING: 64 | # EXPECTED_TYPE: CursorResult[Unpack[.*tuple[Any, ...]]] 65 | reveal_type(result) 66 | 67 | # we can type these like this 68 | my_result: Result[User] = conn.execute(s6) 69 | 70 | if TYPE_CHECKING: 71 | # pyright and mypy disagree on the specific type here, 72 | # mypy sees Result as we said, pyright seems to upgrade it to 73 | # CursorResult 74 | # EXPECTED_RE_TYPE: .*(?:Cursor)?Result\[.*User\] 75 | reveal_type(my_result) 76 | -------------------------------------------------------------------------------- /test/typing/plain_files/sql/lowercase_objects.py: -------------------------------------------------------------------------------- 1 | # PYTHON_VERSION >= 3.10 2 | 3 | import sqlalchemy as sa 4 | 5 | Book = sa.table( 6 | "book", 7 | sa.column("id", sa.Integer), 8 | sa.column("name", sa.String), 9 | ) 10 | Book.append_column(sa.column("other")) 11 | Book.corresponding_column(Book.c.id) 12 | 13 | values = sa.values( 14 | sa.column("id", sa.Integer), sa.column("name", sa.String), name="my_values" 15 | ) 16 | value_expr = values.data([(1, "name1"), (2, "name2"), (3, "name3")]) 17 | 18 | data: list[tuple[int, str]] = [(1, "name1"), (2, "name2"), (3, "name3")] 19 | value_expr2 = values.data(data) 20 | 21 | sa.select(Book) 22 | sa.select(sa.literal_column("42"), sa.column("foo")).select_from(sa.table("t")) 23 | -------------------------------------------------------------------------------- /test/typing/plain_files/sql/misc.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | from sqlalchemy import column 4 | from sqlalchemy import ColumnElement 5 | from sqlalchemy import Integer 6 | from sqlalchemy import literal 7 | from sqlalchemy import table 8 | 9 | 10 | def test_col_accessors() -> None: 11 | t = table("t", column("a"), column("b"), column("c")) 12 | 13 | t.c.a 14 | t.c["a"] 15 | 16 | t.c[2] 17 | t.c[0, 1] 18 | t.c[0, 1, "b", "c"] 19 | t.c[(0, 1, "b", "c")] 20 | 21 | t.c[:-1] 22 | t.c[0:2] 23 | 24 | 25 | def test_col_get() -> None: 26 | col_id = column("id", Integer) 27 | col_alt = column("alt", Integer) 28 | tbl = table("mytable", col_id) 29 | 30 | # EXPECTED_TYPE: Union[ColumnClause[Any], None] 31 | reveal_type(tbl.c.get("id")) 32 | # EXPECTED_TYPE: Union[ColumnClause[Any], None] 33 | reveal_type(tbl.c.get("id", None)) 34 | # EXPECTED_TYPE: Union[ColumnClause[Any], ColumnClause[int]] 35 | reveal_type(tbl.c.get("alt", col_alt)) 36 | col: ColumnElement[Any] = tbl.c.get("foo", literal("bar")) 37 | print(col) 38 | -------------------------------------------------------------------------------- /test/typing/plain_files/sql/schema.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | 3 | from sqlalchemy import CheckConstraint 4 | from sqlalchemy import Constraint 5 | from sqlalchemy import Index 6 | from sqlalchemy import MetaData 7 | from sqlalchemy import Table 8 | 9 | MetaData( 10 | naming_convention={ 11 | "ix": "ix_%(column_0_label)s", 12 | "uq": "uq_%(table_name)s_%(column_0_name)s", 13 | "ck": "ck_%(table_name)s_%(constraint_name)s", 14 | "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", 15 | "pk": "pk_%(table_name)s", 16 | } 17 | ) 18 | 19 | 20 | MetaData(naming_convention={"uq": "uq_%(table_name)s_%(column_0_N_name)s"}) 21 | 22 | 23 | def fk_guid(constraint: Union[Constraint, Index], table: Table) -> str: 24 | return "foo" 25 | 26 | 27 | MetaData( 28 | naming_convention={ 29 | "fk_guid": fk_guid, 30 | "ix": "ix_%(column_0_label)s", 31 | "fk": "fk_%(fk_guid)s", 32 | "foo": lambda c, t: t.name + str(c.name), 33 | } 34 | ) 35 | 36 | NAMING_CONVENTIONS_ONLY_CALLABLE = { 37 | "fk_guid": fk_guid, 38 | "foo": lambda c, t: t.name + str(c.name), 39 | } 40 | 41 | MetaData(naming_convention=NAMING_CONVENTIONS_ONLY_CALLABLE) 42 | 43 | NAMING_CONVENTIONS_TYPES_FOR_KEYS_ONLY = { 44 | CheckConstraint: "%(table_name)s_%(constraint_name)s_ck", 45 | Index: "%(column_0_label)s_ix", 46 | } 47 | 48 | MetaData(naming_convention=NAMING_CONVENTIONS_TYPES_FOR_KEYS_ONLY) 49 | 50 | NAMING_CONVENTIONS_TYPES_AND_STR_FOR_KEYS = { 51 | CheckConstraint: "%(table_name)s_%(constraint_name)s_ck", 52 | Index: "%(column_0_label)s_ix", 53 | "custom": "custom", 54 | "fk": "fk_name", 55 | } 56 | 57 | MetaData(naming_convention=NAMING_CONVENTIONS_TYPES_AND_STR_FOR_KEYS) 58 | 59 | 60 | NAMING_CONVENTIONS_STR = { 61 | "ix": "%(column_0_label)s_ix", 62 | "uq": "%(table_name)s_%(column_0_name)s_uq", 63 | "ck": "%(table_name)s_%(constraint_name)s_ck", 64 | "fk": "%(table_name)s_%(column_0_name)s_%(referred_table_name)s_fk", 65 | "pk": "%(table_name)s_pk", 66 | } 67 | 68 | MetaData(naming_convention=NAMING_CONVENTIONS_STR) 69 | -------------------------------------------------------------------------------- /test/typing/plain_files/sql/sqltypes.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import Float 2 | from sqlalchemy import Numeric 3 | 4 | # EXPECTED_TYPE: Float[float] 5 | reveal_type(Float()) 6 | # EXPECTED_TYPE: Float[Decimal] 7 | reveal_type(Float(asdecimal=True)) 8 | 9 | # EXPECTED_TYPE: Numeric[Decimal] 10 | reveal_type(Numeric()) 11 | # EXPECTED_TYPE: Numeric[float] 12 | reveal_type(Numeric(asdecimal=False)) 13 | -------------------------------------------------------------------------------- /test/typing/test_mypy.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from sqlalchemy import testing 4 | from sqlalchemy.testing import fixtures 5 | 6 | 7 | class MypyPlainTest(fixtures.MypyTest): 8 | @testing.combinations( 9 | *( 10 | (os.path.basename(path), path) 11 | for path in fixtures.MypyTest.file_combinations("plain_files") 12 | ), 13 | argnames="path", 14 | id_="ia", 15 | ) 16 | def test_mypy_no_plugin(self, mypy_typecheck_file, path): 17 | mypy_typecheck_file(path) 18 | -------------------------------------------------------------------------------- /tools/walk_packages.py: -------------------------------------------------------------------------------- 1 | import pkgutil 2 | 3 | import sqlalchemy 4 | 5 | list(pkgutil.walk_packages(sqlalchemy.__path__, sqlalchemy.__name__ + ".")) 6 | --------------------------------------------------------------------------------