From cb5a95bede99f13628dfc269590e386d225b8943 Mon Sep 17 00:00:00 2001 From: Blaine Jester Date: Fri, 23 Oct 2026 11:37:35 -0700 Subject: [PATCH 1/5] Remove unused rmc argument from merge conflict SQL format calls Neither query references {rmc}, so ruff flags the keyword as F522. Co-Authored-By: Claude Opus 5.5 (1M context) --- morango/sync/backends/postgres.py | 1 - morango/sync/backends/sqlite.py | 1 - 2 files changed, 2 deletions(-) diff --git a/morango/sync/backends/postgres.py b/morango/sync/backends/postgres.py index ce187f85..15aec093 100644 --- a/morango/sync/backends/postgres.py +++ b/morango/sync/backends/postgres.py @@ -255,7 +255,6 @@ def _dequeuing_merge_conflict_buffer(self, cursor, current_id, transfersession_i buffer=Buffer._meta.db_table, rmcb=RecordMaxCounterBuffer._meta.db_table, store=Store._meta.db_table, - rmc=RecordMaxCounter._meta.db_table, transfer_session_id=transfersession_id, current_instance_id=current_id.id, current_instance_counter=current_id.counter, diff --git a/morango/sync/backends/sqlite.py b/morango/sync/backends/sqlite.py index e82ac7d4..3f4d54c3 100644 --- a/morango/sync/backends/sqlite.py +++ b/morango/sync/backends/sqlite.py @@ -196,7 +196,6 @@ def _dequeuing_merge_conflict_buffer(self, cursor, current_id, transfersession_i buffer=Buffer._meta.db_table, rmcb=RecordMaxCounterBuffer._meta.db_table, store=Store._meta.db_table, - rmc=RecordMaxCounter._meta.db_table, transfer_session_id=transfersession_id, current_instance_id=current_id.id, current_instance_counter=current_id.counter, From e7c7572d07523b61e9422614c9ce5a601b2ed77f Mon Sep 17 00:00:00 2001 From: Blaine Jester Date: Fri, 23 Oct 2026 11:39:23 -0700 Subject: [PATCH 2/5] Reformat files previously excluded from ruff Formatting and import sorting only, produced by ruff 0.15.16 with the project config. No behavior change: each file's AST is unchanged apart from import order and dropped u"" string prefixes. Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/conf.py | 42 +++++------- morango/sync/backends/postgres.py | 32 ++++----- morango/sync/backends/sqlite.py | 23 +++---- morango/sync/operations.py | 103 ++++++++--------------------- tests/testapp/tests/test_crypto.py | 62 +++++++++-------- 5 files changed, 102 insertions(+), 160 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index e37f8cd2..b60a284b 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -64,7 +64,7 @@ def process_docstring(app, what, name, obj, options, lines): for field in fields: # Skip ManyToOneRel and ManyToManyRel fields # which have no 'verbose_name' or 'help_text' - if not hasattr(field, 'verbose_name'): + if not hasattr(field, "verbose_name"): continue # Decode and strip any html out of the field's help text @@ -77,24 +77,20 @@ def process_docstring(app, what, name, obj, options, lines): if help_text: # Add the model field to the end of the docstring as a param # using the help text as the description - lines.append(u':param %s: %s' % (field.attname, help_text)) + lines.append(":param %s: %s" % (field.attname, help_text)) else: # Add the model field to the end of the docstring as a param # using the verbose name as the description - lines.append(u':param %s: %s' % (field.attname, verbose_name)) + lines.append(":param %s: %s" % (field.attname, verbose_name)) # Add the field's type to the docstring if isinstance(field, models.ForeignKey): to = field.remote_field.model lines.append( - u':type %s: %s to :class:`~%s`' - % (field.attname, type(field).__name__, to) + ":type %s: %s to :class:`~%s`" % (field.attname, type(field).__name__, to) ) else: - lines.append( - u':type %s: %s' - % (field.attname, type(field).__name__) - ) + lines.append(":type %s: %s" % (field.attname, type(field).__name__)) return lines @@ -106,18 +102,18 @@ def process_docstring(app, what, name, obj, options, lines): extensions = ["sphinx.ext.autodoc", "sphinx.ext.viewcode"] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: source_suffix = [".rst"] # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = u"Morango developer documentation" -copyright = u"2020 Learning Equality" +project = "Morango developer documentation" +copyright = "2020 Learning Equality" # The version info for the project you're documenting, acts as replacement # for |version| and |release|, also used in various other places throughout @@ -140,7 +136,7 @@ def process_docstring(app, what, name, obj, options, lines): # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['_build'] +exclude_patterns = ["_build"] # The reST default role (used for this markup: `text`) to use for all # documents. @@ -158,7 +154,7 @@ def process_docstring(app, what, name, obj, options, lines): # show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] @@ -257,7 +253,7 @@ def setup(app): # html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'morangodoc' +htmlhelp_basename = "morangodoc" # -- Options for LaTeX output ------------------------------------------ @@ -265,10 +261,8 @@ def setup(app): latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. # 'preamble': '', } @@ -277,9 +271,7 @@ def setup(app): # (source start file, target name, title, author, documentclass # [howto/manual]). latex_documents = [ - ('index', 'morango.tex', - u'morango Documentation', - u'Learning Equality', 'manual'), + ("index", "morango.tex", "morango Documentation", "Learning Equality", "manual"), ] # The name of an image file (relative to this directory) to place at @@ -307,11 +299,7 @@ def setup(app): # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'morango', - u'morango Documentation', - [u'Learning Equality'], 1) -] +man_pages = [("index", "morango", "morango Documentation", ["Learning Equality"], 1)] # If true, show URL addresses after external links. # man_show_urls = False @@ -346,4 +334,4 @@ def setup(app): # If true, do not generate a @detailmenu in the "Top" node's menu. # texinfo_no_detailmenu = False -suppress_warnings = ['image.nonlocal_uri'] +suppress_warnings = ["image.nonlocal_uri"] diff --git a/morango/sync/backends/postgres.py b/morango/sync/backends/postgres.py index 15aec093..04afc809 100644 --- a/morango/sync/backends/postgres.py +++ b/morango/sync/backends/postgres.py @@ -2,8 +2,6 @@ import logging from contextlib import contextmanager -from .base import BaseSQLWrapper -from .utils import get_pk_field from morango.errors import MorangoDatabaseError from morango.models.core import Buffer from morango.models.core import RecordMaxCounter @@ -11,6 +9,8 @@ from morango.models.core import Store from morango.utils import SETTINGS +from .base import BaseSQLWrapper +from .utils import get_pk_field # advisory lock integers for locking partitions LOCK_ALL_PARTITIONS = 1 @@ -23,9 +23,7 @@ class SQLWrapper(BaseSQLWrapper): backend = "postgresql" - create_temporary_table_template = ( - "CREATE TEMP TABLE {name} ({fields}) ON COMMIT DROP" - ) + create_temporary_table_template = "CREATE TEMP TABLE {name} ({fields}) ON COMMIT DROP" def _is_transaction_isolation_error(self, error): """ @@ -36,7 +34,7 @@ def _is_transaction_isolation_error(self, error): from psycopg2.extensions import TransactionRollbackError # Django can wrap errors, adding it to the `__cause__` attribute - for e in (error, getattr(error, '__cause__', None)): + for e in (error, getattr(error, "__cause__", None)): if isinstance(e, TransactionRollbackError): return True return False @@ -55,11 +53,15 @@ def _set_transaction_repeatable_read(self): # before any reading/writing operations have taken place, which includes creating # savepoints if self.connection.in_atomic_block: - raise MorangoDatabaseError("Unable to set transaction isolation during a transaction") + raise MorangoDatabaseError( + "Unable to set transaction isolation during a transaction" + ) for savepoint_id in self.connection.savepoint_ids: if savepoint_id is not None: - raise MorangoDatabaseError("Unable to set transaction isolation when savepoints have been created") + raise MorangoDatabaseError( + "Unable to set transaction isolation when savepoints have been created" + ) # ensure the postgres database wrapper loads the isolation level, which requires it to # connection to the database. @@ -70,7 +72,9 @@ def _set_transaction_repeatable_read(self): try: self.connection.isolation_level = ISOLATION_LEVEL_REPEATABLE_READ - self.connection.connection.set_session(isolation_level=ISOLATION_LEVEL_REPEATABLE_READ, autocommit=False) + self.connection.connection.set_session( + isolation_level=ISOLATION_LEVEL_REPEATABLE_READ, autocommit=False + ) yield finally: self.connection.isolation_level = existing_isolation_level @@ -99,9 +103,7 @@ def _prepare_with_values(self, name, fields, db_values): def _prepare_casted_fields(self, fields): return ", ".join( map( - lambda f: "{f}::{type}".format( - f=f.column, type=f.rel_db_type(self.connection) - ), + lambda f: "{f}::{type}".format(f=f.column, type=f.rel_db_type(self.connection)), fields, ) ) @@ -262,9 +264,7 @@ def _dequeuing_merge_conflict_buffer(self, cursor, current_id, transfersession_i cursor.execute(merge_conflict_store) - def _dequeuing_update_rmcs_last_saved_by( - self, cursor, current_id, transfersession_id - ): + def _dequeuing_update_rmcs_last_saved_by(self, cursor, current_id, transfersession_id): # update or create rmc for merge conflicts with local instance id merge_conflict_store = """ WITH new_values as @@ -469,7 +469,7 @@ def _execute_lock(self, key1, key2=None, unlock=False, session=False, shared=Fal xact_="" if session else "xact_", lock="unlock" if unlock else "lock", _shared="_shared" if shared else "", - keys=", ".join(["%s"] * len(keys)) + keys=", ".join(["%s"] * len(keys)), ) with self.connection.cursor() as c: diff --git a/morango/sync/backends/sqlite.py b/morango/sync/backends/sqlite.py index 3f4d54c3..e6cfd307 100644 --- a/morango/sync/backends/sqlite.py +++ b/morango/sync/backends/sqlite.py @@ -1,11 +1,12 @@ -from .base import BaseSQLWrapper -from .utils import calculate_max_sqlite_variables -from .utils import get_pk_field from morango.models.core import Buffer from morango.models.core import RecordMaxCounter from morango.models.core import RecordMaxCounterBuffer from morango.models.core import Store +from .base import BaseSQLWrapper +from .utils import calculate_max_sqlite_variables +from .utils import get_pk_field + class SQLWrapper(BaseSQLWrapper): backend = "sqlite" @@ -51,9 +52,7 @@ def _bulk_insert(self, cursor, table_name, fields, db_values): for x in range(0, len(db_values), num_of_values_able_to_insert) ] for value_chunk in value_chunks: - super(SQLWrapper, self)._bulk_insert( - cursor, table_name, fields, value_chunk - ) + super(SQLWrapper, self)._bulk_insert(cursor, table_name, fields, value_chunk) def _bulk_update(self, cursor, table_name, fields, db_values): """ @@ -64,9 +63,7 @@ def _bulk_update(self, cursor, table_name, fields, db_values): # calculate and create equal sized chunks of data to update incrementally # for every field we're updating, we'll require 3 parameters num_update_fields = len(fields) - 1 - num_of_rows_able_to_update = ( - calculate_max_sqlite_variables() // num_update_fields // 3 - ) + num_of_rows_able_to_update = calculate_max_sqlite_variables() // num_update_fields // 3 num_of_values_able_to_update = num_of_rows_able_to_update * len(fields) value_chunks = [ db_values[x : x + num_of_values_able_to_update] @@ -100,9 +97,7 @@ def _bulk_update(self, cursor, table_name, fields, db_values): table_name=table_name, set_sql=set_sql[:-1], pk_field=pk.column, - placeholder_str="({})".format( - ",".join("%s" for _ in range(len(pk_params))) - ), + placeholder_str="({})".format(",".join("%s" for _ in range(len(pk_params)))), ) # use DB-APIs parameter substitution (2nd parameter expects a sequence) cursor.execute(update, params) @@ -202,9 +197,7 @@ def _dequeuing_merge_conflict_buffer(self, cursor, current_id, transfersession_i ) cursor.execute(merge_conflict_store) - def _dequeuing_update_rmcs_last_saved_by( - self, cursor, current_id, transfersession_id - ): + def _dequeuing_update_rmcs_last_saved_by(self, cursor, current_id, transfersession_id): # update or create rmc for merge conflicts with local instance id merge_conflict_store = """REPLACE INTO {rmc} (instance_id, counter, store_model_id) SELECT '{current_instance_id}', {current_instance_counter}, store.id diff --git a/morango/sync/operations.py b/morango/sync/operations.py index 70da04d7..65059c1b 100644 --- a/morango/sync/operations.py +++ b/morango/sync/operations.py @@ -97,17 +97,13 @@ def _queue_into_buffer_v1(transfersession): if not fsics: return - profile_condition = [ - "profile = '{}'".format(transfersession.sync_session.profile) - ] + profile_condition = ["profile = '{}'".format(transfersession.sync_session.profile)] partition_conditions = [] # create condition for filtering by partitions for prefix in filter_prefixes: partition_conditions += ["partition LIKE '{}%'".format(prefix)] if filter_prefixes: - partition_conditions = [ - _join_with_logical_operator(partition_conditions, "OR") - ] + partition_conditions = [_join_with_logical_operator(partition_conditions, "OR")] chunk_size = 200 fsics = list(fsics.items()) @@ -155,9 +151,7 @@ def _queue_into_buffer_v1(transfersession): FROM {store} WHERE {condition} """.format( transfer_session_id=transfersession.id, - transfer_session_id_type=TransferSession._meta.pk.rel_db_type( - connection - ), + transfer_session_id_type=TransferSession._meta.pk.rel_db_type(connection), condition=where_condition, store=Store._meta.db_table, ) @@ -221,9 +215,7 @@ def _queue_into_buffer_v2(transfersession, chunk_size=200): assert "super" in client_fsic # ensure that the partitions in the FSICs are under the current filter, before using them - for partition in itertools.chain( - server_fsic["sub"].keys(), client_fsic["sub"].keys() - ): + for partition in itertools.chain(server_fsic["sub"].keys(), client_fsic["sub"].keys()): if partition not in sync_filter: raise MorangoInvalidFSICPartition( "Partition '{}' is not in filter".format(partition) @@ -241,9 +233,7 @@ def _queue_into_buffer_v2(transfersession, chunk_size=200): if not fsics: return - profile_condition = [ - "profile = '{}'".format(transfersession.sync_session.profile) - ] + profile_condition = ["profile = '{}'".format(transfersession.sync_session.profile)] fsics_len = sum(len(fsics[part]) for part in fsics) + len(fsics) # subtract one because when partitions overflow chunks they add up to an extra item per chunk @@ -265,7 +255,6 @@ def _queue_into_buffer_v2(transfersession, chunk_size=200): select_buffers = [] for fsic_chunk in chunked_fsics: - # create condition for filtering by partitions partition_conditions = [] for part, insts in fsic_chunk.items(): @@ -286,9 +275,7 @@ def _queue_into_buffer_v2(transfersession, chunk_size=200): + ")" ) - partition_conditions = [ - _join_with_logical_operator(partition_conditions, "OR") - ] + partition_conditions = [_join_with_logical_operator(partition_conditions, "OR")] # combine conditions and filter by profile where_condition = _join_with_logical_operator( @@ -304,9 +291,7 @@ def _queue_into_buffer_v2(transfersession, chunk_size=200): FROM {store} WHERE {condition} """.format( transfer_session_id=transfersession.id, - transfer_session_id_type=TransferSession._meta.pk.rel_db_type( - connection - ), + transfer_session_id_type=TransferSession._meta.pk.rel_db_type(connection), condition=where_condition, store=Store._meta.db_table, ) @@ -351,9 +336,7 @@ def _update_legacy_self_ref_order_for_model(queryset): # root nodes set the _self_ref_order to 0 queryset.filter(_self_ref_fk="").exclude(_self_ref_order=0).update(_self_ref_order=0) # reset the _self_ref_order to None for all records that have a parent - queryset.exclude(_self_ref_fk="").exclude(_self_ref_order=None).update( - _self_ref_order=None - ) + queryset.exclude(_self_ref_fk="").exclude(_self_ref_order=None).update(_self_ref_order=None) parent = Store.objects.filter( id=Cast(OuterRef("_self_ref_fk"), UUIDField()), @@ -394,13 +377,9 @@ def _dequeue_into_store(transfer_session, fsic, v2_format=False, self_ref_order= DBBackend._dequeuing_delete_rmcb_records(cursor, transfer_session.id) DBBackend._dequeuing_delete_buffered_records(cursor, transfer_session.id) current_id = InstanceIDModel.get_current_instance_and_increment_counter() - DBBackend._dequeuing_merge_conflict_buffer( - cursor, current_id, transfer_session.id - ) + DBBackend._dequeuing_merge_conflict_buffer(cursor, current_id, transfer_session.id) DBBackend._dequeuing_merge_conflict_rmcb(cursor, transfer_session.id) - DBBackend._dequeuing_update_rmcs_last_saved_by( - cursor, current_id, transfer_session.id - ) + DBBackend._dequeuing_update_rmcs_last_saved_by(cursor, current_id, transfer_session.id) DBBackend._dequeuing_delete_mc_rmcb(cursor, transfer_session.id) DBBackend._dequeuing_delete_mc_buffer(cursor, transfer_session.id) DBBackend._dequeuing_insert_remaining_buffer(cursor, transfer_session.id) @@ -438,9 +417,7 @@ def __call__(self, context): result = False try: # verify context object matches what the operation expects - if self.expects_context is None or isinstance( - context, self.expects_context - ): + if self.expects_context is None or isinstance(context, self.expects_context): logger.debug("{} = ?".format(debug_msg)) result = self.handle(context) @@ -491,9 +468,7 @@ def handle(self, context): # attributes that we'll use to identify existing sessions. we really only want there to # be one of these at a time - data = dict( - push=context.is_push, sync_session_id=context.sync_session.id, active=True - ) + data = dict(push=context.is_push, sync_session_id=context.sync_session.id, active=True) # get the most recent transfer session transfer_sessions = TransferSession.objects.order_by("-last_activity_timestamp") @@ -515,9 +490,7 @@ def handle(self, context): data.update( id=context.request.data.get("id"), records_total=( - context.request.data.get("records_total") - if context.is_push - else None + context.request.data.get("records_total") if context.is_push else None ), client_fsic=context.request.data.get("client_fsic") or "{}", ) @@ -552,9 +525,7 @@ def handle(self, context): if context.is_producer and SETTINGS.MORANGO_SERIALIZE_BEFORE_QUEUING: try: - serialize_into_store( - context.sync_session.profile, sync_filter=context.filter - ) + serialize_into_store(context.sync_session.profile, sync_filter=context.filter) except OperationalError as e: # if we run into a transaction isolation error, we return a pending status to force # retrying through the controller flow @@ -571,9 +542,7 @@ def handle(self, context): ) if context.is_server: context.transfer_session.server_fsic = fsic - context.transfer_session.client_fsic = context.request.data.get( - "client_fsic", "{}" - ) + context.transfer_session.client_fsic = context.request.data.get("client_fsic", "{}") update_fields = ["server_fsic", "client_fsic"] else: context.transfer_session.client_fsic = fsic @@ -601,9 +570,7 @@ def handle(self, context): _queue_into_buffer_v1(context.transfer_session) # update the records_total for client and server transfer session - records_total = Buffer.objects.filter( - transfer_session=context.transfer_session - ).count() + records_total = Buffer.objects.filter(transfer_session=context.transfer_session).count() logger.debug("[morango] Queued {} records".format(records_total)) context.transfer_session.records_total = records_total @@ -700,10 +667,7 @@ def handle(self, context): validate_and_create_buffer_data(data, context.transfer_session) - if ( - context.transfer_session.records_transferred - == context.transfer_session.records_total - ): + if context.transfer_session.records_transferred == context.transfer_session.records_total: return transfer_statuses.COMPLETED return transfer_statuses.PENDING @@ -785,12 +749,8 @@ def handle(self, context): if SETTINGS.MORANGO_DESERIALIZE_AFTER_DEQUEUING and records_transferred > 0: try: # we first serialize to avoid deserialization merge conflicts - serialize_into_store( - context.sync_session.profile, sync_filter=context.filter - ) - deserialize_from_store( - context.sync_session.profile, sync_filter=context.filter - ) + serialize_into_store(context.sync_session.profile, sync_filter=context.filter) + deserialize_from_store(context.sync_session.profile, sync_filter=context.filter) except OperationalError as e: # if we run into a transaction isolation error, we return a pending status to force # retrying through the controller flow @@ -855,9 +815,7 @@ def update_transfer_session(self, context, **data): :param data: Data to update remote transfer session wiht :return: A response dict """ - return context.connection._update_transfer_session( - data, context.transfer_session - ).json() + return context.connection._update_transfer_session(data, context.transfer_session).json() def close_transfer_session(self, context): """ @@ -1118,9 +1076,7 @@ def handle(self, context): transfer_session=context.transfer_session ).order_by("pk") - data = BufferSerializer( - buffered_records[offset : offset + chunk_size], many=True - ).data + data = BufferSerializer(buffered_records[offset : offset + chunk_size], many=True).data # push buffers chunk to server self.put_buffers(context, data) @@ -1130,14 +1086,13 @@ def handle(self, context): ) context.transfer_session.bytes_sent = context.connection.bytes_sent context.transfer_session.bytes_received = context.connection.bytes_received - context.transfer_session.save(update_fields=["records_transferred", "bytes_sent", "bytes_received"]) + context.transfer_session.save( + update_fields=["records_transferred", "bytes_sent", "bytes_received"] + ) # if we've transferred all records, return a completed status op_status = transfer_statuses.PENDING - if ( - context.transfer_session.records_transferred - >= context.transfer_session.records_total - ): + if context.transfer_session.records_transferred >= context.transfer_session.records_total: op_status = transfer_statuses.COMPLETED return op_status @@ -1157,9 +1112,7 @@ def handle(self, context): # grab buffers, just one chunk data = self.get_buffers(context) - validate_and_create_buffer_data( - data, transfer_session, connection=context.connection - ) + validate_and_create_buffer_data(data, transfer_session, connection=context.connection) # if we've transferred all records, return a completed status op_status = transfer_statuses.PENDING @@ -1222,9 +1175,7 @@ def handle(self, context): self._assert(context.transfer_session is not None) self._assert(ASYNC_OPERATIONS in context.capabilities) - remote_status, _ = self.remote_proceed_to( - context, transfer_stages.DESERIALIZING - ) + remote_status, _ = self.remote_proceed_to(context, transfer_stages.DESERIALIZING) return remote_status diff --git a/tests/testapp/tests/test_crypto.py b/tests/testapp/tests/test_crypto.py index b0207a9b..4400297c 100644 --- a/tests/testapp/tests/test_crypto.py +++ b/tests/testapp/tests/test_crypto.py @@ -5,7 +5,6 @@ class CrossKeySigVerificationMixin(object): - def setupKeys(self, base_key): self.key = base_key self.pykey = crypto.PythonRSAKey( @@ -14,20 +13,21 @@ def setupKeys(self, base_key): if crypto.M2CRYPTO_EXISTS: self.m2cryptokey = crypto.M2CryptoKey( private_key_string=self.key.get_private_key_string(), - public_key_string=self.key.get_public_key_string() + public_key_string=self.key.get_public_key_string(), ) if crypto.CRYPTOGRAPHY_EXISTS: self.cryptokey = crypto.CryptographyKey( private_key_string=self.key.get_private_key_string(), - public_key_string=self.key.get_public_key_string() + public_key_string=self.key.get_public_key_string(), ) self.message_actual = "Hello world! Please leave a message after the tone." self.message_fake = "Hello world! Please leave a message after the tone..." -@unittest.skipIf(not crypto.M2CRYPTO_EXISTS, "Skipping M2Crypto tests as it does not appear to be installed.") +@unittest.skipIf( + not crypto.M2CRYPTO_EXISTS, "Skipping M2Crypto tests as it does not appear to be installed." +) class TestM2CryptoWithPyRSA(CrossKeySigVerificationMixin, unittest.TestCase): - def setUp(self): self.setupKeys(crypto.M2CryptoKey()) @@ -58,9 +58,11 @@ def test_pubkey_verification_pyrsa(self): self.assertFalse(pubkey.verify(self.message_fake, sig)) -@unittest.skipIf(not crypto.CRYPTOGRAPHY_EXISTS, "Skipping python-cryptography test as it does not appear to be installed.") +@unittest.skipIf( + not crypto.CRYPTOGRAPHY_EXISTS, + "Skipping python-cryptography test as it does not appear to be installed.", +) class TestCryptoWithPyRSA(CrossKeySigVerificationMixin, unittest.TestCase): - def setUp(self): self.setupKeys(crypto.CryptographyKey()) @@ -85,10 +87,14 @@ def test_pubkey_verification_crypto(self): self.assertFalse(pubkey.verify(self.message_fake, sig)) -@unittest.skipIf(not crypto.CRYPTOGRAPHY_EXISTS, "Skipping python-cryptography test as it does not appear to be installed.") -@unittest.skipIf(not crypto.M2CRYPTO_EXISTS, "Skipping M2Crypto tests as it does not appear to be installed.") +@unittest.skipIf( + not crypto.CRYPTOGRAPHY_EXISTS, + "Skipping python-cryptography test as it does not appear to be installed.", +) +@unittest.skipIf( + not crypto.M2CRYPTO_EXISTS, "Skipping M2Crypto tests as it does not appear to be installed." +) class TestCryptoWithM2Crypto(CrossKeySigVerificationMixin, unittest.TestCase): - def setUp(self): self.setupKeys(crypto.CryptographyKey()) @@ -108,16 +114,15 @@ def test_crypto_sig_verification_with_m2crypto(self): class ExistingKeyParsingMixin(object): - priv_key_with_pem_header = "-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAuABOgZEZ0pxp2hoYnTrYFoqQtzOEeTrjwTULV2v+zjyuT4f/\nIZylz4TH1MgmUMbn7/nu6dsfCYc87hx16fbhcUdZpiAW0Lb0mfnHxUwJKrBHmdr/\nMF8smN1a4OjOJ5O9ugAoijhG+Pb+SUh4tFSRv1vx68CyfxMSK2g/5jGJWlyh1K9Y\noBKXOtsXQQppl+4N4Stve9qFfsyjIW/FNlya3qmQDe9p9r5Ir7YEIS090rCOCEA3\nyiQ8gFThzCVK8Xlu3R/vclrhfvxhJWSJS5z5QRQ0QaZY+/A4b940yDLluRGViHKq\nagMvaKrcTO/fOAa257eSTFUyn7GjxAa9vy8i2QIDAQABAoIBAAiuWwXZ5rH9FzFn\nEco5QICvwOwjzhg6Iwy2h/Zz7e2lB0RRUkQvs9L6nML5PnWJLOAxlogKAojcjI9f\nYGDNeQ1zJFOmJ+1o9FlfY4F3eOc+seIcZvXNR7lemC8MTM2pNsZTw5Xh2dddL9od\nRTSc2NOCbwOEb+d26uCJZpphs+1DZQ5UYPgdu3N+wna5+OdZra1waqZqm1DFKbFT\nVx1PEPH4zyX5jhNP7MFW4W/u96gqAHVaPbkiycuEnxClidZapFrAqaQjFWCA6OPz\nCoNsy+n5fGD5eDIwI/AQQULRAQm35IW6zFmHrdB2q5Aeg87cclhdRnLXx7HQzfWZ\nKetBogECgYEA48mcaU69f4o8E7OCqGKP905MOXT9b1oRC7HRIhcSV3QKlxl/0VY/\nL9A64hn92ByWsyfWbkWjchK3mz2KGi9j1TaoErMLcfxWhcmvHCHIkYjmpilspKfp\nHNAM530C24+7POMcQiT6Q+KIapWyLffpmXHQPd4Z9p11KFx6gQ6hHtECgYEAzspg\nKD0889I32wa0fohHe6fk1Wtv/Fz+SRJ5LYAk/CCfisYDTA2ejayChSXzfPc0oPlb\n9EqBNd6tShhTc1VrJp3F/M4nPN/ZvHzVA/ndu5vpeAiBzdtzjttp3W7Ea01bym++\nOYvnhoDLrG80GCH0nJDCqtuqoYxLvB3Ek8EmlYkCgYAxgSh4Dn/Kjx1dXr7/n2QQ\naDjSp+VIZPedZgjAcukujm6axhTsRuU2m/egGev8IsJxry/ACWxrJzw2BdrUtAXr\nWZSPc9AB9shLDTj8US9Iycruw8PzyPY1p9WWHaoYU5VqtyT2DxlA1aO2HlB6Aw4G\npiCOwY089p12pxqMn8ROcQKBgHJZVnLp6hqp1Fk5i/WsRlsKrG+XyYUzpymhHYEb\nq1gAcji65nfX0CVnj4UxR0ODL4cUXNTpnim7yPeAHCVaxrXD6Qeyt9/hqPWh0ekw\n8nwb6y6FBcJf57bHffMEnXj4fhmjUP1hb9Xgwr/HfncZz7oEEqGIdwJ+IiMUEu/h\njwSBAoGACN/OWrCnLDDqb9kXXIsqx+oJpo311PW39JipU1yEB5Z1PAHw6/qm0PzU\nwCQ+UUbIhdrfdWEs+pPVa4qFNIjVatNdOL5heJzY6ZGQOCV2xv+qX9vuuN962rUk\nmQW3SLGIqqvUDV3Z2nfBwV5L3qbPuGm21PliMUQQOggjx+UIjOo=\n-----END RSA PRIVATE KEY-----" priv_key_without_pem_header = "MIIEogIBAAKCAQEAuABOgZEZ0pxp2hoYnTrYFoqQtzOEeTrjwTULV2v+zjyuT4f/\nIZylz4TH1MgmUMbn7/nu6dsfCYc87hx16fbhcUdZpiAW0Lb0mfnHxUwJKrBHmdr/\nMF8smN1a4OjOJ5O9ugAoijhG+Pb+SUh4tFSRv1vx68CyfxMSK2g/5jGJWlyh1K9Y\noBKXOtsXQQppl+4N4Stve9qFfsyjIW/FNlya3qmQDe9p9r5Ir7YEIS090rCOCEA3\nyiQ8gFThzCVK8Xlu3R/vclrhfvxhJWSJS5z5QRQ0QaZY+/A4b940yDLluRGViHKq\nagMvaKrcTO/fOAa257eSTFUyn7GjxAa9vy8i2QIDAQABAoIBAAiuWwXZ5rH9FzFn\nEco5QICvwOwjzhg6Iwy2h/Zz7e2lB0RRUkQvs9L6nML5PnWJLOAxlogKAojcjI9f\nYGDNeQ1zJFOmJ+1o9FlfY4F3eOc+seIcZvXNR7lemC8MTM2pNsZTw5Xh2dddL9od\nRTSc2NOCbwOEb+d26uCJZpphs+1DZQ5UYPgdu3N+wna5+OdZra1waqZqm1DFKbFT\nVx1PEPH4zyX5jhNP7MFW4W/u96gqAHVaPbkiycuEnxClidZapFrAqaQjFWCA6OPz\nCoNsy+n5fGD5eDIwI/AQQULRAQm35IW6zFmHrdB2q5Aeg87cclhdRnLXx7HQzfWZ\nKetBogECgYEA48mcaU69f4o8E7OCqGKP905MOXT9b1oRC7HRIhcSV3QKlxl/0VY/\nL9A64hn92ByWsyfWbkWjchK3mz2KGi9j1TaoErMLcfxWhcmvHCHIkYjmpilspKfp\nHNAM530C24+7POMcQiT6Q+KIapWyLffpmXHQPd4Z9p11KFx6gQ6hHtECgYEAzspg\nKD0889I32wa0fohHe6fk1Wtv/Fz+SRJ5LYAk/CCfisYDTA2ejayChSXzfPc0oPlb\n9EqBNd6tShhTc1VrJp3F/M4nPN/ZvHzVA/ndu5vpeAiBzdtzjttp3W7Ea01bym++\nOYvnhoDLrG80GCH0nJDCqtuqoYxLvB3Ek8EmlYkCgYAxgSh4Dn/Kjx1dXr7/n2QQ\naDjSp+VIZPedZgjAcukujm6axhTsRuU2m/egGev8IsJxry/ACWxrJzw2BdrUtAXr\nWZSPc9AB9shLDTj8US9Iycruw8PzyPY1p9WWHaoYU5VqtyT2DxlA1aO2HlB6Aw4G\npiCOwY089p12pxqMn8ROcQKBgHJZVnLp6hqp1Fk5i/WsRlsKrG+XyYUzpymhHYEb\nq1gAcji65nfX0CVnj4UxR0ODL4cUXNTpnim7yPeAHCVaxrXD6Qeyt9/hqPWh0ekw\n8nwb6y6FBcJf57bHffMEnXj4fhmjUP1hb9Xgwr/HfncZz7oEEqGIdwJ+IiMUEu/h\njwSBAoGACN/OWrCnLDDqb9kXXIsqx+oJpo311PW39JipU1yEB5Z1PAHw6/qm0PzU\nwCQ+UUbIhdrfdWEs+pPVa4qFNIjVatNdOL5heJzY6ZGQOCV2xv+qX9vuuN962rUk\nmQW3SLGIqqvUDV3Z2nfBwV5L3qbPuGm21PliMUQQOggjx+UIjOo=" - priv_key_with_pem_header_unicode = u"-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAuABOgZEZ0pxp2hoYnTrYFoqQtzOEeTrjwTULV2v+zjyuT4f/\nIZylz4TH1MgmUMbn7/nu6dsfCYc87hx16fbhcUdZpiAW0Lb0mfnHxUwJKrBHmdr/\nMF8smN1a4OjOJ5O9ugAoijhG+Pb+SUh4tFSRv1vx68CyfxMSK2g/5jGJWlyh1K9Y\noBKXOtsXQQppl+4N4Stve9qFfsyjIW/FNlya3qmQDe9p9r5Ir7YEIS090rCOCEA3\nyiQ8gFThzCVK8Xlu3R/vclrhfvxhJWSJS5z5QRQ0QaZY+/A4b940yDLluRGViHKq\nagMvaKrcTO/fOAa257eSTFUyn7GjxAa9vy8i2QIDAQABAoIBAAiuWwXZ5rH9FzFn\nEco5QICvwOwjzhg6Iwy2h/Zz7e2lB0RRUkQvs9L6nML5PnWJLOAxlogKAojcjI9f\nYGDNeQ1zJFOmJ+1o9FlfY4F3eOc+seIcZvXNR7lemC8MTM2pNsZTw5Xh2dddL9od\nRTSc2NOCbwOEb+d26uCJZpphs+1DZQ5UYPgdu3N+wna5+OdZra1waqZqm1DFKbFT\nVx1PEPH4zyX5jhNP7MFW4W/u96gqAHVaPbkiycuEnxClidZapFrAqaQjFWCA6OPz\nCoNsy+n5fGD5eDIwI/AQQULRAQm35IW6zFmHrdB2q5Aeg87cclhdRnLXx7HQzfWZ\nKetBogECgYEA48mcaU69f4o8E7OCqGKP905MOXT9b1oRC7HRIhcSV3QKlxl/0VY/\nL9A64hn92ByWsyfWbkWjchK3mz2KGi9j1TaoErMLcfxWhcmvHCHIkYjmpilspKfp\nHNAM530C24+7POMcQiT6Q+KIapWyLffpmXHQPd4Z9p11KFx6gQ6hHtECgYEAzspg\nKD0889I32wa0fohHe6fk1Wtv/Fz+SRJ5LYAk/CCfisYDTA2ejayChSXzfPc0oPlb\n9EqBNd6tShhTc1VrJp3F/M4nPN/ZvHzVA/ndu5vpeAiBzdtzjttp3W7Ea01bym++\nOYvnhoDLrG80GCH0nJDCqtuqoYxLvB3Ek8EmlYkCgYAxgSh4Dn/Kjx1dXr7/n2QQ\naDjSp+VIZPedZgjAcukujm6axhTsRuU2m/egGev8IsJxry/ACWxrJzw2BdrUtAXr\nWZSPc9AB9shLDTj8US9Iycruw8PzyPY1p9WWHaoYU5VqtyT2DxlA1aO2HlB6Aw4G\npiCOwY089p12pxqMn8ROcQKBgHJZVnLp6hqp1Fk5i/WsRlsKrG+XyYUzpymhHYEb\nq1gAcji65nfX0CVnj4UxR0ODL4cUXNTpnim7yPeAHCVaxrXD6Qeyt9/hqPWh0ekw\n8nwb6y6FBcJf57bHffMEnXj4fhmjUP1hb9Xgwr/HfncZz7oEEqGIdwJ+IiMUEu/h\njwSBAoGACN/OWrCnLDDqb9kXXIsqx+oJpo311PW39JipU1yEB5Z1PAHw6/qm0PzU\nwCQ+UUbIhdrfdWEs+pPVa4qFNIjVatNdOL5heJzY6ZGQOCV2xv+qX9vuuN962rUk\nmQW3SLGIqqvUDV3Z2nfBwV5L3qbPuGm21PliMUQQOggjx+UIjOo=\n-----END RSA PRIVATE KEY-----" + priv_key_with_pem_header_unicode = "-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAuABOgZEZ0pxp2hoYnTrYFoqQtzOEeTrjwTULV2v+zjyuT4f/\nIZylz4TH1MgmUMbn7/nu6dsfCYc87hx16fbhcUdZpiAW0Lb0mfnHxUwJKrBHmdr/\nMF8smN1a4OjOJ5O9ugAoijhG+Pb+SUh4tFSRv1vx68CyfxMSK2g/5jGJWlyh1K9Y\noBKXOtsXQQppl+4N4Stve9qFfsyjIW/FNlya3qmQDe9p9r5Ir7YEIS090rCOCEA3\nyiQ8gFThzCVK8Xlu3R/vclrhfvxhJWSJS5z5QRQ0QaZY+/A4b940yDLluRGViHKq\nagMvaKrcTO/fOAa257eSTFUyn7GjxAa9vy8i2QIDAQABAoIBAAiuWwXZ5rH9FzFn\nEco5QICvwOwjzhg6Iwy2h/Zz7e2lB0RRUkQvs9L6nML5PnWJLOAxlogKAojcjI9f\nYGDNeQ1zJFOmJ+1o9FlfY4F3eOc+seIcZvXNR7lemC8MTM2pNsZTw5Xh2dddL9od\nRTSc2NOCbwOEb+d26uCJZpphs+1DZQ5UYPgdu3N+wna5+OdZra1waqZqm1DFKbFT\nVx1PEPH4zyX5jhNP7MFW4W/u96gqAHVaPbkiycuEnxClidZapFrAqaQjFWCA6OPz\nCoNsy+n5fGD5eDIwI/AQQULRAQm35IW6zFmHrdB2q5Aeg87cclhdRnLXx7HQzfWZ\nKetBogECgYEA48mcaU69f4o8E7OCqGKP905MOXT9b1oRC7HRIhcSV3QKlxl/0VY/\nL9A64hn92ByWsyfWbkWjchK3mz2KGi9j1TaoErMLcfxWhcmvHCHIkYjmpilspKfp\nHNAM530C24+7POMcQiT6Q+KIapWyLffpmXHQPd4Z9p11KFx6gQ6hHtECgYEAzspg\nKD0889I32wa0fohHe6fk1Wtv/Fz+SRJ5LYAk/CCfisYDTA2ejayChSXzfPc0oPlb\n9EqBNd6tShhTc1VrJp3F/M4nPN/ZvHzVA/ndu5vpeAiBzdtzjttp3W7Ea01bym++\nOYvnhoDLrG80GCH0nJDCqtuqoYxLvB3Ek8EmlYkCgYAxgSh4Dn/Kjx1dXr7/n2QQ\naDjSp+VIZPedZgjAcukujm6axhTsRuU2m/egGev8IsJxry/ACWxrJzw2BdrUtAXr\nWZSPc9AB9shLDTj8US9Iycruw8PzyPY1p9WWHaoYU5VqtyT2DxlA1aO2HlB6Aw4G\npiCOwY089p12pxqMn8ROcQKBgHJZVnLp6hqp1Fk5i/WsRlsKrG+XyYUzpymhHYEb\nq1gAcji65nfX0CVnj4UxR0ODL4cUXNTpnim7yPeAHCVaxrXD6Qeyt9/hqPWh0ekw\n8nwb6y6FBcJf57bHffMEnXj4fhmjUP1hb9Xgwr/HfncZz7oEEqGIdwJ+IiMUEu/h\njwSBAoGACN/OWrCnLDDqb9kXXIsqx+oJpo311PW39JipU1yEB5Z1PAHw6/qm0PzU\nwCQ+UUbIhdrfdWEs+pPVa4qFNIjVatNdOL5heJzY6ZGQOCV2xv+qX9vuuN962rUk\nmQW3SLGIqqvUDV3Z2nfBwV5L3qbPuGm21PliMUQQOggjx+UIjOo=\n-----END RSA PRIVATE KEY-----" pub_key_with_both_headers = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuABOgZEZ0pxp2hoYnTrY\nFoqQtzOEeTrjwTULV2v+zjyuT4f/IZylz4TH1MgmUMbn7/nu6dsfCYc87hx16fbh\ncUdZpiAW0Lb0mfnHxUwJKrBHmdr/MF8smN1a4OjOJ5O9ugAoijhG+Pb+SUh4tFSR\nv1vx68CyfxMSK2g/5jGJWlyh1K9YoBKXOtsXQQppl+4N4Stve9qFfsyjIW/FNlya\n3qmQDe9p9r5Ir7YEIS090rCOCEA3yiQ8gFThzCVK8Xlu3R/vclrhfvxhJWSJS5z5\nQRQ0QaZY+/A4b940yDLluRGViHKqagMvaKrcTO/fOAa257eSTFUyn7GjxAa9vy8i\n2QIDAQAB\n-----END PUBLIC KEY-----\n" pub_key_with_pkcs8_header = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuABOgZEZ0pxp2hoYnTrY\nFoqQtzOEeTrjwTULV2v+zjyuT4f/IZylz4TH1MgmUMbn7/nu6dsfCYc87hx16fbh\ncUdZpiAW0Lb0mfnHxUwJKrBHmdr/MF8smN1a4OjOJ5O9ugAoijhG+Pb+SUh4tFSR\nv1vx68CyfxMSK2g/5jGJWlyh1K9YoBKXOtsXQQppl+4N4Stve9qFfsyjIW/FNlya\n3qmQDe9p9r5Ir7YEIS090rCOCEA3yiQ8gFThzCVK8Xlu3R/vclrhfvxhJWSJS5z5\nQRQ0QaZY+/A4b940yDLluRGViHKqagMvaKrcTO/fOAa257eSTFUyn7GjxAa9vy8i\n2QIDAQAB" pub_key_with_pem_header = "-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEAuABOgZEZ0pxp2hoYnTrY\nFoqQtzOEeTrjwTULV2v+zjyuT4f/IZylz4TH1MgmUMbn7/nu6dsfCYc87hx16fbh\ncUdZpiAW0Lb0mfnHxUwJKrBHmdr/MF8smN1a4OjOJ5O9ugAoijhG+Pb+SUh4tFSR\nv1vx68CyfxMSK2g/5jGJWlyh1K9YoBKXOtsXQQppl+4N4Stve9qFfsyjIW/FNlya\n3qmQDe9p9r5Ir7YEIS090rCOCEA3yiQ8gFThzCVK8Xlu3R/vclrhfvxhJWSJS5z5\nQRQ0QaZY+/A4b940yDLluRGViHKqagMvaKrcTO/fOAa257eSTFUyn7GjxAa9vy8i\n2QIDAQAB\n-----END RSA PUBLIC KEY-----\n" pub_key_with_no_headers = "MIIBCgKCAQEAuABOgZEZ0pxp2hoYnTrY\nFoqQtzOEeTrjwTULV2v+zjyuT4f/IZylz4TH1MgmUMbn7/nu6dsfCYc87hx16fbh\ncUdZpiAW0Lb0mfnHxUwJKrBHmdr/MF8smN1a4OjOJ5O9ugAoijhG+Pb+SUh4tFSR\nv1vx68CyfxMSK2g/5jGJWlyh1K9YoBKXOtsXQQppl+4N4Stve9qFfsyjIW/FNlya\n3qmQDe9p9r5Ir7YEIS090rCOCEA3yiQ8gFThzCVK8Xlu3R/vclrhfvxhJWSJS5z5\nQRQ0QaZY+/A4b940yDLluRGViHKqagMvaKrcTO/fOAa257eSTFUyn7GjxAa9vy8i\n2QIDAQAB" - pub_key_with_both_headers_unicode = u"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuABOgZEZ0pxp2hoYnTrY\nFoqQtzOEeTrjwTULV2v+zjyuT4f/IZylz4TH1MgmUMbn7/nu6dsfCYc87hx16fbh\ncUdZpiAW0Lb0mfnHxUwJKrBHmdr/MF8smN1a4OjOJ5O9ugAoijhG+Pb+SUh4tFSR\nv1vx68CyfxMSK2g/5jGJWlyh1K9YoBKXOtsXQQppl+4N4Stve9qFfsyjIW/FNlya\n3qmQDe9p9r5Ir7YEIS090rCOCEA3yiQ8gFThzCVK8Xlu3R/vclrhfvxhJWSJS5z5\nQRQ0QaZY+/A4b940yDLluRGViHKqagMvaKrcTO/fOAa257eSTFUyn7GjxAa9vy8i\n2QIDAQAB\n-----END PUBLIC KEY-----\n" + pub_key_with_both_headers_unicode = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuABOgZEZ0pxp2hoYnTrY\nFoqQtzOEeTrjwTULV2v+zjyuT4f/IZylz4TH1MgmUMbn7/nu6dsfCYc87hx16fbh\ncUdZpiAW0Lb0mfnHxUwJKrBHmdr/MF8smN1a4OjOJ5O9ugAoijhG+Pb+SUh4tFSR\nv1vx68CyfxMSK2g/5jGJWlyh1K9YoBKXOtsXQQppl+4N4Stve9qFfsyjIW/FNlya\n3qmQDe9p9r5Ir7YEIS090rCOCEA3yiQ8gFThzCVK8Xlu3R/vclrhfvxhJWSJS5z5\nQRQ0QaZY+/A4b940yDLluRGViHKqagMvaKrcTO/fOAa257eSTFUyn7GjxAa9vy8i\n2QIDAQAB\n-----END PUBLIC KEY-----\n" message_actual = "This is the real message." message_fake = "This is not the real message." @@ -166,32 +171,33 @@ def test_pub_key_with_no_headers_verification(self): class TestExistingKeyParsingWithPythonRSA(unittest.TestCase, ExistingKeyParsingMixin): - def setUp(self): self.key_class = crypto.PythonRSAKey -@unittest.skipIf(not crypto.M2CRYPTO_EXISTS, "Skipping M2Crypto test as it does not appear to be installed.") +@unittest.skipIf( + not crypto.M2CRYPTO_EXISTS, "Skipping M2Crypto test as it does not appear to be installed." +) class TestExistingKeyParsingWithM2Crypto(unittest.TestCase, ExistingKeyParsingMixin): - def setUp(self): self.key_class = crypto.M2CryptoKey -@unittest.skipIf(not crypto.CRYPTOGRAPHY_EXISTS, "Skipping python-cryptography test as it does not appear to be installed.") +@unittest.skipIf( + not crypto.CRYPTOGRAPHY_EXISTS, + "Skipping python-cryptography test as it does not appear to be installed.", +) class TestExistingKeyParsingWithPythonCryptography(unittest.TestCase, ExistingKeyParsingMixin): - def setUp(self): self.key_class = crypto.CryptographyKey class StringEncodingVariationsMixin(object): - priv_key_string = "-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAuABOgZEZ0pxp2hoYnTrYFoqQtzOEeTrjwTULV2v+zjyuT4f/\nIZylz4TH1MgmUMbn7/nu6dsfCYc87hx16fbhcUdZpiAW0Lb0mfnHxUwJKrBHmdr/\nMF8smN1a4OjOJ5O9ugAoijhG+Pb+SUh4tFSRv1vx68CyfxMSK2g/5jGJWlyh1K9Y\noBKXOtsXQQppl+4N4Stve9qFfsyjIW/FNlya3qmQDe9p9r5Ir7YEIS090rCOCEA3\nyiQ8gFThzCVK8Xlu3R/vclrhfvxhJWSJS5z5QRQ0QaZY+/A4b940yDLluRGViHKq\nagMvaKrcTO/fOAa257eSTFUyn7GjxAa9vy8i2QIDAQABAoIBAAiuWwXZ5rH9FzFn\nEco5QICvwOwjzhg6Iwy2h/Zz7e2lB0RRUkQvs9L6nML5PnWJLOAxlogKAojcjI9f\nYGDNeQ1zJFOmJ+1o9FlfY4F3eOc+seIcZvXNR7lemC8MTM2pNsZTw5Xh2dddL9od\nRTSc2NOCbwOEb+d26uCJZpphs+1DZQ5UYPgdu3N+wna5+OdZra1waqZqm1DFKbFT\nVx1PEPH4zyX5jhNP7MFW4W/u96gqAHVaPbkiycuEnxClidZapFrAqaQjFWCA6OPz\nCoNsy+n5fGD5eDIwI/AQQULRAQm35IW6zFmHrdB2q5Aeg87cclhdRnLXx7HQzfWZ\nKetBogECgYEA48mcaU69f4o8E7OCqGKP905MOXT9b1oRC7HRIhcSV3QKlxl/0VY/\nL9A64hn92ByWsyfWbkWjchK3mz2KGi9j1TaoErMLcfxWhcmvHCHIkYjmpilspKfp\nHNAM530C24+7POMcQiT6Q+KIapWyLffpmXHQPd4Z9p11KFx6gQ6hHtECgYEAzspg\nKD0889I32wa0fohHe6fk1Wtv/Fz+SRJ5LYAk/CCfisYDTA2ejayChSXzfPc0oPlb\n9EqBNd6tShhTc1VrJp3F/M4nPN/ZvHzVA/ndu5vpeAiBzdtzjttp3W7Ea01bym++\nOYvnhoDLrG80GCH0nJDCqtuqoYxLvB3Ek8EmlYkCgYAxgSh4Dn/Kjx1dXr7/n2QQ\naDjSp+VIZPedZgjAcukujm6axhTsRuU2m/egGev8IsJxry/ACWxrJzw2BdrUtAXr\nWZSPc9AB9shLDTj8US9Iycruw8PzyPY1p9WWHaoYU5VqtyT2DxlA1aO2HlB6Aw4G\npiCOwY089p12pxqMn8ROcQKBgHJZVnLp6hqp1Fk5i/WsRlsKrG+XyYUzpymhHYEb\nq1gAcji65nfX0CVnj4UxR0ODL4cUXNTpnim7yPeAHCVaxrXD6Qeyt9/hqPWh0ekw\n8nwb6y6FBcJf57bHffMEnXj4fhmjUP1hb9Xgwr/HfncZz7oEEqGIdwJ+IiMUEu/h\njwSBAoGACN/OWrCnLDDqb9kXXIsqx+oJpo311PW39JipU1yEB5Z1PAHw6/qm0PzU\nwCQ+UUbIhdrfdWEs+pPVa4qFNIjVatNdOL5heJzY6ZGQOCV2xv+qX9vuuN962rUk\nmQW3SLGIqqvUDV3Z2nfBwV5L3qbPuGm21PliMUQQOggjx+UIjOo=\n-----END RSA PRIVATE KEY-----" normal_string = "here is a snowman: ☃!" byte_string = b"here is a snowman: \xe2\x98\x83!" - unicode_string = u"here is a snowman: ☃!" + unicode_string = "here is a snowman: ☃!" signature = "Ml95gR/0M6wpW+wNo+4DZjumlTzVQALw75gngJh3h4fRRkBQGSnfGvKq/FUTre+OMVmgwSGAE91+A8d5CDmCWVosUczQIJGUB4KBa4sVCBn3cZFD3MDL23Bc1EOebMCYt6WGznXu+Wb/m/AyBHIsNGCU3H0cTtWT9ST8NhEF3mHb/nei9mgE8n8KL1UmlIGSsbTxbdEK9JMgf5ZdYjm3p6aHoj/P1EmTFt31mScO4z8IBuH1RdfqMFdU8JKMOnQy6I4f943Y5NXH/pR0d+Y2JMEsoUvHmNU2FDp1SofiQSNBsXOBSBYa09/SgL6dFtqf7JKwepI7LSKSL1suAwF6Kg==" @@ -207,20 +213,24 @@ def test_signature_verifies_across_encodings(self): class TestStringEncodingVariationsWithPythonRSA(unittest.TestCase, StringEncodingVariationsMixin): - def setUp(self): self.key = crypto.PythonRSAKey(private_key_string=self.priv_key_string) -@unittest.skipIf(not crypto.M2CRYPTO_EXISTS, "Skipping M2Crypto test as it does not appear to be installed.") +@unittest.skipIf( + not crypto.M2CRYPTO_EXISTS, "Skipping M2Crypto test as it does not appear to be installed." +) class TestStringEncodingVariationsWithM2Crypto(unittest.TestCase, StringEncodingVariationsMixin): - def setUp(self): self.key = crypto.M2CryptoKey(private_key_string=self.priv_key_string) -@unittest.skipIf(not crypto.CRYPTOGRAPHY_EXISTS, "Skipping python-cryptography test as it does not appear to be installed.") -class TestStringEncodingVariationsWithPythonCryptography(unittest.TestCase, StringEncodingVariationsMixin): - +@unittest.skipIf( + not crypto.CRYPTOGRAPHY_EXISTS, + "Skipping python-cryptography test as it does not appear to be installed.", +) +class TestStringEncodingVariationsWithPythonCryptography( + unittest.TestCase, StringEncodingVariationsMixin +): def setUp(self): self.key = crypto.CryptographyKey(private_key_string=self.priv_key_string) From 50b6605d10470a54c6a88fc2d2289fdf29bf6216 Mon Sep 17 00:00:00 2001 From: Blaine Jester Date: Fri, 23 Oct 2026 11:39:45 -0700 Subject: [PATCH 3/5] Remove ruff exclude list The list predates ruff. It came from the flake8 config with no recorded reason, and with ruff it also skipped import sorting and formatting. The migrations pattern matched no files. Co-Authored-By: Claude Opus 5.5 (1M context) --- pyproject.toml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ee1dd8a0..e01ad118 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -102,14 +102,6 @@ git_describe_command = "git describe --dirty --tags --long --match 'v*' --first- [tool.ruff] line-length = 100 -exclude = [ - "morango/*/migrations/*", - "docs", - "morango/sync/operations.py", - "morango/sync/backends/postgres.py", - "morango/sync/backends/sqlite.py", - "tests/testapp/tests/test_crypto.py", -] [tool.ruff.lint] select = [ From c95840f71b2f4fdf319547e3331e8eba8c8ca3a1 Mon Sep 17 00:00:00 2001 From: Blaine Jester Date: Fri, 23 Oct 2026 11:39:45 -0700 Subject: [PATCH 4/5] Ignore ruff reformat commit in git blame Co-Authored-By: Claude Opus 5.5 (1M context) --- .git-blame-ignore-revs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index f2b7301a..da78ba22 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -6,3 +6,6 @@ # Import reformatting cff1e87a0d742be463d820382f467115fb18c8a2 + +# Reformat files previously excluded from ruff +ca41d10a8aa8bbd5f6715896e5878e4f0789af93 From ecf390e0f566cf011882aabfb6cee9e473efac1f Mon Sep 17 00:00:00 2001 From: Blaine Jester Date: Fri, 23 Oct 2026 11:39:45 -0700 Subject: [PATCH 5/5] Remove stale make lint target It ran pre-commit, which the project replaced with prek. Run `prek run --all-files` instead. Co-Authored-By: Claude Opus 5.5 (1M context) --- Makefile | 3 --- 1 file changed, 3 deletions(-) diff --git a/Makefile b/Makefile index 5688594a..772724fc 100644 --- a/Makefile +++ b/Makefile @@ -74,9 +74,6 @@ clean-test: ## remove test and coverage artifacts rm -f .coverage rm -fr htmlcov/ -lint: - pre-commit run --all-files - migrations: python tests/testapp/manage.py makemigrations