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 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 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 ce187f85..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, ) ) @@ -255,7 +257,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, @@ -263,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 @@ -470,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 e82ac7d4..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) @@ -196,16 +191,13 @@ 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, ) 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/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 = [ 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)