From 532bdbdbfe3371381541e016e2be75ee33388be3 Mon Sep 17 00:00:00 2001 From: Ivan Date: Fri, 28 Feb 2020 02:07:12 +0500 Subject: [PATCH] [IMP] sentry: black, isort --- sentry/__init__.py | 39 ++++++++------- sentry/__manifest__.py | 34 ++++++------- sentry/const.py | 92 +++++++++++++++++------------------ sentry/logutils.py | 56 +++++++++------------ sentry/tests/__init__.py | 5 +- sentry/tests/test_client.py | 45 ++++++++--------- sentry/tests/test_logutils.py | 73 +++++++++++++-------------- 7 files changed, 157 insertions(+), 187 deletions(-) diff --git a/sentry/__init__.py b/sentry/__init__.py index 968f6ae31..ccee682e4 100644 --- a/sentry/__init__.py +++ b/sentry/__init__.py @@ -22,41 +22,44 @@ except ImportError: def get_odoo_commit(odoo_dir): - '''Attempts to get Odoo git commit from :param:`odoo_dir`.''' + """Attempts to get Odoo git commit from :param:`odoo_dir`.""" if not odoo_dir: return try: return raven.fetch_git_sha(odoo_dir) except raven.exceptions.InvalidGitRepository: - _logger.debug( - 'Odoo directory: "%s" not a valid git repository', odoo_dir) + _logger.debug('Odoo directory: "%s" not a valid git repository', odoo_dir) def initialize_raven(config, client_cls=None): - ''' + """ Setup an instance of :class:`raven.Client`. :param config: Sentry configuration :param client: class used to instantiate the raven client. - ''' - enabled = config.get('sentry_enabled', False) + """ + enabled = config.get("sentry_enabled", False) if not (HAS_RAVEN and enabled): return - if config.get('sentry_odoo_dir') and config.get('sentry_release'): - _logger.debug('Both sentry_odoo_dir and sentry_release defined, choosing sentry_release') + if config.get("sentry_odoo_dir") and config.get("sentry_release"): + _logger.debug( + "Both sentry_odoo_dir and sentry_release defined, choosing sentry_release" + ) options = { - 'release': config.get('sentry_release', get_odoo_commit(config.get('sentry_odoo_dir'))), + "release": config.get( + "sentry_release", get_odoo_commit(config.get("sentry_odoo_dir")) + ) } for option in const.get_sentry_options(): - value = config.get('sentry_%s' % option.key, option.default) + value = config.get("sentry_%s" % option.key, option.default) if isinstance(option.converter, collections.Callable): value = option.converter(value) options[option.key] = value - level = config.get('sentry_logging_level', const.DEFAULT_LOG_LEVEL) + level = config.get("sentry_logging_level", const.DEFAULT_LOG_LEVEL) exclude_loggers = const.split_multiple( - config.get('sentry_exclude_loggers', const.DEFAULT_EXCLUDE_LOGGERS) + config.get("sentry_exclude_loggers", const.DEFAULT_EXCLUDE_LOGGERS) ) if level not in const.LOG_LEVEL_MAP: level = const.DEFAULT_LOG_LEVEL @@ -64,18 +67,18 @@ def initialize_raven(config, client_cls=None): client_cls = client_cls or raven.Client client = client_cls(**options) handler = OdooSentryHandler( - config.get('sentry_include_context', True), + config.get("sentry_include_context", True), client=client, level=const.LOG_LEVEL_MAP[level], ) if exclude_loggers: - handler.addFilter(LoggerNameFilter( - exclude_loggers, name='sentry.logger.filter')) + handler.addFilter( + LoggerNameFilter(exclude_loggers, name="sentry.logger.filter") + ) raven.conf.setup_logging(handler) - wsgi_server.application = Sentry( - wsgi_server.application, client=client) + wsgi_server.application = Sentry(wsgi_server.application, client=client) - client.captureMessage('Starting Odoo Server') + client.captureMessage("Starting Odoo Server") return client diff --git a/sentry/__manifest__.py b/sentry/__manifest__.py index d4471b69e..65048bc8b 100644 --- a/sentry/__manifest__.py +++ b/sentry/__manifest__.py @@ -1,24 +1,18 @@ # Copyright 2016-2017 Versada # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { - 'name': 'Sentry', - 'summary': 'Report Odoo errors to Sentry', - 'version': '12.0.1.0.0', - 'category': 'Extra Tools', - 'website': 'https://odoo-community.org/', - 'author': 'Mohammed Barsi,' - 'Versada,' - 'Nicolas JEUDY,' - 'Odoo Community Association (OCA)', - 'license': 'AGPL-3', - 'application': False, - 'installable': True, - 'external_dependencies': { - 'python': [ - 'raven', - ] - }, - 'depends': [ - 'base', - ], + "name": "Sentry", + "summary": "Report Odoo errors to Sentry", + "version": "12.0.1.0.0", + "category": "Extra Tools", + "website": "https://odoo-community.org/", + "author": "Mohammed Barsi," + "Versada," + "Nicolas JEUDY," + "Odoo Community Association (OCA)", + "license": "AGPL-3", + "application": False, + "installable": True, + "external_dependencies": {"python": ["raven"]}, + "depends": ["base"], } diff --git a/sentry/const.py b/sentry/const.py index 0092d7544..8ea20aebb 100644 --- a/sentry/const.py +++ b/sentry/const.py @@ -14,76 +14,72 @@ except ImportError: _logger.debug('Cannot import "raven". Please make sure it is installed.') -def split_multiple(string, delimiter=',', strip_chars=None): - '''Splits :param:`string` and strips :param:`strip_chars` from values.''' +def split_multiple(string, delimiter=",", strip_chars=None): + """Splits :param:`string` and strips :param:`strip_chars` from values.""" if not string: return [] return [v.strip(strip_chars) for v in string.split(delimiter)] -SentryOption = collections.namedtuple( - 'SentryOption', ['key', 'default', 'converter']) +SentryOption = collections.namedtuple("SentryOption", ["key", "default", "converter"]) # Mapping of Odoo logging level -> Python stdlib logging library log level. -LOG_LEVEL_MAP = dict([ - (getattr(odoo.loglevels, 'LOG_%s' % x), getattr(logging, x)) - for x in ('CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG', 'NOTSET') -]) -DEFAULT_LOG_LEVEL = 'warn' +LOG_LEVEL_MAP = { + getattr(odoo.loglevels, "LOG_%s" % x): getattr(logging, x) + for x in ("CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "NOTSET") +} +DEFAULT_LOG_LEVEL = "warn" ODOO_USER_EXCEPTIONS = [ - 'odoo.exceptions.AccessDenied', - 'odoo.exceptions.AccessError', - 'odoo.exceptions.DeferredException', - 'odoo.exceptions.MissingError', - 'odoo.exceptions.RedirectWarning', - 'odoo.exceptions.UserError', - 'odoo.exceptions.ValidationError', - 'odoo.exceptions.Warning', - 'odoo.exceptions.except_orm', + "odoo.exceptions.AccessDenied", + "odoo.exceptions.AccessError", + "odoo.exceptions.DeferredException", + "odoo.exceptions.MissingError", + "odoo.exceptions.RedirectWarning", + "odoo.exceptions.UserError", + "odoo.exceptions.ValidationError", + "odoo.exceptions.Warning", + "odoo.exceptions.except_orm", ] -DEFAULT_IGNORED_EXCEPTIONS = ','.join(ODOO_USER_EXCEPTIONS) +DEFAULT_IGNORED_EXCEPTIONS = ",".join(ODOO_USER_EXCEPTIONS) PROCESSORS = ( - 'raven.processors.SanitizePasswordsProcessor', - 'odoo.addons.sentry.logutils.SanitizeOdooCookiesProcessor', + "raven.processors.SanitizePasswordsProcessor", + "odoo.addons.sentry.logutils.SanitizeOdooCookiesProcessor", ) -DEFAULT_PROCESSORS = ','.join(PROCESSORS) +DEFAULT_PROCESSORS = ",".join(PROCESSORS) -EXCLUDE_LOGGERS = ( - 'werkzeug', -) -DEFAULT_EXCLUDE_LOGGERS = ','.join(EXCLUDE_LOGGERS) +EXCLUDE_LOGGERS = ("werkzeug",) +DEFAULT_EXCLUDE_LOGGERS = ",".join(EXCLUDE_LOGGERS) -DEFAULT_TRANSPORT = 'threaded' +DEFAULT_TRANSPORT = "threaded" def select_transport(name=DEFAULT_TRANSPORT): return { - 'requests_synchronous': raven.transport.RequestsHTTPTransport, - 'requests_threaded': raven.transport.ThreadedRequestsHTTPTransport, - 'synchronous': raven.transport.HTTPTransport, - 'threaded': raven.transport.ThreadedHTTPTransport, + "requests_synchronous": raven.transport.RequestsHTTPTransport, + "requests_threaded": raven.transport.ThreadedRequestsHTTPTransport, + "synchronous": raven.transport.HTTPTransport, + "threaded": raven.transport.ThreadedHTTPTransport, }.get(name, DEFAULT_TRANSPORT) def get_sentry_options(): return [ - SentryOption('dsn', '', str.strip), - SentryOption('install_sys_hook', False, None), - SentryOption('transport', DEFAULT_TRANSPORT, select_transport), - SentryOption('include_paths', '', split_multiple), - SentryOption('exclude_paths', '', split_multiple), - SentryOption('machine', defaults.NAME, None), - SentryOption('auto_log_stacks', defaults.AUTO_LOG_STACKS, None), - SentryOption('capture_locals', defaults.CAPTURE_LOCALS, None), - SentryOption('string_max_length', defaults.MAX_LENGTH_STRING, None), - SentryOption('list_max_length', defaults.MAX_LENGTH_LIST, None), - SentryOption('site', None, None), - SentryOption('include_versions', True, None), - SentryOption( - 'ignore_exceptions', DEFAULT_IGNORED_EXCEPTIONS, split_multiple), - SentryOption('processors', DEFAULT_PROCESSORS, split_multiple), - SentryOption('environment', None, None), - SentryOption('release', None, None), + SentryOption("dsn", "", str.strip), + SentryOption("install_sys_hook", False, None), + SentryOption("transport", DEFAULT_TRANSPORT, select_transport), + SentryOption("include_paths", "", split_multiple), + SentryOption("exclude_paths", "", split_multiple), + SentryOption("machine", defaults.NAME, None), + SentryOption("auto_log_stacks", defaults.AUTO_LOG_STACKS, None), + SentryOption("capture_locals", defaults.CAPTURE_LOCALS, None), + SentryOption("string_max_length", defaults.MAX_LENGTH_STRING, None), + SentryOption("list_max_length", defaults.MAX_LENGTH_LIST, None), + SentryOption("site", None, None), + SentryOption("include_versions", True, None), + SentryOption("ignore_exceptions", DEFAULT_IGNORED_EXCEPTIONS, split_multiple), + SentryOption("processors", DEFAULT_PROCESSORS, split_multiple), + SentryOption("environment", None, None), + SentryOption("release", None, None), ] diff --git a/sentry/logutils.py b/sentry/logutils.py index cef132bd7..93709c9ce 100644 --- a/sentry/logutils.py +++ b/sentry/logutils.py @@ -18,56 +18,50 @@ except ImportError: def get_request_info(request): - ''' + """ Returns context data extracted from :param:`request`. Heavily based on flask integration for Sentry: https://git.io/vP4i9. - ''' + """ urlparts = urllib.parse.urlsplit(request.url) return { - 'url': '%s://%s%s' % (urlparts.scheme, urlparts.netloc, urlparts.path), - 'query_string': urlparts.query, - 'method': request.method, - 'headers': dict(get_headers(request.environ)), - 'env': dict(get_environ(request.environ)), + "url": "{}://{}{}".format(urlparts.scheme, urlparts.netloc, urlparts.path), + "query_string": urlparts.query, + "method": request.method, + "headers": dict(get_headers(request.environ)), + "env": dict(get_environ(request.environ)), } def get_extra_context(): - ''' + """ Extracts additional context from the current request (if such is set). - ''' + """ request = odoo.http.request try: - session = getattr(request, 'session', {}) + session = getattr(request, "session", {}) except RuntimeError: ctx = {} else: ctx = { - 'tags': { - 'database': session.get('db', None), - }, - 'user': { - 'login': session.get('login', None), - 'uid': session.get('uid', None), - }, - 'extra': { - 'context': session.get('context', {}), + "tags": {"database": session.get("db", None)}, + "user": { + "login": session.get("login", None), + "uid": session.get("uid", None), }, + "extra": {"context": session.get("context", {})}, } if request.httprequest: - ctx.update({ - 'request': get_request_info(request.httprequest), - }) + ctx.update({"request": get_request_info(request.httprequest)}) return ctx class LoggerNameFilter(logging.Filter): - ''' + """ Custom :class:`logging.Filter` which allows to filter loggers by name. - ''' + """ - def __init__(self, loggers, name=''): + def __init__(self, loggers, name=""): super(LoggerNameFilter, self).__init__(name=name) self._exclude_loggers = set(loggers) @@ -76,12 +70,12 @@ class LoggerNameFilter(logging.Filter): class OdooSentryHandler(SentryHandler): - ''' + """ Customized :class:`raven.handlers.logging.SentryHandler`. Allows to add additional Odoo and HTTP request data to the event which is sent to Sentry. - ''' + """ def __init__(self, include_extra_context, *args, **kwargs): super(OdooSentryHandler, self).__init__(*args, **kwargs) @@ -94,12 +88,10 @@ class OdooSentryHandler(SentryHandler): class SanitizeOdooCookiesProcessor(SanitizePasswordsProcessor): - ''' + """ Custom :class:`raven.processors.Processor`. Allows to sanitize sensitive Odoo cookies, namely the "session_id" cookie. - ''' + """ - KEYS = FIELDS = frozenset([ - 'session_id', - ]) + KEYS = FIELDS = frozenset(["session_id"]) diff --git a/sentry/tests/__init__.py b/sentry/tests/__init__.py index 6955e47d5..21926387a 100644 --- a/sentry/tests/__init__.py +++ b/sentry/tests/__init__.py @@ -1,7 +1,4 @@ # Copyright 2016-2017 Versada # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from . import ( - test_client, - test_logutils, -) +from . import test_client, test_logutils diff --git a/sentry/tests/test_client.py b/sentry/tests/test_client.py index aafe9d0e7..eb68c7137 100644 --- a/sentry/tests/test_client.py +++ b/sentry/tests/test_client.py @@ -20,25 +20,25 @@ def log_handler_by_class(logger, handler_cls): def remove_logging_handler(logger_name, handler_cls): - '''Removes handlers of specified classes from a :class:`logging.Logger` + """Removes handlers of specified classes from a :class:`logging.Logger` with a given name. :param string logger_name: name of the logger :param handler_cls: class of the handler to remove. You can pass a tuple of classes to catch several classes - ''' + """ logger = logging.getLogger(logger_name) for handler in log_handler_by_class(logger, handler_cls): logger.removeHandler(handler) class InMemoryClient(raven.Client): - '''A :class:`raven.Client` subclass which simply stores events in a list. + """A :class:`raven.Client` subclass which simply stores events in a list. Extended based on the one found in raven-python to avoid additional testing dependencies: https://git.io/vyGO3 - ''' + """ def __init__(self, **kwargs): self.events = [] @@ -52,14 +52,12 @@ class InMemoryClient(raven.Client): def has_event(self, event_level, event_msg): for event in self.events: - if (event.get('level') == event_level and - event.get('message') == event_msg): + if event.get("level") == event_level and event.get("message") == event_msg: return True return False class TestClientSetup(unittest.TestCase): - def setUp(self): super(TestClientSetup, self).setUp() self.logger = logging.getLogger(__name__) @@ -68,57 +66,54 @@ class TestClientSetup(unittest.TestCase): # when the module is loaded. After that, subsequent calls to # setup_logging will not re-add our handler. We explicitly remove # OdooSentryHandler handler so we can test with our in-memory client. - remove_logging_handler('', OdooSentryHandler) + remove_logging_handler("", OdooSentryHandler) def assertEventCaptured(self, client, event_level, event_msg): self.assertTrue( client.has_event(event_level, event_msg), - msg='Event: "%s" was not captured' % event_msg + msg='Event: "%s" was not captured' % event_msg, ) def assertEventNotCaptured(self, client, event_level, event_msg): self.assertFalse( client.has_event(event_level, event_msg), - msg='Event: "%s" was captured' % event_msg + msg='Event: "%s" was captured' % event_msg, ) def test_initialize_raven_sets_dsn(self): config = { - 'sentry_enabled': True, - 'sentry_dsn': 'http://public:secret@example.com/1', + "sentry_enabled": True, + "sentry_dsn": "http://public:secret@example.com/1", } client = initialize_raven(config, client_cls=InMemoryClient) - self.assertEqual(client.remote.base_url, 'http://example.com') + self.assertEqual(client.remote.base_url, "http://example.com") def test_capture_event(self): config = { - 'sentry_enabled': True, - 'sentry_dsn': 'http://public:secret@example.com/1', + "sentry_enabled": True, + "sentry_dsn": "http://public:secret@example.com/1", } - level, msg = logging.WARNING, 'Test event, can be ignored' + level, msg = logging.WARNING, "Test event, can be ignored" client = initialize_raven(config, client_cls=InMemoryClient) self.logger.log(level, msg) self.assertEventCaptured(client, level, msg) def test_ignore_exceptions(self): config = { - 'sentry_enabled': True, - 'sentry_dsn': 'http://public:secret@example.com/1', - 'sentry_ignore_exceptions': 'odoo.exceptions.UserError', + "sentry_enabled": True, + "sentry_dsn": "http://public:secret@example.com/1", + "sentry_ignore_exceptions": "odoo.exceptions.UserError", } - level, msg = logging.WARNING, 'Test UserError' + level, msg = logging.WARNING, "Test UserError" client = initialize_raven(config, client_cls=InMemoryClient) - handlers = list( - log_handler_by_class(logging.getLogger(), OdooSentryHandler) - ) + handlers = list(log_handler_by_class(logging.getLogger(), OdooSentryHandler)) self.assertTrue(handlers) handler = handlers[0] try: raise exceptions.UserError(msg) except exceptions.UserError: exc_info = sys.exc_info() - record = logging.LogRecord( - __name__, level, __file__, 42, msg, (), exc_info) + record = logging.LogRecord(__name__, level, __file__, 42, msg, (), exc_info) handler.emit(record) self.assertEventNotCaptured(client, level, msg) diff --git a/sentry/tests/test_logutils.py b/sentry/tests/test_logutils.py index bcabdcb6a..1dd20e2de 100644 --- a/sentry/tests/test_logutils.py +++ b/sentry/tests/test_logutils.py @@ -9,69 +9,62 @@ from ..logutils import SanitizeOdooCookiesProcessor class TestOdooCookieSanitizer(unittest.TestCase): - def test_cookie_as_string(self): data = { - 'request': { - 'cookies': 'website_lang=en_us;' - 'session_id=hello;' - 'Session_ID=hello;' - 'foo=bar', - }, + "request": { + "cookies": "website_lang=en_us;" + "session_id=hello;" + "Session_ID=hello;" + "foo=bar" + } } proc = SanitizeOdooCookiesProcessor(mock.Mock()) result = proc.process(data) - self.assertTrue('request' in result) - http = result['request'] + self.assertTrue("request" in result) + http = result["request"] self.assertEqual( - http['cookies'], - 'website_lang=en_us;' - 'session_id={m};' - 'Session_ID={m};' - 'foo=bar'.format( - m=proc.MASK, - ), + http["cookies"], + "website_lang=en_us;" + "session_id={m};" + "Session_ID={m};" + "foo=bar".format(m=proc.MASK), ) def test_cookie_as_string_with_partials(self): - data = { - 'request': { - 'cookies': 'website_lang=en_us;session_id;foo=bar', - }, - } + data = {"request": {"cookies": "website_lang=en_us;session_id;foo=bar"}} proc = SanitizeOdooCookiesProcessor(mock.Mock()) result = proc.process(data) - self.assertTrue('request' in result) - http = result['request'] + self.assertTrue("request" in result) + http = result["request"] self.assertEqual( - http['cookies'], - 'website_lang=en_us;session_id;foo=bar'.format(m=proc.MASK), + http["cookies"], "website_lang=en_us;session_id;foo=bar".format(m=proc.MASK) ) def test_cookie_header(self): data = { - 'request': { - 'headers': { - 'Cookie': 'foo=bar;' - 'session_id=hello;' - 'Session_ID=hello;' - 'a_session_id_here=hello', - }, - }, + "request": { + "headers": { + "Cookie": "foo=bar;" + "session_id=hello;" + "Session_ID=hello;" + "a_session_id_here=hello" + } + } } proc = SanitizeOdooCookiesProcessor(mock.Mock()) result = proc.process(data) - self.assertTrue('request' in result) - http = result['request'] + self.assertTrue("request" in result) + http = result["request"] self.assertEqual( - http['headers']['Cookie'], - 'foo=bar;' - 'session_id={m};' - 'Session_ID={m};' - 'a_session_id_here={m}'.format(m=proc.MASK)) + http["headers"]["Cookie"], + "foo=bar;" + "session_id={m};" + "Session_ID={m};" + "a_session_id_here={m}".format(m=proc.MASK), + )