diff --git a/django_tidb/base.py b/django_tidb/base.py index 5a40850..191c8f1 100644 --- a/django_tidb/base.py +++ b/django_tidb/base.py @@ -31,8 +31,8 @@ class DatabaseWrapper(MysqlDatabaseWrapper): - vendor = 'tidb' - display_name = 'TiDB' + vendor = "tidb" + display_name = "TiDB" SchemaEditorClass = DatabaseSchemaEditor # Classes instantiated in __init__(). @@ -43,10 +43,12 @@ class DatabaseWrapper(MysqlDatabaseWrapper): @cached_property def data_type_check_constraints(self): if self.features.supports_column_check_constraints: - check_constraints = {'PositiveBigIntegerField': '`%(column)s` >= 0', - 'PositiveIntegerField': '`%(column)s` >= 0', - 'PositiveSmallIntegerField': '`%(column)s` >= 0', - 'JSONField': 'JSON_VALID(`%(column)s`)'} + check_constraints = { + "PositiveBigIntegerField": "`%(column)s` >= 0", + "PositiveIntegerField": "`%(column)s` >= 0", + "PositiveSmallIntegerField": "`%(column)s` >= 0", + "JSONField": "JSON_VALID(`%(column)s`)", + } # MariaDB < 10.4.3 doesn't automatically use the JSON_VALID as # a check constraint. return check_constraints @@ -58,36 +60,41 @@ def tidb_server_data(self): # Select some server variables and test if the time zone # definitions are installed. CONVERT_TZ returns NULL if 'UTC' # timezone isn't loaded into the mysql.time_zone table. - cursor.execute(""" + cursor.execute( + """ SELECT VERSION(), @@sql_mode, @@default_storage_engine, @@sql_auto_is_null, @@lower_case_table_names, CONVERT_TZ('2001-01-01 01:00:00', 'UTC', 'UTC') IS NOT NULL - """) + """ + ) row = cursor.fetchone() return { - 'version': row[0], - 'sql_mode': row[1], - 'default_storage_engine': row[2], - 'sql_auto_is_null': bool(row[3]), - 'lower_case_table_names': bool(row[4]), - 'has_zoneinfo_database': bool(row[5]), + "version": row[0], + "sql_mode": row[1], + "default_storage_engine": row[2], + "sql_auto_is_null": bool(row[3]), + "lower_case_table_names": bool(row[4]), + "has_zoneinfo_database": bool(row[5]), } @cached_property def tidb_server_info(self): - return self.tidb_server_data['version'] + return self.tidb_server_data["version"] @cached_property def tidb_version(self): match = server_version.match(self.tidb_server_info) if not match: - raise Exception('Unable to determine Tidb version from version string %r' % self.tidb_server_info) + raise Exception( + "Unable to determine Tidb version from version string %r" + % self.tidb_server_info + ) return server_version.version @cached_property def sql_mode(self): - sql_mode = self.tidb_server_data['sql_mode'] - return set(sql_mode.split(',') if sql_mode else ()) + sql_mode = self.tidb_server_data["sql_mode"] + return set(sql_mode.split(",") if sql_mode else ()) diff --git a/django_tidb/features.py b/django_tidb/features.py index ebebe99..7cd913c 100644 --- a/django_tidb/features.py +++ b/django_tidb/features.py @@ -30,8 +30,8 @@ class DatabaseFeatures(MysqlDatabaseFeatures): create_test_procedure_without_params_sql = None create_test_procedure_with_int_param_sql = None test_collations = { - 'ci': 'utf8mb4_general_ci', - 'non_default': 'utf8mb4_bin', + "ci": "utf8mb4_general_ci", + "non_default": "utf8mb4_bin", } @cached_property @@ -69,345 +69,312 @@ def can_release_savepoints(self): def django_test_skips(self): skips = { "This doesn't work on MySQL.": { - 'db_functions.comparison.test_greatest.GreatestTests.test_coalesce_workaround', - 'db_functions.comparison.test_least.LeastTests.test_coalesce_workaround', + "db_functions.comparison.test_greatest.GreatestTests.test_coalesce_workaround", + "db_functions.comparison.test_least.LeastTests.test_coalesce_workaround", }, "MySQL doesn't support functional indexes on a function that " "returns JSON": { - 'schema.tests.SchemaTests.test_func_index_json_key_transform', + "schema.tests.SchemaTests.test_func_index_json_key_transform", }, "MySQL supports multiplying and dividing DurationFields by a " "scalar value but it's not implemented (#25287).": { - 'expressions.tests.FTimeDeltaTests.test_durationfield_multiply_divide', + "expressions.tests.FTimeDeltaTests.test_durationfield_multiply_divide", }, "tidb": { # "Expression #5 of SELECT list is not in GROUP BY clause and contains nonaggregated column # 'test_django_tests.aggregation_regress_alfa.id' which is not functionally dependent on columns in # GROUP BY clause; this is incompatible with sql_mode=only_full_group_by" - 'aggregation.tests.AggregateTestCase.test_annotate_defer_select_related', - - 'aggregation_regress.tests.AggregationTests.test_aggregate_duplicate_columns_select_related', - 'aggregation_regress.tests.AggregationTests.test_boolean_conversion', - 'aggregation_regress.tests.AggregationTests.test_more_more', - 'aggregation_regress.tests.JoinPromotionTests.test_ticket_21150', - 'annotations.tests.NonAggregateAnnotationTestCase.test_annotation_aggregate_with_m2o', - 'defer_regress.tests.DeferAnnotateSelectRelatedTest.test_defer_annotate_select_related', - - 'queries.test_explain.ExplainTests', - 'queries.test_qs_combinators.QuerySetSetOperationTests.' - 'test_union_with_values_list_and_order_on_annotation', - 'queries.test_qs_combinators.QuerySetSetOperationTests.test_union_with_values_list_and_order', - 'queries.test_qs_combinators.QuerySetSetOperationTests.test_ordering_subqueries', - 'queries.test_qs_combinators.QuerySetSetOperationTests.test_ordering_by_f_expression_and_alias', - 'queries.test_qs_combinators.QuerySetSetOperationTests.test_ordering_by_f_expression', - 'queries.test_qs_combinators.QuerySetSetOperationTests.test_ordering_by_alias', - 'queries.test_qs_combinators.QuerySetSetOperationTests.test_ordering', - 'queries.test_qs_combinators.QuerySetSetOperationTests.test_order_by_same_type', - 'queries.test_qs_combinators.QuerySetSetOperationTests.test_combining_multiple_models', - + "aggregation.tests.AggregateTestCase.test_annotate_defer_select_related", + "aggregation_regress.tests.AggregationTests.test_aggregate_duplicate_columns_select_related", + "aggregation_regress.tests.AggregationTests.test_boolean_conversion", + "aggregation_regress.tests.AggregationTests.test_more_more", + "aggregation_regress.tests.JoinPromotionTests.test_ticket_21150", + "annotations.tests.NonAggregateAnnotationTestCase.test_annotation_aggregate_with_m2o", + "defer_regress.tests.DeferAnnotateSelectRelatedTest.test_defer_annotate_select_related", + "queries.test_explain.ExplainTests", + "queries.test_qs_combinators.QuerySetSetOperationTests." + "test_union_with_values_list_and_order_on_annotation", + "queries.test_qs_combinators.QuerySetSetOperationTests.test_union_with_values_list_and_order", + "queries.test_qs_combinators.QuerySetSetOperationTests.test_ordering_subqueries", + "queries.test_qs_combinators.QuerySetSetOperationTests.test_ordering_by_f_expression_and_alias", + "queries.test_qs_combinators.QuerySetSetOperationTests.test_ordering_by_f_expression", + "queries.test_qs_combinators.QuerySetSetOperationTests.test_ordering_by_alias", + "queries.test_qs_combinators.QuerySetSetOperationTests.test_ordering", + "queries.test_qs_combinators.QuerySetSetOperationTests.test_order_by_same_type", + "queries.test_qs_combinators.QuerySetSetOperationTests.test_combining_multiple_models", # is unrelation with tidb - 'file_uploads.tests.DirectoryCreationTests.test_readonly_root', - 'cache.tests.CacheMiddlewareTest.test_cache_page_timeout', - + "file_uploads.tests.DirectoryCreationTests.test_readonly_root", + "cache.tests.CacheMiddlewareTest.test_cache_page_timeout", # wrong test result - '.test_no_duplicates_for_non_unique_related_object_in_search_fields', - 'transaction_hooks.tests.TestConnectionOnCommit.test_inner_savepoint_does_not_affect_outer', - 'filtered_relation.tests.FilteredRelationTests.test_select_for_update', - 'filtered_relation.tests.FilteredRelationTests.test_union', - 'fixtures_regress.tests.TestFixtures.test_loaddata_raises_error_when_fixture_has_invalid_foreign_key', - 'introspection.tests.IntrospectionTests.test_get_table_description_nullable', - + ".test_no_duplicates_for_non_unique_related_object_in_search_fields", + "transaction_hooks.tests.TestConnectionOnCommit.test_inner_savepoint_does_not_affect_outer", + "filtered_relation.tests.FilteredRelationTests.test_select_for_update", + "filtered_relation.tests.FilteredRelationTests.test_union", + "fixtures_regress.tests.TestFixtures.test_loaddata_raises_error_when_fixture_has_invalid_foreign_key", + "introspection.tests.IntrospectionTests.test_get_table_description_nullable", # django.db.transaction.TransactionManagementError: An error occurred in the current transaction. You # can't execute queries until the end of the 'atomic' block. - 'transaction_hooks.tests.TestConnectionOnCommit.test_inner_savepoint_rolled_back_with_outer', - 'transaction_hooks.tests.TestConnectionOnCommit.test_discards_hooks_from_rolled_back_savepoint', - 'transaction_hooks.tests.TestConnectionOnCommit.test_inner_savepoint_rolled_back_with_outer', - + "transaction_hooks.tests.TestConnectionOnCommit.test_inner_savepoint_rolled_back_with_outer", + "transaction_hooks.tests.TestConnectionOnCommit.test_discards_hooks_from_rolled_back_savepoint", + "transaction_hooks.tests.TestConnectionOnCommit.test_inner_savepoint_rolled_back_with_outer", # AssertionError: True is not false - 'sites_tests.tests.CreateDefaultSiteTests.test_multi_db_with_router', + "sites_tests.tests.CreateDefaultSiteTests.test_multi_db_with_router", # AssertionError: {} != {'example2.com': } - 'sites_tests.tests.SitesFrameworkTests.test_clear_site_cache_domain', - + "sites_tests.tests.SitesFrameworkTests.test_clear_site_cache_domain", # AttributeError: 'NoneType' object has no attribute 'ping' - 'servers.test_liveserverthread.LiveServerThreadTest.test_closes_connections', - + "servers.test_liveserverthread.LiveServerThreadTest.test_closes_connections", # [planner:3065]Expression #1 of ORDER BY clause is not in SELECT list, references column '' which is # not in SELECT list; this is incompatible with - 'ordering.tests.OrderingTests.test_orders_nulls_first_on_filtered_subquery', - + "ordering.tests.OrderingTests.test_orders_nulls_first_on_filtered_subquery", # You have an error in your SQL syntax - 'schema.tests.SchemaTests.test_func_index_cast', - 'schema.tests.SchemaTests.test_add_field_binary', - 'schema.tests.SchemaTests.test_add_textfield_default_nullable', - 'schema.tests.SchemaTests.test_add_textfield_unhashable_default', - + "schema.tests.SchemaTests.test_func_index_cast", + "schema.tests.SchemaTests.test_add_field_binary", + "schema.tests.SchemaTests.test_add_textfield_default_nullable", + "schema.tests.SchemaTests.test_add_textfield_unhashable_default", # Unsupported modify column: this column has primary key flag - 'schema.tests.SchemaTests.test_alter_auto_field_to_char_field', - + "schema.tests.SchemaTests.test_alter_auto_field_to_char_field", # Unsupported modify column: can't remove auto_increment without @@tidb_allow_remove_auto_inc enabled - 'schema.tests.SchemaTests.test_alter_auto_field_to_integer_field', - + "schema.tests.SchemaTests.test_alter_auto_field_to_integer_field", # Found wrong number (0) of check constraints for schema_author.height - 'schema.tests.SchemaTests.test_alter_field_default_dropped', - + "schema.tests.SchemaTests.test_alter_field_default_dropped", # Unsupported modify column: can't set auto_increment - 'schema.tests.SchemaTests.test_alter_int_pk_to_autofield_pk', - 'schema.tests.SchemaTests.test_alter_int_pk_to_bigautofield_pk', - + "schema.tests.SchemaTests.test_alter_int_pk_to_autofield_pk", + "schema.tests.SchemaTests.test_alter_int_pk_to_bigautofield_pk", # Unsupported drop primary key when the table's pkIsHandle is true - 'schema.tests.SchemaTests.test_alter_int_pk_to_int_unique', - + "schema.tests.SchemaTests.test_alter_int_pk_to_int_unique", # Unsupported drop integer primary key - 'schema.tests.SchemaTests.test_alter_not_unique_field_to_primary_key', - + "schema.tests.SchemaTests.test_alter_not_unique_field_to_primary_key", # Unsupported modify column: can't set auto_increment - 'schema.tests.SchemaTests.test_alter_smallint_pk_to_smallautofield_pk', - + "schema.tests.SchemaTests.test_alter_smallint_pk_to_smallautofield_pk", # BLOB/TEXT/JSON column 'address' can't have a default value - 'schema.tests.SchemaTests.test_alter_text_field_to_not_null_with_default_value', - + "schema.tests.SchemaTests.test_alter_text_field_to_not_null_with_default_value", # Unsupported modify column: this column has primary key flag - 'schema.tests.SchemaTests.test_char_field_pk_to_auto_field', - + "schema.tests.SchemaTests.test_char_field_pk_to_auto_field", # Unsupported modify charset from utf8mb4 to utf8 - 'schema.tests.SchemaTests.test_ci_cs_db_collation', - + "schema.tests.SchemaTests.test_ci_cs_db_collation", # Unsupported drop integer primary key - 'schema.tests.SchemaTests.test_primary_key', - + "schema.tests.SchemaTests.test_primary_key", # wrong result - 'schema.tests.SchemaTests.test_alter_pk_with_self_referential_field', - 'schema.tests.SchemaTests.test_db_table', - 'schema.tests.SchemaTests.test_indexes', - 'schema.tests.SchemaTests.test_inline_fk', - 'schema.tests.SchemaTests.test_remove_constraints_capital_letters', - 'schema.tests.SchemaTests.test_remove_db_index_doesnt_remove_custom_indexes', - 'schema.tests.SchemaTests.test_rename_column_renames_deferred_sql_references', - 'schema.tests.SchemaTests.test_rename_referenced_field', - 'schema.tests.SchemaTests.test_rename_table_renames_deferred_sql_references', - 'schema.tests.SchemaTests.test_add_field_remove_field', - + "schema.tests.SchemaTests.test_alter_pk_with_self_referential_field", + "schema.tests.SchemaTests.test_db_table", + "schema.tests.SchemaTests.test_indexes", + "schema.tests.SchemaTests.test_inline_fk", + "schema.tests.SchemaTests.test_remove_constraints_capital_letters", + "schema.tests.SchemaTests.test_remove_db_index_doesnt_remove_custom_indexes", + "schema.tests.SchemaTests.test_rename_column_renames_deferred_sql_references", + "schema.tests.SchemaTests.test_rename_referenced_field", + "schema.tests.SchemaTests.test_rename_table_renames_deferred_sql_references", + "schema.tests.SchemaTests.test_add_field_remove_field", # Unknown column 'annotations_publisher.id' in 'where clause' - 'annotations.tests.NonAggregateAnnotationTestCase.test_annotation_filter_with_subquery', - + "annotations.tests.NonAggregateAnnotationTestCase.test_annotation_filter_with_subquery", # Duplicate entry 'admin' for key 'username' - 'auth_tests.test_admin_multidb.MultiDatabaseTests.test_add_view', - + "auth_tests.test_admin_multidb.MultiDatabaseTests.test_add_view", # Duplicate entry 'app_b-examplemodelb' for key 'django_content_type_app_label_model_76bd3d3b_uniq' - 'auth_tests.test_models.LoadDataWithNaturalKeysAndMultipleDatabasesTestCase' - '.test_load_data_with_user_permissions', - - 'auth_tests.test_views.ChangelistTests.test_view_user_password_is_readonly', - 'auth_tests.test_migrations.MultiDBProxyModelAppLabelTests', - 'auth_tests.test_management.GetDefaultUsernameTestCase.test_with_database', - - 'backends.base.test_base.ExecuteWrapperTests.test_nested_wrapper_invoked', - 'backends.base.test_base.ExecuteWrapperTests.test_outer_wrapper_blocks', - 'backends.tests.BackendTestCase.test_queries_limit', - 'backends.tests.FkConstraintsTests.test_check_constraints', - 'backends.tests.FkConstraintsTests.test_check_constraints_sql_keywords', - + "auth_tests.test_models.LoadDataWithNaturalKeysAndMultipleDatabasesTestCase" + ".test_load_data_with_user_permissions", + "auth_tests.test_views.ChangelistTests.test_view_user_password_is_readonly", + "auth_tests.test_migrations.MultiDBProxyModelAppLabelTests", + "auth_tests.test_management.GetDefaultUsernameTestCase.test_with_database", + "backends.base.test_base.ExecuteWrapperTests.test_nested_wrapper_invoked", + "backends.base.test_base.ExecuteWrapperTests.test_outer_wrapper_blocks", + "backends.tests.BackendTestCase.test_queries_limit", + "backends.tests.FkConstraintsTests.test_check_constraints", + "backends.tests.FkConstraintsTests.test_check_constraints_sql_keywords", # ignore multi database - 'contenttypes_tests.test_models.ContentTypesMultidbTests.test_multidb', - + "contenttypes_tests.test_models.ContentTypesMultidbTests.test_multidb", # ContentType matching query does not exist. - 'contenttypes_tests.test_models.ContentTypesTests.test_app_labeled_name', - + "contenttypes_tests.test_models.ContentTypesTests.test_app_labeled_name", # IntegrityError not raised - 'constraints.tests.CheckConstraintTests.test_database_constraint', - 'constraints.tests.CheckConstraintTests.test_database_constraint_unicode', - + "constraints.tests.CheckConstraintTests.test_database_constraint", + "constraints.tests.CheckConstraintTests.test_database_constraint_unicode", # Cannot assign "": the current database router prevents this relation. - 'prefetch_related.tests.MultiDbTests.test_using_is_honored_custom_qs', - + "prefetch_related.tests.MultiDbTests.test_using_is_honored_custom_qs", # django.http.response.Http404: No Article matches the given query. - 'get_object_or_404.tests.GetObjectOr404Tests.test_get_object_or_404', - + "get_object_or_404.tests.GetObjectOr404Tests.test_get_object_or_404", # django.db.transaction.TransactionManagementError: An error occurred in the current transaction. # You can't execute queries until the end of the 'atomic' block. - 'get_or_create.tests.UpdateOrCreateTests.test_integrity', - 'get_or_create.tests.UpdateOrCreateTests.test_manual_primary_key_test', - 'get_or_create.tests.UpdateOrCreateTestsWithManualPKs.test_create_with_duplicate_primary_key', - - 'db_functions.text.test_chr.ChrTests.test_non_ascii', - 'db_functions.text.test_sha224.SHA224Tests.test_basic', - 'db_functions.text.test_sha224.SHA224Tests.test_transform', - 'db_functions.text.test_sha256.SHA256Tests.test_basic', - 'db_functions.text.test_sha256.SHA256Tests.test_transform', - 'db_functions.text.test_sha384.SHA384Tests.test_basic', - 'db_functions.text.test_sha384.SHA384Tests.test_transform', - 'db_functions.text.test_sha512.SHA512Tests.test_basic', - 'db_functions.text.test_sha512.SHA512Tests.test_transform', - 'db_functions.comparison.test_greatest.GreatestTests.test_basic', - 'db_functions.comparison.test_least.LeastTests.test_basic', - 'db_functions.datetime.test_extract_trunc.DateFunctionTests.test_trunc_time_func', - - 'migrations.test_commands.MigrateTests.test_migrate_fake_initial_case_insensitive', - 'migrations.test_commands.MigrateTests.test_migrate_fake_split_initial', - 'migrations.test_commands.MigrateTests.test_migrate_plan', - 'migrations.test_executor.ExecutorTests.test_alter_id_type_with_fk', - 'migrations.test_operations.OperationTests.test_add_binaryfield', - 'migrations.test_operations.OperationTests.test_add_textfield', - 'migrations.test_operations.OperationTests.test_alter_field_pk', - 'migrations.test_operations.OperationTests.test_alter_field_reloads_state_on_fk_target_changes', - 'migrations.test_operations.OperationTests.test_autofield__bigautofield_foreignfield_growth', - 'migrations.test_operations.OperationTests.test_rename_field_reloads_state_on_fk_target_changes', - 'migrations.test_operations.OperationTests.test_smallfield_autofield_foreignfield_growth', - 'migrations.test_operations.OperationTests.test_smallfield_bigautofield_foreignfield_growth', - 'migrations.test_loader.RecorderTests.test_apply', - 'migrations.test_commands.MigrateTests.test_migrate_fake_initial', - 'migrations.test_commands.MigrateTests.test_migrate_initial_false', - 'migrations.test_commands.MigrateTests.test_migrate_syncdb_app_label', - 'migrations.test_commands.MigrateTests.test_migrate_syncdb_deferred_sql_executed_with_schemaeditor', - 'migrations.test_operations.OperationTests.test_add_constraint', - 'migrations.test_operations.OperationTests.test_add_constraint_combinable', - 'migrations.test_operations.OperationTests.test_add_constraint_percent_escaping', - 'migrations.test_operations.OperationTests.test_add_or_constraint', - 'migrations.test_operations.OperationTests.test_create_model_with_constraint', - 'migrations.test_operations.OperationTests.test_remove_constraint', - + "get_or_create.tests.UpdateOrCreateTests.test_integrity", + "get_or_create.tests.UpdateOrCreateTests.test_manual_primary_key_test", + "get_or_create.tests.UpdateOrCreateTestsWithManualPKs.test_create_with_duplicate_primary_key", + "db_functions.text.test_chr.ChrTests.test_non_ascii", + "db_functions.text.test_sha224.SHA224Tests.test_basic", + "db_functions.text.test_sha224.SHA224Tests.test_transform", + "db_functions.text.test_sha256.SHA256Tests.test_basic", + "db_functions.text.test_sha256.SHA256Tests.test_transform", + "db_functions.text.test_sha384.SHA384Tests.test_basic", + "db_functions.text.test_sha384.SHA384Tests.test_transform", + "db_functions.text.test_sha512.SHA512Tests.test_basic", + "db_functions.text.test_sha512.SHA512Tests.test_transform", + "db_functions.comparison.test_greatest.GreatestTests.test_basic", + "db_functions.comparison.test_least.LeastTests.test_basic", + "db_functions.datetime.test_extract_trunc.DateFunctionTests.test_trunc_time_func", + "migrations.test_commands.MigrateTests.test_migrate_fake_initial_case_insensitive", + "migrations.test_commands.MigrateTests.test_migrate_fake_split_initial", + "migrations.test_commands.MigrateTests.test_migrate_plan", + "migrations.test_executor.ExecutorTests.test_alter_id_type_with_fk", + "migrations.test_operations.OperationTests.test_add_binaryfield", + "migrations.test_operations.OperationTests.test_add_textfield", + "migrations.test_operations.OperationTests.test_alter_field_pk", + "migrations.test_operations.OperationTests.test_alter_field_reloads_state_on_fk_target_changes", + "migrations.test_operations.OperationTests.test_autofield__bigautofield_foreignfield_growth", + "migrations.test_operations.OperationTests.test_rename_field_reloads_state_on_fk_target_changes", + "migrations.test_operations.OperationTests.test_smallfield_autofield_foreignfield_growth", + "migrations.test_operations.OperationTests.test_smallfield_bigautofield_foreignfield_growth", + "migrations.test_loader.RecorderTests.test_apply", + "migrations.test_commands.MigrateTests.test_migrate_fake_initial", + "migrations.test_commands.MigrateTests.test_migrate_initial_false", + "migrations.test_commands.MigrateTests.test_migrate_syncdb_app_label", + "migrations.test_commands.MigrateTests.test_migrate_syncdb_deferred_sql_executed_with_schemaeditor", + "migrations.test_operations.OperationTests.test_add_constraint", + "migrations.test_operations.OperationTests.test_add_constraint_combinable", + "migrations.test_operations.OperationTests.test_add_constraint_percent_escaping", + "migrations.test_operations.OperationTests.test_add_or_constraint", + "migrations.test_operations.OperationTests.test_create_model_with_constraint", + "migrations.test_operations.OperationTests.test_remove_constraint", # An error occurred in the current transaction. You can't execute queries until the end of the # 'atomic' block." not found in 'Save with update_fields did not affect any rows. - 'basic.tests.SelectOnSaveTests.test_select_on_save_lying_update', - - 'admin_views.test_multidb.MultiDatabaseTests.test_add_view', - 'admin_views.test_multidb.MultiDatabaseTests.test_change_view', - 'admin_views.test_multidb.MultiDatabaseTests.test_delete_view', - 'admin_views.test_autocomplete_view.AutocompleteJsonViewTests.test_to_field_resolution_with_fk_pk', - 'admin_views.test_autocomplete_view.AutocompleteJsonViewTests.test_to_field_resolution_with_mti', - 'admin_views.tests.AdminSearchTest.test_exact_matches', - 'admin_views.tests.AdminSearchTest.test_no_total_count', - 'admin_views.tests.AdminSearchTest.test_search_on_sibling_models', - 'admin_views.tests.GroupAdminTest.test_group_permission_performance', - 'admin_views.tests.UserAdminTest.test_user_permission_performance', - - 'multiple_database.tests.AuthTestCase.test_dumpdata', - + "basic.tests.SelectOnSaveTests.test_select_on_save_lying_update", + "admin_views.test_multidb.MultiDatabaseTests.test_add_view", + "admin_views.test_multidb.MultiDatabaseTests.test_change_view", + "admin_views.test_multidb.MultiDatabaseTests.test_delete_view", + "admin_views.test_autocomplete_view.AutocompleteJsonViewTests.test_to_field_resolution_with_fk_pk", + "admin_views.test_autocomplete_view.AutocompleteJsonViewTests.test_to_field_resolution_with_mti", + "admin_views.tests.AdminSearchTest.test_exact_matches", + "admin_views.tests.AdminSearchTest.test_no_total_count", + "admin_views.tests.AdminSearchTest.test_search_on_sibling_models", + "admin_views.tests.GroupAdminTest.test_group_permission_performance", + "admin_views.tests.UserAdminTest.test_user_permission_performance", + "multiple_database.tests.AuthTestCase.test_dumpdata", # about Pessimistic/Optimistic Transaction Model - 'select_for_update.tests.SelectForUpdateTests.test_raw_lock_not_available', - + "select_for_update.tests.SelectForUpdateTests.test_raw_lock_not_available", # https://code.djangoproject.com/ticket/33627#ticket "model_forms.tests.ModelMultipleChoiceFieldTests.test_model_multiple_choice_field", - # https://code.djangoproject.com/ticket/33633#ticket # once supports_transactions is True, could be opened; same as below - 'test_utils.test_testcase.TestDataTests.test_class_attribute_identity', - 'test_utils.tests.CaptureOnCommitCallbacksTests.test_execute', - 'test_utils.tests.CaptureOnCommitCallbacksTests.test_no_arguments', - 'test_utils.tests.CaptureOnCommitCallbacksTests.test_pre_callback', - 'test_utils.tests.CaptureOnCommitCallbacksTests.test_using', - 'test_utils.tests.TestBadSetUpTestData.test_failure_in_setUpTestData_should_rollback_transaction', - } + "test_utils.test_testcase.TestDataTests.test_class_attribute_identity", + "test_utils.tests.CaptureOnCommitCallbacksTests.test_execute", + "test_utils.tests.CaptureOnCommitCallbacksTests.test_no_arguments", + "test_utils.tests.CaptureOnCommitCallbacksTests.test_pre_callback", + "test_utils.tests.CaptureOnCommitCallbacksTests.test_using", + "test_utils.tests.TestBadSetUpTestData.test_failure_in_setUpTestData_should_rollback_transaction", + }, } if int(django.__version__[0]) > 3: - skips.update({ - "django4": { - # MySQL needs a explicit CAST to ensure consistent results - 'aggregation.tests.AggregateTestCase.test_aggregation_default_using_time_from_python', - 'aggregation.tests.AggregateTestCase.test_aggregation_default_using_date_from_python', - 'aggregation.tests.AggregateTestCase.test_aggregation_default_using_datetime_from_python', - - 'migrations.test_operations.OperationTests.test_alter_field_pk_mti_and_fk_to_base', - 'migrations.test_operations.OperationTests.test_alter_field_pk_mti_fk', - # https://code.djangoproject.com/ticket/33633#ticket - # once supports_transactions is True, could be opened - 'test_utils.test_testcase.TestTestCase.test_reset_sequences', - 'test_utils.tests.CaptureOnCommitCallbacksTests.test_execute_recursive', - 'test_utils.tests.CaptureOnCommitCallbacksTests.test_execute_tree', + skips.update( + { + "django4": { + # MySQL needs a explicit CAST to ensure consistent results + "aggregation.tests.AggregateTestCase.test_aggregation_default_using_time_from_python", + "aggregation.tests.AggregateTestCase.test_aggregation_default_using_date_from_python", + "aggregation.tests.AggregateTestCase.test_aggregation_default_using_datetime_from_python", + "migrations.test_operations.OperationTests.test_alter_field_pk_mti_and_fk_to_base", + "migrations.test_operations.OperationTests.test_alter_field_pk_mti_fk", + # https://code.djangoproject.com/ticket/33633#ticket + # once supports_transactions is True, could be opened + "test_utils.test_testcase.TestTestCase.test_reset_sequences", + "test_utils.tests.CaptureOnCommitCallbacksTests.test_execute_recursive", + "test_utils.tests.CaptureOnCommitCallbacksTests.test_execute_tree", + } } - }) + ) if self.connection.tidb_version == (5, 0, 3): - skips.update({ - "tidb503": { - 'expressions_window.tests.WindowFunctionTests.test_subquery_row_range_rank', - 'schema.tests.SchemaTests.test_alter_textual_field_keep_null_status', - - # Unsupported modify column: column type conversion - # between 'varchar' and 'non-varchar' is currently unsupported yet - 'schema.tests.SchemaTests.test_alter', - 'schema.tests.SchemaTests.test_alter_field_type_and_db_collation', - 'schema.tests.SchemaTests.test_alter_textual_field_keep_null_status', + skips.update( + { + "tidb503": { + "expressions_window.tests.WindowFunctionTests.test_subquery_row_range_rank", + "schema.tests.SchemaTests.test_alter_textual_field_keep_null_status", + # Unsupported modify column: column type conversion + # between 'varchar' and 'non-varchar' is currently unsupported yet + "schema.tests.SchemaTests.test_alter", + "schema.tests.SchemaTests.test_alter_field_type_and_db_collation", + "schema.tests.SchemaTests.test_alter_textual_field_keep_null_status", + } } - }) + ) if self.connection.tidb_version == (4, 0, 0): - skips.update({ - "tidb400": { - 'admin_filters.tests.ListFiltersTests.test_relatedfieldlistfilter_reverse_relationships', - 'admin_filters.tests.ListFiltersTests.test_emptylistfieldfilter_reverse_relationships', - 'aggregation.test_filter_argument.FilteredAggregateTests.test_filtered_numerical_aggregates', - 'aggregation_regress.tests.AggregationTests.test_stddev', - 'aggregation_regress.tests.AggregationTests.test_aggregate_fexpr', - 'annotations.tests.NonAggregateAnnotationTestCase.test_raw_sql_with_inherited_field', - 'auth_tests.test_models.UserWithPermTestCase.test_basic', - 'generic_relations_regress.tests.GenericRelationTests.test_ticket_20378', - 'queries.test_bulk_update.BulkUpdateNoteTests.test_functions', - 'queries.tests.TestTicket24605.test_ticket_24605', - 'queries.tests.Queries6Tests.test_tickets_8921_9188', - 'schema.tests.SchemaTests.test_add_field_default_nullable' + skips.update( + { + "tidb400": { + "admin_filters.tests.ListFiltersTests.test_relatedfieldlistfilter_reverse_relationships", + "admin_filters.tests.ListFiltersTests.test_emptylistfieldfilter_reverse_relationships", + "aggregation.test_filter_argument.FilteredAggregateTests.test_filtered_numerical_aggregates", + "aggregation_regress.tests.AggregationTests.test_stddev", + "aggregation_regress.tests.AggregationTests.test_aggregate_fexpr", + "annotations.tests.NonAggregateAnnotationTestCase.test_raw_sql_with_inherited_field", + "auth_tests.test_models.UserWithPermTestCase.test_basic", + "generic_relations_regress.tests.GenericRelationTests.test_ticket_20378", + "queries.test_bulk_update.BulkUpdateNoteTests.test_functions", + "queries.tests.TestTicket24605.test_ticket_24605", + "queries.tests.Queries6Tests.test_tickets_8921_9188", + "schema.tests.SchemaTests.test_add_field_default_nullable", + } } - }) + ) if self.connection.tidb_version < (5,): - skips.update({ - "tidb4": { - # Unsupported modify column - 'schema.tests.SchemaTests.test_rename', - 'schema.tests.SchemaTests.test_m2m_rename_field_in_target_model', - 'schema.tests.SchemaTests.test_alter_textual_field_keep_null_status', - 'schema.tests.SchemaTests.test_alter_text_field_to_time_field', - 'schema.tests.SchemaTests.test_alter_text_field_to_datetime_field', - 'schema.tests.SchemaTests.test_alter_text_field_to_date_field', - 'schema.tests.SchemaTests.test_alter_field_type_and_db_collation', - - # wrong result - 'expressions_window.tests.WindowFunctionTests.test_subquery_row_range_rank', - - 'migrations.test_operations.OperationTests.test_alter_fk_non_fk', - 'migrations.test_operations.OperationTests' - '.test_alter_field_reloads_state_on_fk_with_to_field_target_changes', - 'model_fields.test_integerfield.PositiveIntegerFieldTests.test_negative_values', + skips.update( + { + "tidb4": { + # Unsupported modify column + "schema.tests.SchemaTests.test_rename", + "schema.tests.SchemaTests.test_m2m_rename_field_in_target_model", + "schema.tests.SchemaTests.test_alter_textual_field_keep_null_status", + "schema.tests.SchemaTests.test_alter_text_field_to_time_field", + "schema.tests.SchemaTests.test_alter_text_field_to_datetime_field", + "schema.tests.SchemaTests.test_alter_text_field_to_date_field", + "schema.tests.SchemaTests.test_alter_field_type_and_db_collation", + # wrong result + "expressions_window.tests.WindowFunctionTests.test_subquery_row_range_rank", + "migrations.test_operations.OperationTests.test_alter_fk_non_fk", + "migrations.test_operations.OperationTests" + ".test_alter_field_reloads_state_on_fk_with_to_field_target_changes", + "model_fields.test_integerfield.PositiveIntegerFieldTests.test_negative_values", + } } - }) - if self.connection.tidb_version >= (4, 0, 5) and self.connection.tidb_version <= (4, 0, 9): - skips['tidb4'].add('lookup.tests.LookupTests.test_regex') + ) + if self.connection.tidb_version >= ( + 4, + 0, + 5, + ) and self.connection.tidb_version <= (4, 0, 9): + skips["tidb4"].add("lookup.tests.LookupTests.test_regex") if django.utils.version.get_complete_version() < (4, 1): - skips.update({ - 'django40': { - 'constraints.tests.CheckConstraintTests.test_database_constraint_expression', - 'constraints.tests.CheckConstraintTests.test_database_constraint_expressionwrapper', - - # 'Unsupported modify column: this column has primary key flag - 'schema.tests.SchemaTests.test_alter_autofield_pk_to_smallautofield_pk_sequence_owner', - - 'test_utils.test_testcase.TestDataTests.test_undeepcopyable_warning', - - # RuntimeError: A durable atomic block cannot be nested within another atomic block. - 'transactions.tests.DisableDurabiltityCheckTests.test_nested_both_durable', - 'transactions.tests.DisableDurabiltityCheckTests.test_nested_inner_durable', + skips.update( + { + "django40": { + "constraints.tests.CheckConstraintTests.test_database_constraint_expression", + "constraints.tests.CheckConstraintTests.test_database_constraint_expressionwrapper", + # 'Unsupported modify column: this column has primary key flag + "schema.tests.SchemaTests.test_alter_autofield_pk_to_smallautofield_pk_sequence_owner", + "test_utils.test_testcase.TestDataTests.test_undeepcopyable_warning", + # RuntimeError: A durable atomic block cannot be nested within another atomic block. + "transactions.tests.DisableDurabiltityCheckTests.test_nested_both_durable", + "transactions.tests.DisableDurabiltityCheckTests.test_nested_inner_durable", + } } - }) + ) if django.utils.version.get_complete_version() >= (4, 1): - skips.update({ - 'django41': { - 'migrations.test_operations.OperationTests.test_create_model_with_boolean_expression_in_check_constraint', - 'migrations.test_operations.OperationTests.test_remove_func_unique_constraint', - 'migrations.test_operations.OperationTests.test_remove_func_index', - 'migrations.test_operations.OperationTests.test_alter_field_with_func_index', - 'migrations.test_operations.OperationTests.test_add_func_unique_constraint', - 'migrations.test_operations.OperationTests.test_add_func_index', - - 'schema.tests.SchemaTests.test_add_auto_field', - 'schema.tests.SchemaTests.test_add_field_o2o_nullable', - 'schema.tests.SchemaTests.test_alter_autofield_pk_to_smallautofield_pk', - 'schema.tests.SchemaTests.test_alter_primary_key_db_collation', - 'schema.tests.SchemaTests.test_alter_primary_key_the_same_name', - 'schema.tests.SchemaTests.test_autofield_to_o2o', - 'schema.tests.SchemaTests.test_func_index_lookups', - 'schema.tests.SchemaTests.test_func_unique_constraint_lookups', - - 'update.tests.AdvancedTests.test_update_ordered_by_inline_m2m_annotation', - 'update.tests.AdvancedTests.test_update_ordered_by_m2m_annotation', + skips.update( + { + "django41": { + "migrations.test_operations.OperationTests.test_create_model_with_boolean_expression_in_check_constraint", + "migrations.test_operations.OperationTests.test_remove_func_unique_constraint", + "migrations.test_operations.OperationTests.test_remove_func_index", + "migrations.test_operations.OperationTests.test_alter_field_with_func_index", + "migrations.test_operations.OperationTests.test_add_func_unique_constraint", + "migrations.test_operations.OperationTests.test_add_func_index", + "schema.tests.SchemaTests.test_add_auto_field", + "schema.tests.SchemaTests.test_add_field_o2o_nullable", + "schema.tests.SchemaTests.test_alter_autofield_pk_to_smallautofield_pk", + "schema.tests.SchemaTests.test_alter_primary_key_db_collation", + "schema.tests.SchemaTests.test_alter_primary_key_the_same_name", + "schema.tests.SchemaTests.test_autofield_to_o2o", + "schema.tests.SchemaTests.test_func_index_lookups", + "schema.tests.SchemaTests.test_func_unique_constraint_lookups", + "update.tests.AdvancedTests.test_update_ordered_by_inline_m2m_annotation", + "update.tests.AdvancedTests.test_update_ordered_by_m2m_annotation", + } } - }) + ) return skips @cached_property @@ -422,27 +389,33 @@ def can_introspect_foreign_keys(self): def can_return_columns_from_insert(self): return False - can_return_rows_from_bulk_insert = property(operator.attrgetter('can_return_columns_from_insert')) + can_return_rows_from_bulk_insert = property( + operator.attrgetter("can_return_columns_from_insert") + ) @cached_property def has_zoneinfo_database(self): - return self.connection.tidb_server_data['has_zoneinfo_database'] + return self.connection.tidb_server_data["has_zoneinfo_database"] @cached_property def is_sql_auto_is_null_enabled(self): - return self.connection.tidb_server_data['sql_auto_is_null'] + return self.connection.tidb_server_data["sql_auto_is_null"] @cached_property def supports_over_clause(self): return True - supports_frame_range_fixed_distance = property(operator.attrgetter('supports_over_clause')) + supports_frame_range_fixed_distance = property( + operator.attrgetter("supports_over_clause") + ) @cached_property def supports_column_check_constraints(self): return True - supports_table_check_constraints = property(operator.attrgetter('supports_column_check_constraints')) + supports_table_check_constraints = property( + operator.attrgetter("supports_column_check_constraints") + ) @cached_property def can_introspect_check_constraints(self): @@ -466,11 +439,11 @@ def supports_explain_analyze(self): @cached_property def supported_explain_formats(self): - return {'DOT', 'ROW', 'BRIEF'} + return {"DOT", "ROW", "BRIEF"} @cached_property def ignores_table_name_case(self): - return self.connection.tidb_server_data['lower_case_table_names'] + return self.connection.tidb_server_data["lower_case_table_names"] @cached_property def supports_default_in_lead_lag(self): @@ -490,4 +463,7 @@ def supports_index_column_ordering(self): @cached_property def supports_expression_indexes(self): - return self.connection.tidb_version >= (5, 1, ) + return self.connection.tidb_version >= ( + 5, + 1, + ) diff --git a/django_tidb/functions.py b/django_tidb/functions.py index c775909..17b20c6 100644 --- a/django_tidb/functions.py +++ b/django_tidb/functions.py @@ -19,8 +19,10 @@ def char(self, compiler, connection, **extra_context): return self.as_sql( - compiler, connection, function='CHAR', - template='%(function)s(%(expressions)s USING utf8mb4)', + compiler, + connection, + function="CHAR", + template="%(function)s(%(expressions)s USING utf8mb4)", **extra_context ) diff --git a/django_tidb/introspection.py b/django_tidb/introspection.py index ca15215..3c9b465 100644 --- a/django_tidb/introspection.py +++ b/django_tidb/introspection.py @@ -20,11 +20,13 @@ from django.db.models import Index from django.utils.datastructures import OrderedSet -FieldInfo = namedtuple('FieldInfo', BaseFieldInfo._fields + ('extra', 'is_unsigned', 'has_json_constraint')) +FieldInfo = namedtuple( + "FieldInfo", BaseFieldInfo._fields + ("extra", "is_unsigned", "has_json_constraint") +) InfoLine = namedtuple( - 'InfoLine', - 'col_name data_type max_len num_prec num_scale extra column_default ' - 'collation is_unsigned' + "InfoLine", + "col_name data_type max_len num_prec num_scale extra column_default " + "collation is_unsigned", ) @@ -38,30 +40,37 @@ def get_table_description(self, cursor, table_name): if self.connection.features.can_introspect_json_field: # JSON data type is an alias for LONGTEXT in MariaDB, select # JSON_VALID() constraints to introspect JSONField. - cursor.execute(""" + cursor.execute( + """ SELECT c.constraint_name AS column_name FROM information_schema.check_constraints AS c WHERE c.table_name = %s AND LOWER(c.check_clause) = 'json_valid(`' + LOWER(c.constraint_name) + '`)' AND c.constraint_schema = DATABASE() - """, [table_name]) + """, + [table_name], + ) json_constraints = {row[0] for row in cursor.fetchall()} # A default collation for the given table. - cursor.execute(""" + cursor.execute( + """ SELECT table_collation FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = %s - """, [table_name]) + """, + [table_name], + ) row = cursor.fetchone() - default_column_collation = row[0] if row else '' + default_column_collation = row[0] if row else "" # information_schema database gives more accurate results for some figures: # - varchar length returned by cursor.description is an internal length, # not visible length (#5725) # - precision and scale (for decimal fields) (#5014) # - auto_increment is not available in cursor.description - cursor.execute(""" + cursor.execute( + """ SELECT column_name, data_type, character_maximum_length, numeric_precision, numeric_scale, extra, column_default, @@ -75,10 +84,14 @@ def get_table_description(self, cursor, table_name): END AS is_unsigned FROM information_schema.columns WHERE table_name = %s AND table_schema = DATABASE() - """, [default_column_collation, table_name]) + """, + [default_column_collation, table_name], + ) field_info = {line[0]: InfoLine(*line) for line in cursor.fetchall()} - cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name)) + cursor.execute( + "SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name) + ) def to_int(i): return int(i) if i is not None else i @@ -86,18 +99,20 @@ def to_int(i): fields = [] for line in cursor.description: info = field_info[line[0]] - fields.append(FieldInfo( - *line[:3], - to_int(info.max_len) or line[3], - to_int(info.num_prec) or line[4], - to_int(info.num_scale) or line[5], - line[6], - info.column_default, - info.collation, - info.extra, - info.is_unsigned, - line[0] in json_constraints, - )) + fields.append( + FieldInfo( + *line[:3], + to_int(info.max_len) or line[3], + to_int(info.num_prec) or line[4], + to_int(info.num_scale) or line[5], + line[6], + info.column_default, + info.collation, + info.extra, + info.is_unsigned, + line[0] in json_constraints, + ) + ) return fields def get_constraints(self, cursor, table_name): @@ -126,20 +141,22 @@ def get_constraints(self, cursor, table_name): for constraint, column, ref_table, ref_column, kind in cursor.fetchall(): if constraint not in constraints: constraints[constraint] = { - 'columns': OrderedSet(), - 'primary_key': kind == 'PRIMARY KEY', - 'unique': kind in {'PRIMARY KEY', 'UNIQUE'}, - 'index': False, - 'check': False, - 'foreign_key': (ref_table, ref_column) if ref_column else None, + "columns": OrderedSet(), + "primary_key": kind == "PRIMARY KEY", + "unique": kind in {"PRIMARY KEY", "UNIQUE"}, + "index": False, + "check": False, + "foreign_key": (ref_table, ref_column) if ref_column else None, } if self.connection.features.supports_index_column_ordering: - constraints[constraint]['orders'] = [] - constraints[constraint]['columns'].add(column) + constraints[constraint]["orders"] = [] + constraints[constraint]["columns"].add(column) # Add check constraints. if self.connection.features.can_introspect_check_constraints: unnamed_constraints_index = 0 - columns = {info.name for info in self.get_table_description(cursor, table_name)} + columns = { + info.name for info in self.get_table_description(cursor, table_name) + } type_query = """ SELECT cc.constraint_name, cc.check_clause FROM @@ -154,42 +171,48 @@ def get_constraints(self, cursor, table_name): """ cursor.execute(type_query, [table_name]) for constraint, check_clause in cursor.fetchall(): - constraint_columns = self._parse_constraint_columns(check_clause, columns) + constraint_columns = self._parse_constraint_columns( + check_clause, columns + ) # Ensure uniqueness of unnamed constraints. Unnamed unique # and check columns constraints have the same name as # a column. if set(constraint_columns) == {constraint}: unnamed_constraints_index += 1 - constraint = '__unnamed_constraint_%s__' % unnamed_constraints_index + constraint = "__unnamed_constraint_%s__" % unnamed_constraints_index constraints[constraint] = { - 'columns': constraint_columns, - 'primary_key': False, - 'unique': False, - 'index': False, - 'check': True, - 'foreign_key': None, + "columns": constraint_columns, + "primary_key": False, + "unique": False, + "index": False, + "check": True, + "foreign_key": None, } # Now add in the indexes - cursor.execute("SHOW INDEX FROM %s" % self.connection.ops.quote_name(table_name)) + cursor.execute( + "SHOW INDEX FROM %s" % self.connection.ops.quote_name(table_name) + ) for table, non_unique, index, colseq, column, order, type_ in [ x[:6] + (x[10],) for x in cursor.fetchall() ]: if index not in constraints: constraints[index] = { - 'columns': OrderedSet(), - 'primary_key': False, - 'unique': not non_unique, - 'check': False, - 'foreign_key': None, + "columns": OrderedSet(), + "primary_key": False, + "unique": not non_unique, + "check": False, + "foreign_key": None, } if self.connection.features.supports_index_column_ordering: - constraints[index]['orders'] = [] - constraints[index]['index'] = True - constraints[index]['type'] = Index.suffix if type_ == 'BTREE' else type_.lower() - constraints[index]['columns'].add(column) + constraints[index]["orders"] = [] + constraints[index]["index"] = True + constraints[index]["type"] = ( + Index.suffix if type_ == "BTREE" else type_.lower() + ) + constraints[index]["columns"].add(column) if self.connection.features.supports_index_column_ordering: - constraints[index]['orders'].append('DESC' if order == 'D' else 'ASC') + constraints[index]["orders"].append("DESC" if order == "D" else "ASC") # Convert the sorted sets to lists for constraint in constraints.values(): - constraint['columns'] = list(constraint['columns']) + constraint["columns"] = list(constraint["columns"]) return constraints diff --git a/django_tidb/operations.py b/django_tidb/operations.py index ee5fe6a..d33fb26 100644 --- a/django_tidb/operations.py +++ b/django_tidb/operations.py @@ -22,30 +22,30 @@ def explain_query_prefix(self, format=None, **options): supported_formats = self.connection.features.supported_explain_formats normalized_format = format.upper() if normalized_format not in supported_formats: - msg = '%s is not a recognized format.' % normalized_format + msg = "%s is not a recognized format." % normalized_format if supported_formats: - msg += ' Allowed formats: %s' % ', '.join(sorted(supported_formats)) + msg += " Allowed formats: %s" % ", ".join(sorted(supported_formats)) raise ValueError(msg) if options: - raise ValueError('Unknown options: %s' % ', '.join(sorted(options.keys()))) - analyze = options.pop('analyze', False) + raise ValueError("Unknown options: %s" % ", ".join(sorted(options.keys()))) + analyze = options.pop("analyze", False) prefix = self.explain_prefix if analyze and self.connection.features.supports_explain_analyze: - prefix += ' ANALYZE' + prefix += " ANALYZE" if format and not analyze: # Only TiDB supports the analyze option with formats but with "ROW". - prefix += ' FORMAT=\"%s\"' % format + prefix += ' FORMAT="%s"' % format return prefix def regex_lookup(self, lookup_type): # REGEXP BINARY doesn't work correctly in MySQL 8+ and REGEXP_LIKE # doesn't exist in MySQL 5.x or in MariaDB. - if lookup_type == 'regex': - return '%s REGEXP BINARY %s' - return '%s REGEXP %s' + if lookup_type == "regex": + return "%s REGEXP BINARY %s" + return "%s REGEXP %s" def lookup_cast(self, lookup_type, internal_type=None): - lookup = '%s' - if internal_type == 'JSONField': - lookup = 'JSON_UNQUOTE(%s)' + lookup = "%s" + if internal_type == "JSONField": + lookup = "JSON_UNQUOTE(%s)" return lookup diff --git a/django_tidb/schema.py b/django_tidb/schema.py index 64eedf8..6ea066e 100644 --- a/django_tidb/schema.py +++ b/django_tidb/schema.py @@ -19,11 +19,11 @@ class DatabaseSchemaEditor(MysqlDatabaseSchemaEditor): @property def sql_delete_check(self): - return 'ALTER TABLE %(table)s DROP CHECK %(name)s' + return "ALTER TABLE %(table)s DROP CHECK %(name)s" @property def sql_rename_column(self): - return 'ALTER TABLE %(table)s CHANGE %(old_column)s %(new_column)s %(type)s' + return "ALTER TABLE %(table)s CHANGE %(old_column)s %(new_column)s %(type)s" def skip_default_on_alter(self, field): return False diff --git a/django_tidb/version.py b/django_tidb/version.py index 70c681a..76b91f3 100644 --- a/django_tidb/version.py +++ b/django_tidb/version.py @@ -11,6 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. + # TiDBVersion deal with tidb's version string. # Our tidb version string is got from ```select version();``` # it look like this: @@ -20,10 +21,10 @@ class TiDBVersion: _version = (0, 0, 0) def match(self, version): - version_list = version.split('-') + version_list = version.split("-") if len(version_list) < 3: return False - tidb_version_list = version_list[2].lstrip('v').split('.') + tidb_version_list = version_list[2].lstrip("v").split(".") self._version = tuple(int(x) for x in tidb_version_list) return True diff --git a/tox.ini b/tox.ini index 11ed9ba..a91a0af 100644 --- a/tox.ini +++ b/tox.ini @@ -34,5 +34,7 @@ setenv = skip_install = True deps = flake8==6.0.0 + black==23.1.0 commands = flake8 --max-line-length 130 django_tidb + black --diff --check django_tidb