From 4c14aacae435d59e67076846c4727f8308eae1d9 Mon Sep 17 00:00:00 2001 From: Squeaky Date: Mon, 14 Feb 2022 14:09:04 +0100 Subject: [PATCH 1/3] Fix outstading simplify codes that could not be done on Python 2 --- .flake8 | 6 ------ inbox/actions/backends/generic.py | 7 +++---- inbox/actions/backends/gmail.py | 7 +++---- inbox/api/kellogs.py | 2 +- inbox/api/ns_api.py | 7 +++---- inbox/api/validation.py | 5 ++--- inbox/auth/base.py | 2 +- inbox/auth/generic.py | 2 +- inbox/auth/google.py | 2 +- inbox/auth/microsoft.py | 2 +- inbox/client/client.py | 5 ++--- inbox/client/restful_model_collection.py | 7 ++----- inbox/contacts/carddav.py | 2 +- inbox/contacts/google.py | 2 +- inbox/contacts/icloud.py | 8 ++++---- inbox/contacts/search.py | 2 +- inbox/contacts/vcard.py | 6 ++---- inbox/crispin.py | 4 ++-- inbox/events/google.py | 2 +- inbox/heartbeat/store.py | 6 +++--- inbox/ignition.py | 2 +- inbox/instrumentation.py | 6 +++--- inbox/logging.py | 9 +++------ inbox/mailsync/backends/gmail.py | 3 +-- inbox/mailsync/backends/imap/generic.py | 5 ++--- inbox/mailsync/frontend.py | 2 +- inbox/mailsync/service.py | 2 +- inbox/models/backends/oauth.py | 4 ++-- inbox/models/event.py | 5 ++--- inbox/models/mixins.py | 10 +++++----- inbox/models/roles.py | 2 +- inbox/models/when.py | 5 ++--- inbox/scheduling/event_queue.py | 4 ++-- inbox/scheduling/queue.py | 4 ++-- inbox/search/backends/gmail.py | 2 +- inbox/search/backends/imap.py | 2 +- inbox/security/oracles.py | 2 +- inbox/sendmail/smtp/postel.py | 4 ++-- inbox/sqlalchemy_ext/util.py | 11 +++-------- inbox/transactions/actions.py | 4 ++-- inbox/util/file.py | 2 +- inbox/util/misc.py | 2 +- inbox/util/testutils.py | 8 ++++---- tests/api/base.py | 2 +- tests/api/test_searching.py | 2 +- tests/api/test_sending.py | 10 +++++----- tests/general/test_concurrency.py | 4 ++-- tests/general/test_required_folders.py | 4 ++-- tests/util/base.py | 4 ++-- 49 files changed, 92 insertions(+), 120 deletions(-) diff --git a/.flake8 b/.flake8 index 593efbc6e..8e6daeebe 100644 --- a/.flake8 +++ b/.flake8 @@ -18,12 +18,6 @@ ignore= E203, W503, W504, - # Use 'class Klass:' instead of 'class Klass(object), can't do this on Python 2 - SIM120, - # use yield from, can't do this on Python 2 - SIM104, - # use contextlib.suppress, can't do this on Python 2 - SIM105, SIM106, SIM110, SIM111, diff --git a/inbox/actions/backends/generic.py b/inbox/actions/backends/generic.py index 51002e3ab..7499eacde 100644 --- a/inbox/actions/backends/generic.py +++ b/inbox/actions/backends/generic.py @@ -2,6 +2,7 @@ """ Operations for syncing back local datastore changes to generic IMAP providers. """ +import contextlib from collections import defaultdict from imaplib import IMAP4 @@ -149,12 +150,10 @@ def remote_delete_folder(crispin_client, account_id, category_id): return display_name = category.display_name - try: - crispin_client.conn.delete_folder(display_name) - except IMAP4.error: + with contextlib.suppress(IMAP4.error): # Folder has already been deleted on remote. Treat delete as # no-op. - pass + crispin_client.conn.delete_folder(display_name) # TODO @karim: Make the main sync loop detect folder renames # more accurately, and get rid of this. diff --git a/inbox/actions/backends/gmail.py b/inbox/actions/backends/gmail.py index 970cd1e11..33bf52a64 100644 --- a/inbox/actions/backends/gmail.py +++ b/inbox/actions/backends/gmail.py @@ -1,5 +1,6 @@ """ Operations for syncing back local datastore changes to Gmail. """ +import contextlib from imaplib import IMAP4 import imapclient @@ -62,12 +63,10 @@ def remote_delete_label(crispin_client, account_id, category_id): return display_name = category.display_name - try: - crispin_client.conn.delete_folder(display_name) - except IMAP4.error: + with contextlib.suppress(IMAP4.error): # Label has already been deleted on remote. Treat delete as # no-op. - pass + crispin_client.conn.delete_folder(display_name) # TODO @karim --- the main sync loop has a hard time detecting # Gmail renames because of a Gmail issue (see https://github.com/nylas/sync-engine/blob/c99656df3c048faf7951e54d74cb5ef9d7dc3c97/inbox/mailsync/gc.py#L146 for more details). diff --git a/inbox/api/kellogs.py b/inbox/api/kellogs.py index 561372a9a..8d04f02e9 100644 --- a/inbox/api/kellogs.py +++ b/inbox/api/kellogs.py @@ -415,7 +415,7 @@ def _get_lowercase_class_name(obj): return resp -class APIEncoder(object): +class APIEncoder: """ Provides methods for serializing Nylas objects. If the optional namespace_public_id parameter is passed, it will be bound and used instead diff --git a/inbox/api/ns_api.py b/inbox/api/ns_api.py index 23654550f..762590f30 100644 --- a/inbox/api/ns_api.py +++ b/inbox/api/ns_api.py @@ -1,4 +1,5 @@ import base64 +import contextlib import itertools import json import os @@ -124,11 +125,9 @@ from inbox.util.misc import imap_folder_path from inbox.util.stats import statsd_client -try: - from inbox.util.eas.codes import STORE_STATUS_CODES -except ImportError: +with contextlib.suppress(ImportError): # Only important for EAS search failures, so shouldn't trigge test fail - pass + from inbox.util.eas.codes import STORE_STATUS_CODES from inbox.logging import get_logger diff --git a/inbox/api/validation.py b/inbox/api/validation.py index 12ff9eeb3..024404683 100644 --- a/inbox/api/validation.py +++ b/inbox/api/validation.py @@ -1,4 +1,5 @@ """Utilities for validating user input to the API.""" +import contextlib from builtins import str import arrow @@ -129,10 +130,8 @@ def valid_category_type(category_type, rule): def timestamp(value, key): try: - try: + with contextlib.suppress(ValueError): value = float(value) - except ValueError: - pass return arrow.get(value).datetime except ValueError: diff --git a/inbox/auth/base.py b/inbox/auth/base.py index 2f6cad6f2..f0a83cb5e 100644 --- a/inbox/auth/base.py +++ b/inbox/auth/base.py @@ -41,7 +41,7 @@ def handler_from_provider(provider_name): ) -class AuthHandler(object): +class AuthHandler: def create_account(self, account_data): """ Create a new account with the given subclass-specific account data. diff --git a/inbox/auth/generic.py b/inbox/auth/generic.py index f7ee5ee17..458d4508a 100644 --- a/inbox/auth/generic.py +++ b/inbox/auth/generic.py @@ -17,7 +17,7 @@ @attr.s -class GenericAccountData(object): +class GenericAccountData: email = attr.ib() imap_server_host = attr.ib() diff --git a/inbox/auth/google.py b/inbox/auth/google.py index 7e5c6c58b..74ba8e630 100644 --- a/inbox/auth/google.py +++ b/inbox/auth/google.py @@ -20,7 +20,7 @@ @attr.s -class GoogleAccountData(object): +class GoogleAccountData: email = attr.ib() secret_type = attr.ib() diff --git a/inbox/auth/microsoft.py b/inbox/auth/microsoft.py index 443a459ad..a13cd46c7 100644 --- a/inbox/auth/microsoft.py +++ b/inbox/auth/microsoft.py @@ -15,7 +15,7 @@ @attr.s -class MicrosoftAccountData(object): +class MicrosoftAccountData: email = attr.ib() secret_type = attr.ib() diff --git a/inbox/client/client.py b/inbox/client/client.py index fb74dc39a..eac45fba3 100644 --- a/inbox/client/client.py +++ b/inbox/client/client.py @@ -1,3 +1,4 @@ +import contextlib import json import sys from os import environ @@ -67,10 +68,8 @@ def _validate(response): ) ) - try: + with contextlib.suppress(ValueError, TypeError): data = json.loads(data) if data else None - except (ValueError, TypeError): - pass if status_code == 200: return response diff --git a/inbox/client/restful_model_collection.py b/inbox/client/restful_model_collection.py index 11a90c5fa..ef186d879 100644 --- a/inbox/client/restful_model_collection.py +++ b/inbox/client/restful_model_collection.py @@ -3,7 +3,7 @@ CHUNK_SIZE = 50 -class RestfulModelCollection(object): +class RestfulModelCollection: def __init__(self, cls, api, filter=None, offset=0, **filters): filter = filter or {} filters.update(filter) @@ -25,11 +25,8 @@ def items(self): offset = self.filters["offset"] while True: items = self._get_model_collection(offset, CHUNK_SIZE) - if not items: - break - for item in items: - yield item + yield from items if len(items) < CHUNK_SIZE: break diff --git a/inbox/contacts/carddav.py b/inbox/contacts/carddav.py index 5bd8f2b9c..2be5bd0d0 100644 --- a/inbox/contacts/carddav.py +++ b/inbox/contacts/carddav.py @@ -41,7 +41,7 @@ def supports_carddav(url): raise Exception("URL is not a CardDAV resource") -class CardDav(object): +class CardDav: """ NOTE: Only supports iCloud for now """ def __init__(self, email_address, password, base_url): diff --git a/inbox/contacts/google.py b/inbox/contacts/google.py index e99bd7190..527132893 100644 --- a/inbox/contacts/google.py +++ b/inbox/contacts/google.py @@ -27,7 +27,7 @@ SOURCE_APP_NAME = "Nylas Sync Engine" -class GoogleContactsProvider(object): +class GoogleContactsProvider: """ A utility class to fetch and parse Google contact data for the specified account using the Google Contacts API. diff --git a/inbox/contacts/icloud.py b/inbox/contacts/icloud.py index 6a9b7ccf5..cf36b8e02 100644 --- a/inbox/contacts/icloud.py +++ b/inbox/contacts/icloud.py @@ -1,6 +1,8 @@ """Provide iCloud contacts""" from __future__ import absolute_import +import contextlib + import lxml.etree as ET from inbox.contacts.carddav import supports_carddav @@ -17,7 +19,7 @@ ICLOUD_CONTACTS_URL = "https://contacts.icloud.com" -class ICloudContactsProvider(object): +class ICloudContactsProvider: """ Base class to fetch and parse iCloud contacts """ @@ -39,10 +41,8 @@ def _vCard_raw_to_contact(self, cardstring): def _x(key): # Ugly parsing helper for ugly formats if key in card: - try: + with contextlib.suppress(IndexError): return card[key][0][0] - except IndexError: - pass # Skip contact groups for now if _x("X-ADDRESSBOOKSERVER-KIND") == "group": diff --git a/inbox/contacts/search.py b/inbox/contacts/search.py index f368f23c8..4af088df2 100644 --- a/inbox/contacts/search.py +++ b/inbox/contacts/search.py @@ -85,7 +85,7 @@ def cloudsearch_contact_repr(contact): } -class ContactSearchClient(object): +class ContactSearchClient: """ Search client that talks to AWS CloudSearch (or a compatible API). """ def __init__(self, namespace_id): diff --git a/inbox/contacts/vcard.py b/inbox/contacts/vcard.py index f0f007170..69547d9da 100644 --- a/inbox/contacts/vcard.py +++ b/inbox/contacts/vcard.py @@ -27,6 +27,7 @@ from __future__ import absolute_import, print_function import base64 +import contextlib import logging import sys from builtins import range @@ -172,12 +173,9 @@ def vcard_from_vobject(vcard): property_name = line.name property_value = line.value - try: + with contextlib.suppress(AttributeError): if line.ENCODING_paramlist == [u"b"] or line.ENCODING_paramlist == [u"B"]: property_value = base64.b64encode(line.value) - - except AttributeError: - pass if isinstance(property_value, list): property_value = (",").join(property_value) diff --git a/inbox/crispin.py b/inbox/crispin.py index 3515587c5..fb35c73cb 100644 --- a/inbox/crispin.py +++ b/inbox/crispin.py @@ -175,7 +175,7 @@ def writable_connection_pool(account_id, pool_size=1): return _get_connection_pool(account_id, pool_size, _writable_pool_map, False) -class CrispinConnectionPool(object): +class CrispinConnectionPool: """ Connection pool for Crispin clients. @@ -309,7 +309,7 @@ def _exc_callback(exc): ) -class CrispinClient(object): +class CrispinClient: """ Generic IMAP client wrapper. diff --git a/inbox/events/google.py b/inbox/events/google.py index 541a30b96..24516f561 100644 --- a/inbox/events/google.py +++ b/inbox/events/google.py @@ -51,7 +51,7 @@ WATCH_EVENTS_URL = "https://www.googleapis.com/calendar/v3/calendars/{}/events/watch" -class GoogleEventsProvider(object): +class GoogleEventsProvider: """ A utility class to fetch and parse Google calendar data for the specified account using the Google Calendar API. diff --git a/inbox/heartbeat/store.py b/inbox/heartbeat/store.py index 326fcda36..5d19e3897 100644 --- a/inbox/heartbeat/store.py +++ b/inbox/heartbeat/store.py @@ -22,7 +22,7 @@ def wrapper(*args, **kwargs): return wrapper -class HeartbeatStatusKey(object): +class HeartbeatStatusKey: def __init__(self, account_id, folder_id): self.account_id = account_id self.folder_id = folder_id @@ -57,7 +57,7 @@ def from_string(cls, string_key): return cls(account_id, folder_id) -class HeartbeatStatusProxy(object): +class HeartbeatStatusProxy: def __init__( self, account_id, @@ -93,7 +93,7 @@ def clear(self): self.store.remove_folders(self.account_id, self.folder_id, self.device_id) -class HeartbeatStore(object): +class HeartbeatStore: """ Store that proxies requests to Redis with handlers that also update indexes and handle scanning through results. """ diff --git a/inbox/ignition.py b/inbox/ignition.py index 201180db0..9a814f3f6 100644 --- a/inbox/ignition.py +++ b/inbox/ignition.py @@ -123,7 +123,7 @@ def receive_checkin(dbapi_connection, connection_record): return engine -class EngineManager(object): +class EngineManager: def __init__(self, databases, users, include_disabled=False): self.engines = {} self._engine_zones = {} diff --git a/inbox/instrumentation.py b/inbox/instrumentation.py index 3fbe0b967..c9978d87b 100644 --- a/inbox/instrumentation.py +++ b/inbox/instrumentation.py @@ -26,7 +26,7 @@ LOGGING_INTERVAL = 60 -class ProfileCollector(object): +class ProfileCollector: """A simple stack sampler for low-overhead CPU profiling: samples the call stack every `interval` seconds and keeps track of counts by frame. Because this uses signals, it only works on the main thread.""" @@ -74,7 +74,7 @@ def reset(self): self._stack_counts = collections.defaultdict(int) -class GreenletTracer(object): +class GreenletTracer: """Log if a greenlet blocks the event loop for too long, and optionally log statistics on time spent in individual greenlets. @@ -286,7 +286,7 @@ def _notify_greenlet_blocked(self, active_greenlet, current_time): MAX_BLOCKING_TIME = 5 -class Tracer(object): +class Tracer: """Log if a greenlet blocks the event loop for too long, and optionally log statistics on time spent in individual greenlets. diff --git a/inbox/logging.py b/inbox/logging.py index 2f4d6c698..22b07c6bd 100644 --- a/inbox/logging.py +++ b/inbox/logging.py @@ -7,6 +7,7 @@ """ from __future__ import absolute_import +import contextlib import logging import logging.handlers import os @@ -345,17 +346,13 @@ def create_error_log_context(exc_info): out["error_code"] = exc_value.code if hasattr(exc_value, "args") and hasattr(exc_value.args, "__getitem__"): - try: + with contextlib.suppress(IndexError): out["error_message"] = exc_value.args[0] - except IndexError: - pass - try: + with contextlib.suppress(Exception): if exc_tb: tb = safe_format_exception(exc_type, exc_value, exc_tb) if tb: out["error_traceback"] = tb - except Exception: - pass return out diff --git a/inbox/mailsync/backends/gmail.py b/inbox/mailsync/backends/gmail.py index ce526c0fd..e8e19dd63 100644 --- a/inbox/mailsync/backends/gmail.py +++ b/inbox/mailsync/backends/gmail.py @@ -491,8 +491,7 @@ def expand_uids_to_download(self, crispin_client, uids, metadata): if g_thrid != g_msgid: uids = set(uids).union(crispin_client.expand_thread(g_thrid)) metadata.update(crispin_client.g_metadata(uids)) - for uid in sorted(uids, reverse=True): - yield uid + yield from sorted(uids, reverse=True) def batch_download_uids( self, diff --git a/inbox/mailsync/backends/imap/generic.py b/inbox/mailsync/backends/imap/generic.py index c605c45b0..2d49239f0 100644 --- a/inbox/mailsync/backends/imap/generic.py +++ b/inbox/mailsync/backends/imap/generic.py @@ -62,6 +62,7 @@ """ from __future__ import division +import contextlib import imaplib import time from datetime import datetime, timedelta @@ -486,12 +487,10 @@ def poll_impl(self): raise log.info("Error initiating IDLE, not idling", error=exc) - try: + with contextlib.supress(AttributeError): # Still have to take the connection out of IDLE # mode to reuse it though. crispin_client.conn.idle_done() - except AttributeError: - pass idling = False else: raise diff --git a/inbox/mailsync/frontend.py b/inbox/mailsync/frontend.py index e4d3d2255..9b6e06113 100644 --- a/inbox/mailsync/frontend.py +++ b/inbox/mailsync/frontend.py @@ -7,7 +7,7 @@ from inbox.instrumentation import GreenletTracer, KillerGreenletTracer, ProfileCollector -class HTTPFrontend(object): +class HTTPFrontend: """This is a lightweight embedded HTTP server that runs inside a mailsync or syncback process. It allows you to programmatically interact with the process: to get profile/memory/load metrics, or to schedule new account diff --git a/inbox/mailsync/service.py b/inbox/mailsync/service.py index d22b07049..1ee9f9c36 100644 --- a/inbox/mailsync/service.py +++ b/inbox/mailsync/service.py @@ -46,7 +46,7 @@ def shared_sync_event_queue_for_zone(zone): return SHARED_SYNC_EVENT_QUEUE_ZONE_MAP[queue_name] -class SyncService(object): +class SyncService: """ Parameters ---------- diff --git a/inbox/models/backends/oauth.py b/inbox/models/backends/oauth.py index 566cf5fc7..9e9731826 100644 --- a/inbox/models/backends/oauth.py +++ b/inbox/models/backends/oauth.py @@ -37,7 +37,7 @@ def log_token_usage(reason, refresh_token=None, access_token=None, account=None) ) -class TokenManager(object): +class TokenManager: def __init__(self): self._tokens = {} @@ -67,7 +67,7 @@ def cache_token(self, account, token, expires_in): token_manager = TokenManager() -class OAuthAccount(object): +class OAuthAccount: @declared_attr def refresh_token_id(cls): return Column(ForeignKey(Secret.id), nullable=False) diff --git a/inbox/models/event.py b/inbox/models/event.py index 2a2b2e7a9..8342aa37b 100644 --- a/inbox/models/event.py +++ b/inbox/models/event.py @@ -1,4 +1,5 @@ import ast +import contextlib import json from datetime import datetime from email.utils import parseaddr @@ -70,10 +71,8 @@ def time_parse(x): # type: (Union[float, int, str, arrow.Arrow]) -> arrow.Arrow - try: + with contextlib.suppress(ValueError, TypeError): x = float(x) - except (ValueError, TypeError): - pass return arrow.get(x).to("utc").naive diff --git a/inbox/models/mixins.py b/inbox/models/mixins.py index fe9dade64..ea17237b8 100644 --- a/inbox/models/mixins.py +++ b/inbox/models/mixins.py @@ -77,7 +77,7 @@ def has_versioned_changes(self): return False -class HasPublicID(object): +class HasPublicID: public_id = Column( Base36UID, nullable=False, index=True, default=generate_public_id ) @@ -101,7 +101,7 @@ def __eq__(self, other): return func.lower(self.__clause_element__()) == func.lower(other) -class HasEmailAddress(object): +class HasEmailAddress: """ Provides an email_address attribute, which returns as value whatever you set it to, but uses a canonicalized form for comparisons. So e.g. @@ -139,11 +139,11 @@ def email_address(self, value): self._canonicalized_address = canonicalize_address(value) -class CreatedAtMixin(object): +class CreatedAtMixin: created_at = Column(DateTime, server_default=func.now(), nullable=False, index=True) -class UpdatedAtMixin(object): +class UpdatedAtMixin: updated_at = Column( DateTime, default=datetime.utcnow, @@ -153,7 +153,7 @@ class UpdatedAtMixin(object): ) -class DeletedAtMixin(object): +class DeletedAtMixin: deleted_at = Column(DateTime, nullable=True, index=True) diff --git a/inbox/models/roles.py b/inbox/models/roles.py index 5c4813ecc..038bae49b 100644 --- a/inbox/models/roles.py +++ b/inbox/models/roles.py @@ -16,7 +16,7 @@ STORE_MESSAGE_ATTACHMENTS = config.get("STORE_MESSAGE_ATTACHMENTS", True) -class Blob(object): +class Blob: """ A blob of data that can be saved to local or remote (S3) disk. """ size = Column(Integer, default=0) diff --git a/inbox/models/when.py b/inbox/models/when.py index d73d08e97..b2e21cf1d 100644 --- a/inbox/models/when.py +++ b/inbox/models/when.py @@ -1,4 +1,5 @@ import abc +import contextlib from typing import Union import arrow @@ -27,10 +28,8 @@ def parse_as_when(raw): def parse_utc(datetime): # type: (Union[float, int, str, arrow.Arrow]) -> arrow.Arrow # Arrow can handle epoch timestamps as well as most ISO-8601 strings - try: + with contextlib.suppress(ValueError, TypeError): datetime = float(datetime) - except (ValueError, TypeError): - pass return arrow.get(datetime).to("utc") diff --git a/inbox/scheduling/event_queue.py b/inbox/scheduling/event_queue.py index ff76c6212..6f1f886aa 100644 --- a/inbox/scheduling/event_queue.py +++ b/inbox/scheduling/event_queue.py @@ -22,7 +22,7 @@ def _get_redis_client(host=None, port=6379, db=1): ) -class EventQueue(object): +class EventQueue: """Simple queue that clients can listen to and wait to be notified of some event that they're interested in. """ @@ -87,7 +87,7 @@ def send_event(self, event_data): self.redis.rpush(self.queue_name, json.dumps(event_data)) -class EventQueueGroup(object): +class EventQueueGroup: """Group of queues that can all be simultaneously watched for new events.""" def __init__(self, queues): diff --git a/inbox/scheduling/queue.py b/inbox/scheduling/queue.py index 890824e2c..814c861eb 100644 --- a/inbox/scheduling/queue.py +++ b/inbox/scheduling/queue.py @@ -38,7 +38,7 @@ SOCKET_TIMEOUT = 5 -class QueueClient(object): +class QueueClient: """Interface to a Redis queue/hashmap combo for managing account sync allocation. """ @@ -128,7 +128,7 @@ def _hash(self): return "assigned_{}".format(self.zone) -class QueuePopulator(object): +class QueuePopulator: """ Polls the database for account ids to sync and queues them. Run one of these per zone. diff --git a/inbox/search/backends/gmail.py b/inbox/search/backends/gmail.py index 713b72e3f..a76ebe0c6 100644 --- a/inbox/search/backends/gmail.py +++ b/inbox/search/backends/gmail.py @@ -18,7 +18,7 @@ SEARCH_CLS = "GmailSearchClient" -class GmailSearchClient(object): +class GmailSearchClient: def __init__(self, account): self.account_id = int(account.id) try: diff --git a/inbox/search/backends/imap.py b/inbox/search/backends/imap.py index 151d97bcf..108afcf9c 100644 --- a/inbox/search/backends/imap.py +++ b/inbox/search/backends/imap.py @@ -18,7 +18,7 @@ PROVIDER = "imap" -class IMAPSearchClient(object): +class IMAPSearchClient: def __init__(self, account): self.account = account self.account_id = account.id diff --git a/inbox/security/oracles.py b/inbox/security/oracles.py index c955c24cc..009cc1479 100644 --- a/inbox/security/oracles.py +++ b/inbox/security/oracles.py @@ -36,7 +36,7 @@ def get_decryption_oracle(secret_name): return _DecryptionOracle(secret_name) -class _EncryptionOracle(object): +class _EncryptionOracle: """ This object is responsible for encryption only. diff --git a/inbox/sendmail/smtp/postel.py b/inbox/sendmail/smtp/postel.py index d463b8193..ed1a90aa8 100644 --- a/inbox/sendmail/smtp/postel.py +++ b/inbox/sendmail/smtp/postel.py @@ -118,7 +118,7 @@ def _substitute_bcc(raw_message): return bcc_regexp.sub(b"", raw_message) -class SMTPConnection(object): +class SMTPConnection: def __init__( self, account_id, @@ -276,7 +276,7 @@ def sendmail(self, recipients, msg): raise SendMailException("Invalid character in recipient address", 402) -class SMTPClient(object): +class SMTPClient: """ SMTPClient for Gmail and other IMAP providers. """ def __init__(self, account): diff --git a/inbox/sqlalchemy_ext/util.py b/inbox/sqlalchemy_ext/util.py index e34585d20..97d479f05 100644 --- a/inbox/sqlalchemy_ext/util.py +++ b/inbox/sqlalchemy_ext/util.py @@ -67,7 +67,7 @@ def before_commit(conn): ) -class ABCMixin(object): +class ABCMixin: """Use this if you want a mixin class which is actually an abstract base class, for example in order to enforce that concrete subclasses define particular methods or properties.""" @@ -303,10 +303,8 @@ def utf8_surrogate_fix_decode(memory, errors="strict"): # type: (memoryview, str) -> Tuple[str, int] binary = memory.tobytes() - try: + with contextlib.suppress(UnicodeDecodeError): return binary.decode("utf-8", errors), len(binary) - except UnicodeDecodeError: - pass text = binary.decode("utf-8", "surrogatepass") @@ -382,8 +380,5 @@ def safer_yield_per(query, id_field, start_id, count): cur_id = start_id while True: results = query.filter(id_field >= cur_id).order_by(id_field).limit(count).all() - if not results: - return - for result in results: - yield result + yield from results cur_id = results[-1].id + 1 diff --git a/inbox/transactions/actions.py b/inbox/transactions/actions.py index 95d359fbf..410cff7ad 100644 --- a/inbox/transactions/actions.py +++ b/inbox/transactions/actions.py @@ -523,7 +523,7 @@ def __del__(self): self.stop() -class SyncbackBatchTask(object): +class SyncbackBatchTask: def __init__(self, semaphore, tasks, account_id): self.semaphore = semaphore self.tasks = tasks @@ -565,7 +565,7 @@ def action_log_ids(self): return [entry for task in self.tasks for entry in task.action_log_ids] -class SyncbackTask(object): +class SyncbackTask: """ Task responsible for executing a single syncback action. We can retry the action up to ACTION_MAX_NR_OF_RETRIES times before we mark it as failed. diff --git a/inbox/util/file.py b/inbox/util/file.py index 9a7fb9120..d251009b9 100644 --- a/inbox/util/file.py +++ b/inbox/util/file.py @@ -63,7 +63,7 @@ def remove_file(filename): raise -class Lock(object): +class Lock: """ UNIX-specific exclusive file locks (released when the process ends). Based on diff --git a/inbox/util/misc.py b/inbox/util/misc.py index 881dc370e..217e67af0 100644 --- a/inbox/util/misc.py +++ b/inbox/util/misc.py @@ -13,7 +13,7 @@ from inbox.util.file import iter_module_names -class DummyContextManager(object): +class DummyContextManager: def __enter__(self): return None diff --git a/inbox/util/testutils.py b/inbox/util/testutils.py index c517fa269..db8b21496 100644 --- a/inbox/util/testutils.py +++ b/inbox/util/testutils.py @@ -75,7 +75,7 @@ def setup_test_db(): init_db(engine, key) -class MockAnswer(object): +class MockAnswer: def __init__(self, exchange): self.exchange = exchange @@ -83,7 +83,7 @@ def __str__(self): return self.exchange -class MockDNSResolver(object): +class MockDNSResolver: def __init__(self): self._registry = {"mx": {}, "ns": {}} @@ -136,7 +136,7 @@ def mock_query(self, domain, record_type): print(json.dumps(query_results, indent=4, sort_keys=True)) -class MockIMAPClient(object): +class MockIMAPClient: """A bare-bones stand-in for an IMAPClient instance, used to test sync logic without requiring a real IMAP account and server.""" @@ -291,7 +291,7 @@ def mock_imapclient(monkeypatch): monkeypatch.undo() -class MockSMTPClient(object): +class MockSMTPClient: def __init__(self): pass diff --git a/tests/api/base.py b/tests/api/base.py index 504c30f8f..9ec168ee9 100644 --- a/tests/api/base.py +++ b/tests/api/base.py @@ -10,7 +10,7 @@ def new_api_client(db, namespace): return TestAPIClient(c, namespace.public_id) -class TestAPIClient(object): +class TestAPIClient: """Provide more convenient access to the API for testing purposes.""" diff --git a/tests/api/test_searching.py b/tests/api/test_searching.py index 237cbd929..5cbcdd98f 100644 --- a/tests/api/test_searching.py +++ b/tests/api/test_searching.py @@ -207,7 +207,7 @@ def different_imap_messages( return [message1, message2, message3] -class MockImapConnection(object): +class MockImapConnection: def __init__(self): self.search_args = None diff --git a/tests/api/test_sending.py b/tests/api/test_sending.py index 37ada2e5c..111c52a53 100644 --- a/tests/api/test_sending.py +++ b/tests/api/test_sending.py @@ -22,7 +22,7 @@ __all__ = ["thread", "message", "imported_event"] -class MockTokenManager(object): +class MockTokenManager: def __init__(self, allow_auth=True): self.allow_auth = allow_auth @@ -49,7 +49,7 @@ def disallow_auth(monkeypatch): def patch_smtp(patch_token_manager, monkeypatch): submitted_messages = [] - class MockSMTPConnection(object): + class MockSMTPConnection: def __init__(self, *args, **kwargs): pass @@ -67,7 +67,7 @@ def sendmail(self, recipients, msg): def erring_smtp_connection(exc_type, *args): - class ErringSMTPConnection(object): + class ErringSMTPConnection: def __init__(self, *args, **kwargs): pass @@ -826,7 +826,7 @@ def fake_remote_delete_sent( ): return True - class FakeConnWrapper(object): + class FakeConnWrapper: def __init__(self): pass @@ -834,7 +834,7 @@ def __init__(self): def get(self): yield MockCrispinClient() - class MockCrispinClient(object): + class MockCrispinClient: def folder_names(self): return ["sent"] diff --git a/tests/general/test_concurrency.py b/tests/general/test_concurrency.py index 9112a3f57..b55eeeae5 100644 --- a/tests/general/test_concurrency.py +++ b/tests/general/test_concurrency.py @@ -8,7 +8,7 @@ from inbox.util.concurrency import retry_with_logging -class MockLogger(object): +class MockLogger: def __init__(self): self.call_count = 0 @@ -16,7 +16,7 @@ def error(self, *args, **kwargs): self.call_count += 1 -class FailingFunction(object): +class FailingFunction: __name__ = "FailingFunction" def __init__(self, exc_type, max_executions=3, delay=0): diff --git a/tests/general/test_required_folders.py b/tests/general/test_required_folders.py index 7168c2a33..650b89b6d 100644 --- a/tests/general/test_required_folders.py +++ b/tests/general/test_required_folders.py @@ -6,7 +6,7 @@ from inbox.crispin import GmailCrispinClient -class AccountStub(object): +class AccountStub: id = 0 email_address = "bob@bob.com" access_token = None @@ -20,7 +20,7 @@ def validate_token(self, new_token): return True -class ConnectionStub(object): +class ConnectionStub: def logout(self): pass diff --git a/tests/util/base.py b/tests/util/base.py index 04cf1e471..54a80ea54 100644 --- a/tests/util/base.py +++ b/tests/util/base.py @@ -90,7 +90,7 @@ def webhooks_client(db): yield TestWebhooksClient(c) -class TestWebhooksClient(object): +class TestWebhooksClient: def __init__(self, test_client): self.client = test_client @@ -203,7 +203,7 @@ def contacts_provider(config, db): return ContactsProviderStub() -class ContactsProviderStub(object): +class ContactsProviderStub: """ Contacts provider stub to stand in for an actual provider. When an instance's get_items() method is called, return an iterable of From b3a0aa34664cd861ba5417a9f347b27559b91b33 Mon Sep 17 00:00:00 2001 From: Squeaky Date: Mon, 14 Feb 2022 14:17:58 +0100 Subject: [PATCH 2/3] Simplify classes it complains about --- inbox/util/testutils.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/inbox/util/testutils.py b/inbox/util/testutils.py index db8b21496..d79e7b067 100644 --- a/inbox/util/testutils.py +++ b/inbox/util/testutils.py @@ -7,6 +7,7 @@ import re import subprocess +import attr import dns import pytest from past.builtins import basestring, long @@ -75,12 +76,9 @@ def setup_test_db(): init_db(engine, key) +@attr.s class MockAnswer: - def __init__(self, exchange): - self.exchange = exchange - - def __str__(self): - return self.exchange + exchange = attr.ib() class MockDNSResolver: @@ -292,8 +290,7 @@ def mock_imapclient(monkeypatch): class MockSMTPClient: - def __init__(self): - pass + pass @pytest.fixture From d10d1c0cac09f73130dc412c9e4a30558dacbf3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Sampaio?= Date: Mon, 14 Feb 2022 11:08:55 -0300 Subject: [PATCH 3/3] Tweaks to how we document exceptions in suppress --- inbox/actions/backends/generic.py | 4 ++-- inbox/actions/backends/gmail.py | 4 ++-- inbox/api/ns_api.py | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/inbox/actions/backends/generic.py b/inbox/actions/backends/generic.py index 7499eacde..5d08c2bb0 100644 --- a/inbox/actions/backends/generic.py +++ b/inbox/actions/backends/generic.py @@ -151,8 +151,8 @@ def remote_delete_folder(crispin_client, account_id, category_id): display_name = category.display_name with contextlib.suppress(IMAP4.error): - # Folder has already been deleted on remote. Treat delete as - # no-op. + # IMAP4.error: Folder has already been deleted on remote. Treat delete + # as no-op. crispin_client.conn.delete_folder(display_name) # TODO @karim: Make the main sync loop detect folder renames diff --git a/inbox/actions/backends/gmail.py b/inbox/actions/backends/gmail.py index 33bf52a64..5c4b26417 100644 --- a/inbox/actions/backends/gmail.py +++ b/inbox/actions/backends/gmail.py @@ -64,8 +64,8 @@ def remote_delete_label(crispin_client, account_id, category_id): display_name = category.display_name with contextlib.suppress(IMAP4.error): - # Label has already been deleted on remote. Treat delete as - # no-op. + # IMAP4.error: Label has already been deleted on remote. Treat delete + # as no-op. crispin_client.conn.delete_folder(display_name) # TODO @karim --- the main sync loop has a hard time detecting diff --git a/inbox/api/ns_api.py b/inbox/api/ns_api.py index 762590f30..e32d3952f 100644 --- a/inbox/api/ns_api.py +++ b/inbox/api/ns_api.py @@ -126,7 +126,8 @@ from inbox.util.stats import statsd_client with contextlib.suppress(ImportError): - # Only important for EAS search failures, so shouldn't trigge test fail + # ImportError: Only important for EAS search failures, so shouldn't trigger + # test failure. from inbox.util.eas.codes import STORE_STATUS_CODES