SQLAlchemy-Utils 0.42.0__tar.gz → 0.43.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/CHANGES.rst +20 -0
- {sqlalchemy_utils-0.42.0/SQLAlchemy_Utils.egg-info → sqlalchemy_utils-0.43.0}/PKG-INFO +6 -20
- sqlalchemy_utils-0.43.0/README.rst +12 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0/SQLAlchemy_Utils.egg-info}/PKG-INFO +6 -20
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/SQLAlchemy_Utils.egg-info/requires.txt +3 -7
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/docs/installation.rst +1 -6
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/pyproject.toml +6 -10
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/__init__.py +1 -1
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/functions/database.py +2 -8
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/functions/mock.py +1 -4
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/functions/orm.py +9 -22
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/functions/sort_query.py +1 -4
- sqlalchemy_utils-0.43.0/sqlalchemy_utils/generic.py +146 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/listeners.py +3 -1
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/choice.py +3 -3
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/password.py +4 -2
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/uuid.py +2 -13
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/conftest.py +1 -1
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_database.py +0 -4
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/generic_relationship/__init__.py +46 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/test_instant_defaults_listener.py +19 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_choice.py +63 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_json.py +1 -4
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_password.py +31 -1
- sqlalchemy_utils-0.42.0/README.rst +0 -22
- sqlalchemy_utils-0.42.0/sqlalchemy_utils/generic.py +0 -200
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/LICENSE +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/MANIFEST.in +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/SQLAlchemy_Utils.egg-info/SOURCES.txt +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/SQLAlchemy_Utils.egg-info/dependency_links.txt +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/SQLAlchemy_Utils.egg-info/top_level.txt +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/docs/aggregates.rst +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/docs/conf.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/docs/data_types.rst +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/docs/database_helpers.rst +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/docs/foreign_key_helpers.rst +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/docs/generic_relationship.rst +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/docs/index.rst +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/docs/internationalization.rst +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/docs/license.rst +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/docs/listeners.rst +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/docs/models.rst +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/docs/observers.rst +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/docs/orm_helpers.rst +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/docs/range_data_types.rst +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/docs/testing.rst +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/docs/utility_classes.rst +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/docs/view.rst +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/setup.cfg +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/aggregates.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/asserts.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/compat.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/exceptions.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/expressions.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/functions/__init__.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/functions/foreign_keys.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/functions/render.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/i18n.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/models.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/observer.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/operators.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/path.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/primitives/__init__.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/primitives/country.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/primitives/currency.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/primitives/ltree.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/primitives/weekday.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/primitives/weekdays.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/proxy_dict.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/query_chain.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/relationships/__init__.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/relationships/chained_join.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/__init__.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/arrow.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/bit.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/color.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/country.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/currency.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/email.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/encrypted/__init__.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/encrypted/encrypted_type.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/encrypted/padding.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/enriched_datetime/__init__.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/enriched_datetime/arrow_datetime.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/enriched_datetime/enriched_date_type.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/enriched_datetime/enriched_datetime_type.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/enriched_datetime/pendulum_date.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/enriched_datetime/pendulum_datetime.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/ip_address.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/json.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/locale.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/ltree.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/pg_composite.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/phone_number.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/range.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/scalar_coercible.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/scalar_list.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/timezone.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/ts_vector.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/url.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/types/weekdays.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/utils.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/view.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/__init__.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/aggregate/__init__.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/aggregate/test_backrefs.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/aggregate/test_custom_select_expressions.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/aggregate/test_join_table_inheritance.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/aggregate/test_m2m.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/aggregate/test_m2m_m2m.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/aggregate/test_multiple_aggregates_per_class.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/aggregate/test_o2m_m2m.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/aggregate/test_o2m_o2m.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/aggregate/test_o2m_o2m_o2m.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/aggregate/test_search_vectors.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/aggregate/test_simple_paths.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/aggregate/test_with_column_alias.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/aggregate/test_with_ondelete_cascade.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/__init__.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_cast_if.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_dependent_objects.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_escape_like.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_get_bind.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_get_class_by_table.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_get_column_key.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_get_columns.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_get_hybrid_properties.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_get_mapper.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_get_primary_keys.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_get_referencing_foreign_keys.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_get_tables.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_get_type.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_getdotattr.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_has_changes.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_has_index.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_has_unique_index.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_identity.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_is_loaded.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_json_sql.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_jsonb_sql.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_make_order_by_deterministic.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_merge_references.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_naturally_equivalent.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_non_indexed_foreign_keys.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_quote.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_render.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/functions/test_table_name.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/generic_relationship/test_abstract_base_class.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/generic_relationship/test_column_aliases.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/generic_relationship/test_composite_keys.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/generic_relationship/test_hybrid_properties.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/generic_relationship/test_single_table_inheritance.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/mixins.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/observes/__init__.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/observes/test_column_property.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/observes/test_dynamic_relationship.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/observes/test_m2m_m2m_m2m.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/observes/test_o2m_o2m_o2m.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/observes/test_o2m_o2o_o2m.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/observes/test_o2o_o2o.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/observes/test_o2o_o2o_o2o.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/primitives/__init__.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/primitives/test_country.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/primitives/test_currency.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/primitives/test_ltree.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/primitives/test_weekdays.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/relationships/__init__.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/relationships/test_chained_join.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/relationships/test_select_correlated_expression.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/test_asserts.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/test_auto_delete_orphans.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/test_case_insensitive_comparator.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/test_expressions.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/test_instrumented_list.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/test_models.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/test_path.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/test_proxy_dict.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/test_query_chain.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/test_translation_hybrid.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/test_views.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/__init__.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/encrypted/test_padding.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_arrow.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_color.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_composite.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_country.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_currency.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_date_range.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_datetime_range.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_email.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_encrypted.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_enriched_date_pendulum.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_enriched_datetime_arrow.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_enriched_datetime_pendulum.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_int_range.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_ip_address.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_locale.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_ltree.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_numeric_range.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_phonenumber.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_scalar_list.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_timezone.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_tsvector.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_url.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_uuid.py +0 -0
- {sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/tests/types/test_weekdays.py +0 -0
|
@@ -3,6 +3,26 @@ Changelog
|
|
|
3
3
|
|
|
4
4
|
Here you can see the full list of changes between each SQLAlchemy-Utils release.
|
|
5
5
|
|
|
6
|
+
0.43.0 (2026-10-09)
|
|
7
|
+
^^^^^^^^^^^^^^^^^^^
|
|
8
|
+
|
|
9
|
+
- Add support for SQLAlchemy 2.1.
|
|
10
|
+
- Reimplement ``generic_relationship`` as a hybrid property built only on public SQLAlchemy APIs, instead of private attribute internals.
|
|
11
|
+
|
|
12
|
+
Assigning to a generic relationship now sets the discriminator and id attributes through regular attribute instrumentation, so re-assigning it on a persistent object is flushed to the database.
|
|
13
|
+
- Support querying generic relationships through aliased models, including composite keys and renamed columns.
|
|
14
|
+
- Drop support for sqlalchemy 1.4.
|
|
15
|
+
- Drop support for Python 3.9.
|
|
16
|
+
- Support Python 3.14.
|
|
17
|
+
- Fix ``ChoiceType`` returning the raw scalar instead of a ``Choice`` for falsy codes such as ``0`` or the empty string. (#813)
|
|
18
|
+
|
|
19
|
+
NULL values continue to return ``None``.
|
|
20
|
+
|
|
21
|
+
0.42.1 (2025-12-12)
|
|
22
|
+
^^^^^^^^^^^^^^^^^^^
|
|
23
|
+
|
|
24
|
+
- Fix ``AttributeError`` with Sequence defaults in ``instant_defaults_listener`` (#793)
|
|
25
|
+
|
|
6
26
|
0.42.0 (2025-08-30)
|
|
7
27
|
^^^^^^^^^^^^^^^^^^^
|
|
8
28
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: SQLAlchemy-Utils
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.43.0
|
|
4
4
|
Summary: Various utility functions for SQLAlchemy.
|
|
5
5
|
Author: Ryan Leckey, Janne Vanhala, Vesa Uimonen
|
|
6
6
|
Author-email: Konsta Vesterinen <konsta@fastmonkeys.com>
|
|
@@ -10,19 +10,19 @@ Classifier: Environment :: Web Environment
|
|
|
10
10
|
Classifier: Intended Audience :: Developers
|
|
11
11
|
Classifier: Operating System :: OS Independent
|
|
12
12
|
Classifier: Programming Language :: Python
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
14
13
|
Classifier: Programming Language :: Python :: 3.10
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.11
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
18
|
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
|
19
19
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
-
Requires-Python: >=3.
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
21
|
Description-Content-Type: text/x-rst
|
|
22
22
|
License-File: LICENSE
|
|
23
|
-
Requires-Dist: SQLAlchemy>=
|
|
23
|
+
Requires-Dist: SQLAlchemy>=2.0
|
|
24
24
|
Provides-Extra: test
|
|
25
|
-
Requires-Dist: pytest
|
|
25
|
+
Requires-Dist: pytest<10,>=9.0; extra == "test"
|
|
26
26
|
Requires-Dist: Pygments>=1.2; extra == "test"
|
|
27
27
|
Requires-Dist: Jinja2>=2.3; extra == "test"
|
|
28
28
|
Requires-Dist: docutils>=0.10; extra == "test"
|
|
@@ -34,8 +34,6 @@ Requires-Dist: pg8000>=1.12.4; extra == "test"
|
|
|
34
34
|
Requires-Dist: pytz>=2014.2; extra == "test"
|
|
35
35
|
Requires-Dist: python-dateutil>=2.6; extra == "test"
|
|
36
36
|
Requires-Dist: pymysql; extra == "test"
|
|
37
|
-
Requires-Dist: flake8>=2.4.0; extra == "test"
|
|
38
|
-
Requires-Dist: isort>=4.2.2; extra == "test"
|
|
39
37
|
Requires-Dist: pyodbc; extra == "test"
|
|
40
38
|
Provides-Extra: babel
|
|
41
39
|
Requires-Dist: Babel>=1.3; extra == "babel"
|
|
@@ -58,7 +56,7 @@ Requires-Dist: furl>=0.4.1; extra == "url"
|
|
|
58
56
|
Provides-Extra: encrypted
|
|
59
57
|
Requires-Dist: cryptography>=0.6; extra == "encrypted"
|
|
60
58
|
Provides-Extra: test-all
|
|
61
|
-
Requires-Dist: pytest
|
|
59
|
+
Requires-Dist: pytest<10,>=9.0; extra == "test-all"
|
|
62
60
|
Requires-Dist: Pygments>=1.2; extra == "test-all"
|
|
63
61
|
Requires-Dist: Jinja2>=2.3; extra == "test-all"
|
|
64
62
|
Requires-Dist: docutils>=0.10; extra == "test-all"
|
|
@@ -70,8 +68,6 @@ Requires-Dist: pg8000>=1.12.4; extra == "test-all"
|
|
|
70
68
|
Requires-Dist: pytz>=2014.2; extra == "test-all"
|
|
71
69
|
Requires-Dist: python-dateutil>=2.6; extra == "test-all"
|
|
72
70
|
Requires-Dist: pymysql; extra == "test-all"
|
|
73
|
-
Requires-Dist: flake8>=2.4.0; extra == "test-all"
|
|
74
|
-
Requires-Dist: isort>=4.2.2; extra == "test-all"
|
|
75
71
|
Requires-Dist: pyodbc; extra == "test-all"
|
|
76
72
|
Requires-Dist: Babel>=1.3; extra == "test-all"
|
|
77
73
|
Requires-Dist: arrow>=0.3.4; extra == "test-all"
|
|
@@ -88,8 +84,6 @@ Dynamic: license-file
|
|
|
88
84
|
SQLAlchemy-Utils
|
|
89
85
|
================
|
|
90
86
|
|
|
91
|
-
|Build| |Version Status| |Downloads|
|
|
92
|
-
|
|
93
87
|
Various utility functions, new data types and helpers for SQLAlchemy.
|
|
94
88
|
|
|
95
89
|
|
|
@@ -99,11 +93,3 @@ Resources
|
|
|
99
93
|
- `Documentation <https://sqlalchemy-utils.readthedocs.io/>`_
|
|
100
94
|
- `Issue Tracker <https://github.com/kvesteri/sqlalchemy-utils/issues>`_
|
|
101
95
|
- `Code <https://github.com/kvesteri/sqlalchemy-utils/>`_
|
|
102
|
-
|
|
103
|
-
.. |Build| image:: https://github.com/kvesteri/sqlalchemy-utils/actions/workflows/test.yaml/badge.svg?branch=master
|
|
104
|
-
:target: https://github.com/kvesteri/sqlalchemy-utils/actions/workflows/test.yaml
|
|
105
|
-
:alt: Tests
|
|
106
|
-
.. |Version Status| image:: https://img.shields.io/pypi/v/SQLAlchemy-Utils.svg
|
|
107
|
-
:target: https://pypi.python.org/pypi/SQLAlchemy-Utils/
|
|
108
|
-
.. |Downloads| image:: https://img.shields.io/pypi/dm/SQLAlchemy-Utils.svg
|
|
109
|
-
:target: https://pypi.python.org/pypi/SQLAlchemy-Utils/
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
SQLAlchemy-Utils
|
|
2
|
+
================
|
|
3
|
+
|
|
4
|
+
Various utility functions, new data types and helpers for SQLAlchemy.
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
Resources
|
|
8
|
+
---------
|
|
9
|
+
|
|
10
|
+
- `Documentation <https://sqlalchemy-utils.readthedocs.io/>`_
|
|
11
|
+
- `Issue Tracker <https://github.com/kvesteri/sqlalchemy-utils/issues>`_
|
|
12
|
+
- `Code <https://github.com/kvesteri/sqlalchemy-utils/>`_
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: SQLAlchemy-Utils
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.43.0
|
|
4
4
|
Summary: Various utility functions for SQLAlchemy.
|
|
5
5
|
Author: Ryan Leckey, Janne Vanhala, Vesa Uimonen
|
|
6
6
|
Author-email: Konsta Vesterinen <konsta@fastmonkeys.com>
|
|
@@ -10,19 +10,19 @@ Classifier: Environment :: Web Environment
|
|
|
10
10
|
Classifier: Intended Audience :: Developers
|
|
11
11
|
Classifier: Operating System :: OS Independent
|
|
12
12
|
Classifier: Programming Language :: Python
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
14
13
|
Classifier: Programming Language :: Python :: 3.10
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.11
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
18
|
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
|
19
19
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
-
Requires-Python: >=3.
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
21
|
Description-Content-Type: text/x-rst
|
|
22
22
|
License-File: LICENSE
|
|
23
|
-
Requires-Dist: SQLAlchemy>=
|
|
23
|
+
Requires-Dist: SQLAlchemy>=2.0
|
|
24
24
|
Provides-Extra: test
|
|
25
|
-
Requires-Dist: pytest
|
|
25
|
+
Requires-Dist: pytest<10,>=9.0; extra == "test"
|
|
26
26
|
Requires-Dist: Pygments>=1.2; extra == "test"
|
|
27
27
|
Requires-Dist: Jinja2>=2.3; extra == "test"
|
|
28
28
|
Requires-Dist: docutils>=0.10; extra == "test"
|
|
@@ -34,8 +34,6 @@ Requires-Dist: pg8000>=1.12.4; extra == "test"
|
|
|
34
34
|
Requires-Dist: pytz>=2014.2; extra == "test"
|
|
35
35
|
Requires-Dist: python-dateutil>=2.6; extra == "test"
|
|
36
36
|
Requires-Dist: pymysql; extra == "test"
|
|
37
|
-
Requires-Dist: flake8>=2.4.0; extra == "test"
|
|
38
|
-
Requires-Dist: isort>=4.2.2; extra == "test"
|
|
39
37
|
Requires-Dist: pyodbc; extra == "test"
|
|
40
38
|
Provides-Extra: babel
|
|
41
39
|
Requires-Dist: Babel>=1.3; extra == "babel"
|
|
@@ -58,7 +56,7 @@ Requires-Dist: furl>=0.4.1; extra == "url"
|
|
|
58
56
|
Provides-Extra: encrypted
|
|
59
57
|
Requires-Dist: cryptography>=0.6; extra == "encrypted"
|
|
60
58
|
Provides-Extra: test-all
|
|
61
|
-
Requires-Dist: pytest
|
|
59
|
+
Requires-Dist: pytest<10,>=9.0; extra == "test-all"
|
|
62
60
|
Requires-Dist: Pygments>=1.2; extra == "test-all"
|
|
63
61
|
Requires-Dist: Jinja2>=2.3; extra == "test-all"
|
|
64
62
|
Requires-Dist: docutils>=0.10; extra == "test-all"
|
|
@@ -70,8 +68,6 @@ Requires-Dist: pg8000>=1.12.4; extra == "test-all"
|
|
|
70
68
|
Requires-Dist: pytz>=2014.2; extra == "test-all"
|
|
71
69
|
Requires-Dist: python-dateutil>=2.6; extra == "test-all"
|
|
72
70
|
Requires-Dist: pymysql; extra == "test-all"
|
|
73
|
-
Requires-Dist: flake8>=2.4.0; extra == "test-all"
|
|
74
|
-
Requires-Dist: isort>=4.2.2; extra == "test-all"
|
|
75
71
|
Requires-Dist: pyodbc; extra == "test-all"
|
|
76
72
|
Requires-Dist: Babel>=1.3; extra == "test-all"
|
|
77
73
|
Requires-Dist: arrow>=0.3.4; extra == "test-all"
|
|
@@ -88,8 +84,6 @@ Dynamic: license-file
|
|
|
88
84
|
SQLAlchemy-Utils
|
|
89
85
|
================
|
|
90
86
|
|
|
91
|
-
|Build| |Version Status| |Downloads|
|
|
92
|
-
|
|
93
87
|
Various utility functions, new data types and helpers for SQLAlchemy.
|
|
94
88
|
|
|
95
89
|
|
|
@@ -99,11 +93,3 @@ Resources
|
|
|
99
93
|
- `Documentation <https://sqlalchemy-utils.readthedocs.io/>`_
|
|
100
94
|
- `Issue Tracker <https://github.com/kvesteri/sqlalchemy-utils/issues>`_
|
|
101
95
|
- `Code <https://github.com/kvesteri/sqlalchemy-utils/>`_
|
|
102
|
-
|
|
103
|
-
.. |Build| image:: https://github.com/kvesteri/sqlalchemy-utils/actions/workflows/test.yaml/badge.svg?branch=master
|
|
104
|
-
:target: https://github.com/kvesteri/sqlalchemy-utils/actions/workflows/test.yaml
|
|
105
|
-
:alt: Tests
|
|
106
|
-
.. |Version Status| image:: https://img.shields.io/pypi/v/SQLAlchemy-Utils.svg
|
|
107
|
-
:target: https://pypi.python.org/pypi/SQLAlchemy-Utils/
|
|
108
|
-
.. |Downloads| image:: https://img.shields.io/pypi/dm/SQLAlchemy-Utils.svg
|
|
109
|
-
:target: https://pypi.python.org/pypi/SQLAlchemy-Utils/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
SQLAlchemy>=
|
|
1
|
+
SQLAlchemy>=2.0
|
|
2
2
|
|
|
3
3
|
[arrow]
|
|
4
4
|
arrow>=0.3.4
|
|
@@ -25,7 +25,7 @@ pendulum>=2.0.5
|
|
|
25
25
|
phonenumbers>=5.9.2
|
|
26
26
|
|
|
27
27
|
[test]
|
|
28
|
-
pytest
|
|
28
|
+
pytest<10,>=9.0
|
|
29
29
|
Pygments>=1.2
|
|
30
30
|
Jinja2>=2.3
|
|
31
31
|
docutils>=0.10
|
|
@@ -37,12 +37,10 @@ pg8000>=1.12.4
|
|
|
37
37
|
pytz>=2014.2
|
|
38
38
|
python-dateutil>=2.6
|
|
39
39
|
pymysql
|
|
40
|
-
flake8>=2.4.0
|
|
41
|
-
isort>=4.2.2
|
|
42
40
|
pyodbc
|
|
43
41
|
|
|
44
42
|
[test_all]
|
|
45
|
-
pytest
|
|
43
|
+
pytest<10,>=9.0
|
|
46
44
|
Pygments>=1.2
|
|
47
45
|
Jinja2>=2.3
|
|
48
46
|
docutils>=0.10
|
|
@@ -54,8 +52,6 @@ pg8000>=1.12.4
|
|
|
54
52
|
pytz>=2014.2
|
|
55
53
|
python-dateutil>=2.6
|
|
56
54
|
pymysql
|
|
57
|
-
flake8>=2.4.0
|
|
58
|
-
isort>=4.2.2
|
|
59
55
|
pyodbc
|
|
60
56
|
Babel>=1.3
|
|
61
57
|
arrow>=0.3.4
|
|
@@ -6,12 +6,7 @@ This part of the documentation covers the installation of SQLAlchemy-Utils.
|
|
|
6
6
|
Supported platforms
|
|
7
7
|
-------------------
|
|
8
8
|
|
|
9
|
-
SQLAlchemy-Utils is
|
|
10
|
-
|
|
11
|
-
- CPython 3.9
|
|
12
|
-
- CPython 3.10
|
|
13
|
-
- CPython 3.11
|
|
14
|
-
- CPython 3.12
|
|
9
|
+
SQLAlchemy-Utils is tested against supported CPython versions.
|
|
15
10
|
|
|
16
11
|
|
|
17
12
|
Installing an official release
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "SQLAlchemy-Utils"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.43.0"
|
|
8
8
|
description = "Various utility functions for SQLAlchemy."
|
|
9
9
|
readme = "README.rst"
|
|
10
10
|
license = "BSD-3-Clause"
|
|
@@ -14,22 +14,22 @@ authors = [
|
|
|
14
14
|
{name = "Janne Vanhala"},
|
|
15
15
|
{name = "Vesa Uimonen"}
|
|
16
16
|
]
|
|
17
|
-
requires-python = ">=3.
|
|
17
|
+
requires-python = ">=3.10"
|
|
18
18
|
classifiers = [
|
|
19
19
|
"Environment :: Web Environment",
|
|
20
20
|
"Intended Audience :: Developers",
|
|
21
21
|
"Operating System :: OS Independent",
|
|
22
22
|
"Programming Language :: Python",
|
|
23
|
-
"Programming Language :: Python :: 3.9",
|
|
24
23
|
"Programming Language :: Python :: 3.10",
|
|
25
24
|
"Programming Language :: Python :: 3.11",
|
|
26
25
|
"Programming Language :: Python :: 3.12",
|
|
27
26
|
"Programming Language :: Python :: 3.13",
|
|
27
|
+
"Programming Language :: Python :: 3.14",
|
|
28
28
|
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
|
|
29
29
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
30
30
|
]
|
|
31
31
|
dependencies = [
|
|
32
|
-
"SQLAlchemy>=
|
|
32
|
+
"SQLAlchemy>=2.0",
|
|
33
33
|
]
|
|
34
34
|
|
|
35
35
|
[project.urls]
|
|
@@ -37,7 +37,7 @@ Homepage = "https://github.com/kvesteri/sqlalchemy-utils"
|
|
|
37
37
|
|
|
38
38
|
[project.optional-dependencies]
|
|
39
39
|
test = [
|
|
40
|
-
"pytest
|
|
40
|
+
"pytest>=9.0,<10",
|
|
41
41
|
"Pygments>=1.2",
|
|
42
42
|
"Jinja2>=2.3",
|
|
43
43
|
"docutils>=0.10",
|
|
@@ -49,8 +49,6 @@ test = [
|
|
|
49
49
|
"pytz>=2014.2",
|
|
50
50
|
"python-dateutil>=2.6",
|
|
51
51
|
"pymysql",
|
|
52
|
-
"flake8>=2.4.0",
|
|
53
|
-
"isort>=4.2.2",
|
|
54
52
|
"pyodbc",
|
|
55
53
|
]
|
|
56
54
|
babel = ["Babel>=1.3"]
|
|
@@ -64,7 +62,7 @@ timezone = ["python-dateutil"]
|
|
|
64
62
|
url = ["furl >= 0.4.1"]
|
|
65
63
|
encrypted = ["cryptography>=0.6"]
|
|
66
64
|
test_all = [
|
|
67
|
-
"pytest
|
|
65
|
+
"pytest>=9.0,<10",
|
|
68
66
|
"Pygments>=1.2",
|
|
69
67
|
"Jinja2>=2.3",
|
|
70
68
|
"docutils>=0.10",
|
|
@@ -76,8 +74,6 @@ test_all = [
|
|
|
76
74
|
"pytz>=2014.2",
|
|
77
75
|
"python-dateutil>=2.6",
|
|
78
76
|
"pymysql",
|
|
79
|
-
"flake8>=2.4.0",
|
|
80
|
-
"isort>=4.2.2",
|
|
81
77
|
"pyodbc",
|
|
82
78
|
"Babel>=1.3",
|
|
83
79
|
"arrow>=0.3.4",
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import itertools
|
|
2
2
|
import os
|
|
3
3
|
from collections.abc import Mapping, Sequence
|
|
4
|
-
from copy import copy
|
|
5
4
|
|
|
6
5
|
import sqlalchemy as sa
|
|
7
6
|
from sqlalchemy.engine.url import make_url
|
|
@@ -416,13 +415,8 @@ def _set_url_database(url: sa.engine.url.URL, database):
|
|
|
416
415
|
:param database: New database to set.
|
|
417
416
|
|
|
418
417
|
"""
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
ret = url._replace(database=database)
|
|
422
|
-
else: # SQLAlchemy <1.4
|
|
423
|
-
url = copy(url)
|
|
424
|
-
url.database = database
|
|
425
|
-
ret = url
|
|
418
|
+
# Cannot use URL.set() as database may need to be set to None.
|
|
419
|
+
ret = url._replace(database=database)
|
|
426
420
|
assert ret.database == database, ret
|
|
427
421
|
return ret
|
|
428
422
|
|
|
@@ -47,10 +47,7 @@ def create_mock_engine(bind, stream=None):
|
|
|
47
47
|
def dump(*args, **kw):
|
|
48
48
|
return None
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
engine = sa.create_mock_engine(bind_url, executor=dump)
|
|
52
|
-
except AttributeError: # SQLAlchemy <1.4
|
|
53
|
-
engine = sa.create_engine(bind_url, strategy='mock', executor=dump)
|
|
50
|
+
engine = sa.create_mock_engine(bind_url, executor=dump)
|
|
54
51
|
return engine
|
|
55
52
|
|
|
56
53
|
|
|
@@ -10,10 +10,7 @@ from sqlalchemy.orm import ColumnProperty, mapperlib, RelationshipProperty
|
|
|
10
10
|
from sqlalchemy.orm.attributes import InstrumentedAttribute
|
|
11
11
|
from sqlalchemy.orm.exc import UnmappedInstanceError
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
from sqlalchemy.orm.context import _ColumnEntity, _MapperEntity
|
|
15
|
-
except ImportError: # SQLAlchemy <1.4
|
|
16
|
-
from sqlalchemy.orm.query import _ColumnEntity, _MapperEntity
|
|
13
|
+
from sqlalchemy.orm.context import _ColumnEntity, _MapperEntity
|
|
17
14
|
|
|
18
15
|
from sqlalchemy.orm.session import object_session
|
|
19
16
|
from sqlalchemy.orm.util import AliasedInsp
|
|
@@ -281,12 +278,9 @@ def get_mapper(mixed):
|
|
|
281
278
|
if isinstance(mixed, sa.orm.attributes.InstrumentedAttribute):
|
|
282
279
|
mixed = mixed.class_
|
|
283
280
|
if isinstance(mixed, sa.Table):
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
all_mappers.update(mapper_registry.mappers)
|
|
288
|
-
else: # SQLAlchemy <1.4
|
|
289
|
-
all_mappers = mapperlib._mapper_registry
|
|
281
|
+
all_mappers = set()
|
|
282
|
+
for mapper_registry in mapperlib._all_registries():
|
|
283
|
+
all_mappers.update(mapper_registry.mappers)
|
|
290
284
|
mappers = [mapper for mapper in all_mappers if mixed in mapper.tables]
|
|
291
285
|
if len(mappers) > 1:
|
|
292
286
|
raise ValueError("Multiple mappers found for table '%s'." % mixed.name)
|
|
@@ -449,11 +443,10 @@ def get_columns(mixed):
|
|
|
449
443
|
SA Table object, SA Mapper, SA declarative class, SA declarative class
|
|
450
444
|
instance or an alias of any of these objects
|
|
451
445
|
"""
|
|
446
|
+
if isinstance(mixed, sa.SelectBase):
|
|
447
|
+
return mixed.subquery().c
|
|
452
448
|
if isinstance(mixed, sa.sql.selectable.Selectable):
|
|
453
|
-
|
|
454
|
-
return mixed.selected_columns
|
|
455
|
-
except AttributeError: # SQLAlchemy <1.4
|
|
456
|
-
return mixed.c
|
|
449
|
+
return mixed.c
|
|
457
450
|
if isinstance(mixed, sa.orm.util.AliasedClass):
|
|
458
451
|
return sa.inspect(mixed).mapper.columns
|
|
459
452
|
if isinstance(mixed, sa.orm.Mapper):
|
|
@@ -520,10 +513,7 @@ def quote(mixed, ident):
|
|
|
520
513
|
|
|
521
514
|
|
|
522
515
|
def _get_query_compile_state(query):
|
|
523
|
-
|
|
524
|
-
return query._compile_state()
|
|
525
|
-
else: # SQLAlchemy <1.4
|
|
526
|
-
return query
|
|
516
|
+
return query._compile_state()
|
|
527
517
|
|
|
528
518
|
|
|
529
519
|
def get_polymorphic_mappers(mixed):
|
|
@@ -878,7 +868,4 @@ def naturally_equivalent(obj, obj2):
|
|
|
878
868
|
|
|
879
869
|
|
|
880
870
|
def _get_class_registry(class_):
|
|
881
|
-
|
|
882
|
-
return class_.registry._class_registry
|
|
883
|
-
except AttributeError: # SQLAlchemy <1.4
|
|
884
|
-
return class_._decl_class_registry
|
|
871
|
+
return class_.registry._class_registry
|
{sqlalchemy_utils-0.42.0 → sqlalchemy_utils-0.43.0}/sqlalchemy_utils/functions/sort_query.py
RENAMED
|
@@ -40,10 +40,7 @@ def make_order_by_deterministic(query):
|
|
|
40
40
|
"""
|
|
41
41
|
order_by_func = sa.asc
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
order_by_clauses = query._order_by_clauses
|
|
45
|
-
except AttributeError: # SQLAlchemy <1.4
|
|
46
|
-
order_by_clauses = query._order_by
|
|
43
|
+
order_by_clauses = query._order_by_clauses
|
|
47
44
|
if not order_by_clauses:
|
|
48
45
|
column = None
|
|
49
46
|
else:
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import builtins
|
|
2
|
+
from collections.abc import Iterable
|
|
3
|
+
|
|
4
|
+
import sqlalchemy as sa
|
|
5
|
+
from sqlalchemy.ext.hybrid import Comparator, hybrid_property
|
|
6
|
+
from sqlalchemy.orm import object_session
|
|
7
|
+
|
|
8
|
+
from .exceptions import ImproperlyConfigured
|
|
9
|
+
from .functions import identity
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class GenericComparator(Comparator):
|
|
13
|
+
def __init__(self, relationship, cls):
|
|
14
|
+
self.relationship = relationship
|
|
15
|
+
self.cls = cls
|
|
16
|
+
|
|
17
|
+
def __clause_element__(self):
|
|
18
|
+
raise NotImplementedError(
|
|
19
|
+
'A generic relationship can only be compared against a model '
|
|
20
|
+
'instance or with is_type().'
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
def __eq__(self, other):
|
|
24
|
+
discriminator, ids = self.relationship._attributes(self.cls)
|
|
25
|
+
q = discriminator == type(other).__name__
|
|
26
|
+
for column, value in zip(ids, identity(other)):
|
|
27
|
+
q &= column == value
|
|
28
|
+
return q
|
|
29
|
+
|
|
30
|
+
def __ne__(self, other):
|
|
31
|
+
return ~(self == other)
|
|
32
|
+
|
|
33
|
+
def is_type(self, other):
|
|
34
|
+
discriminator, _ = self.relationship._attributes(self.cls)
|
|
35
|
+
class_names = [
|
|
36
|
+
mapper.class_.__name__ for mapper in sa.inspect(other).self_and_descendants
|
|
37
|
+
]
|
|
38
|
+
return discriminator.in_(class_names)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class GenericRelationship:
|
|
42
|
+
"""A generic form of the relationship property.
|
|
43
|
+
|
|
44
|
+
Creates a 1 to many relationship between the parent model
|
|
45
|
+
and any other models using a discriminator (the class name).
|
|
46
|
+
|
|
47
|
+
Implemented as a hybrid property on top of the discriminator and id
|
|
48
|
+
attributes, so it only relies on public SQLAlchemy APIs.
|
|
49
|
+
|
|
50
|
+
:param discriminator:
|
|
51
|
+
Field to discriminate which model we are referring to.
|
|
52
|
+
:param id:
|
|
53
|
+
Field to point to the model we are referring to.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
def __init__(self, discriminator, id):
|
|
57
|
+
self.discriminator = discriminator
|
|
58
|
+
if isinstance(id, Iterable) and not isinstance(id, str):
|
|
59
|
+
self.ids = list(id)
|
|
60
|
+
else:
|
|
61
|
+
self.ids = [id]
|
|
62
|
+
# Key for caching the assigned target object on the instance dict.
|
|
63
|
+
self.cache_key = f'_generic_relationship_{builtins.id(self)}'
|
|
64
|
+
|
|
65
|
+
def _key(self, cls, column):
|
|
66
|
+
if isinstance(column, str):
|
|
67
|
+
return column
|
|
68
|
+
if isinstance(column, hybrid_property):
|
|
69
|
+
return column.__name__
|
|
70
|
+
try:
|
|
71
|
+
return sa.inspect(cls).mapper.get_property_by_column(column).key
|
|
72
|
+
except sa.orm.exc.UnmappedColumnError:
|
|
73
|
+
raise ImproperlyConfigured(
|
|
74
|
+
f'Could not find generic relationship attribute for {column!r}.'
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
def _keys(self, cls):
|
|
78
|
+
return (
|
|
79
|
+
self._key(cls, self.discriminator),
|
|
80
|
+
[self._key(cls, column) for column in self.ids],
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
def _attributes(self, cls):
|
|
84
|
+
discriminator, ids = self._keys(cls)
|
|
85
|
+
return getattr(cls, discriminator), [getattr(cls, key) for key in ids]
|
|
86
|
+
|
|
87
|
+
def _target_class(self, cls, discriminator):
|
|
88
|
+
for mapper in sa.inspect(cls).registry.mappers:
|
|
89
|
+
if mapper.class_.__name__ == discriminator:
|
|
90
|
+
return mapper.class_
|
|
91
|
+
|
|
92
|
+
def get(self, obj):
|
|
93
|
+
discriminator_key, id_keys = self._keys(type(obj))
|
|
94
|
+
discriminator = getattr(obj, discriminator_key)
|
|
95
|
+
id = tuple(getattr(obj, key) for key in id_keys)
|
|
96
|
+
|
|
97
|
+
# Return the object assigned to this relationship as long as the
|
|
98
|
+
# discriminator and id still point to it.
|
|
99
|
+
cached = obj.__dict__.get(self.cache_key)
|
|
100
|
+
if (
|
|
101
|
+
cached is not None
|
|
102
|
+
and type(cached).__name__ == discriminator
|
|
103
|
+
and identity(cached) == id
|
|
104
|
+
):
|
|
105
|
+
return cached
|
|
106
|
+
|
|
107
|
+
# Use the session the object is bound to in order to perform
|
|
108
|
+
# a lazy query for the target.
|
|
109
|
+
session = object_session(obj)
|
|
110
|
+
if session is None:
|
|
111
|
+
return None
|
|
112
|
+
|
|
113
|
+
target_class = self._target_class(type(obj), discriminator)
|
|
114
|
+
if target_class is None:
|
|
115
|
+
# Unknown discriminator; return nothing.
|
|
116
|
+
return None
|
|
117
|
+
|
|
118
|
+
return session.get(target_class, id)
|
|
119
|
+
|
|
120
|
+
def set(self, obj, value):
|
|
121
|
+
discriminator_key, id_keys = self._keys(type(obj))
|
|
122
|
+
obj.__dict__[self.cache_key] = value
|
|
123
|
+
|
|
124
|
+
if value is None:
|
|
125
|
+
# Nullify relationship args
|
|
126
|
+
for key in id_keys:
|
|
127
|
+
setattr(obj, key, None)
|
|
128
|
+
setattr(obj, discriminator_key, None)
|
|
129
|
+
else:
|
|
130
|
+
for key, pk in zip(id_keys, identity(value)):
|
|
131
|
+
setattr(obj, key, pk)
|
|
132
|
+
setattr(obj, discriminator_key, type(value).__name__)
|
|
133
|
+
|
|
134
|
+
def comparator(self, cls):
|
|
135
|
+
return GenericComparator(self, cls)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def generic_relationship(discriminator, id, doc=None):
|
|
139
|
+
relationship = GenericRelationship(discriminator, id)
|
|
140
|
+
prop = hybrid_property(
|
|
141
|
+
relationship.get,
|
|
142
|
+
relationship.set,
|
|
143
|
+
custom_comparator=relationship.comparator,
|
|
144
|
+
)
|
|
145
|
+
prop.__doc__ = doc
|
|
146
|
+
return prop
|
|
@@ -24,7 +24,9 @@ def instant_defaults_listener(target, args, kwargs):
|
|
|
24
24
|
|
|
25
25
|
for key, column in sa.inspect(target.__class__).columns.items():
|
|
26
26
|
if hasattr(column, 'default') and column.default is not None:
|
|
27
|
-
if
|
|
27
|
+
if not hasattr(column.default, 'arg'):
|
|
28
|
+
continue
|
|
29
|
+
elif callable(column.default.arg):
|
|
28
30
|
kwargs[key] = column.default.arg(target)
|
|
29
31
|
else:
|
|
30
32
|
kwargs[key] = column.default.arg
|
|
@@ -183,9 +183,9 @@ class ChoiceTypeImpl:
|
|
|
183
183
|
return value
|
|
184
184
|
|
|
185
185
|
def process_result_value(self, value, dialect):
|
|
186
|
-
if value:
|
|
187
|
-
return
|
|
188
|
-
return value
|
|
186
|
+
if value is None:
|
|
187
|
+
return None
|
|
188
|
+
return Choice(value, self.choices_dict[value])
|
|
189
189
|
|
|
190
190
|
|
|
191
191
|
class EnumTypeImpl:
|
|
@@ -42,8 +42,10 @@ class Password(Mutable):
|
|
|
42
42
|
|
|
43
43
|
def __eq__(self, value):
|
|
44
44
|
if self.hash is None or value is None:
|
|
45
|
-
#
|
|
46
|
-
|
|
45
|
+
# If either the hash or the value is None,
|
|
46
|
+
# equivalence depends on *all* values being None,
|
|
47
|
+
# including the secret.
|
|
48
|
+
return self.hash is None and self.secret is None and value is None
|
|
47
49
|
|
|
48
50
|
if isinstance(value, Password):
|
|
49
51
|
# Comparing 2 hashes isn't very useful; but this equality
|
|
@@ -3,11 +3,8 @@ import uuid
|
|
|
3
3
|
from sqlalchemy import types, util
|
|
4
4
|
from sqlalchemy.dialects import mssql, postgresql
|
|
5
5
|
|
|
6
|
-
from ..compat import get_sqlalchemy_version
|
|
7
6
|
from .scalar_coercible import ScalarCoercible
|
|
8
7
|
|
|
9
|
-
sqlalchemy_version = get_sqlalchemy_version()
|
|
10
|
-
|
|
11
8
|
|
|
12
9
|
class UUIDType(ScalarCoercible, types.TypeDecorator):
|
|
13
10
|
"""
|
|
@@ -71,16 +68,8 @@ class UUIDType(ScalarCoercible, types.TypeDecorator):
|
|
|
71
68
|
|
|
72
69
|
return value
|
|
73
70
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
if sqlalchemy_version < (1, 4, 30):
|
|
77
|
-
|
|
78
|
-
def process_literal_param(self, value, dialect):
|
|
79
|
-
return f"'{value}'" if value else value
|
|
80
|
-
else:
|
|
81
|
-
|
|
82
|
-
def process_literal_param(self, value, dialect):
|
|
83
|
-
return value
|
|
71
|
+
def process_literal_param(self, value, dialect):
|
|
72
|
+
return value
|
|
84
73
|
|
|
85
74
|
def process_bind_param(self, value, dialect):
|
|
86
75
|
if value is None:
|
|
@@ -64,7 +64,7 @@ def mysql_db_user():
|
|
|
64
64
|
def postgresql_dsn(
|
|
65
65
|
postgresql_db_user, postgresql_db_password, postgresql_db_host, db_name
|
|
66
66
|
):
|
|
67
|
-
return 'postgresql://{}:{}@{}/{}'.format(
|
|
67
|
+
return 'postgresql+psycopg2://{}:{}@{}/{}'.format(
|
|
68
68
|
postgresql_db_user, postgresql_db_password, postgresql_db_host, db_name
|
|
69
69
|
)
|
|
70
70
|
|