Skip to content
This repository has been archived by the owner on Feb 8, 2018. It is now read-only.

Commit

Permalink
Refactor sentry wiring to avoid function passing
Browse files Browse the repository at this point in the history
  • Loading branch information
chadwhitacre committed Dec 2, 2016
1 parent 0224591 commit cb1a53f
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 42 deletions.
22 changes: 22 additions & 0 deletions gratipay/sync_npm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import sys
from threading import Lock

from gratipay import wireup


log_lock = Lock()

Expand All @@ -19,3 +21,23 @@ def log(*a, **kw):
"""
with log_lock:
print(*a, file=sys.stderr, **kw)


class sentry(object):
"""This is a context manager to log to sentry. You have to pass in an ``Environment``
object with a ``sentry_dsn`` attribute.
"""

def __init__(self, env, noop=None):
try:
sys.stdout = sys.stderr # work around aspen.log_dammit limitation; sigh
self.tell_sentry = wireup.make_sentry_teller(env, noop)
finally:
sys.stdout = sys.__stdout__

def __enter__(self):
return self

def __exit__(self, exc_type, exc_value, traceback):
self.tell_sentry(exc_type, {})
return False
17 changes: 1 addition & 16 deletions gratipay/sync_npm/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,4 @@ def main(argv=sys.argv):
args = parse_args(argv[1:])
db = wireup.db(env)

try:
sys.stdout = sys.stderr # work around aspen.log_dammit limitation; sigh
tell_sentry = wireup.make_sentry_teller(env)
finally:
sys.stdout = sys.__stdout__

def sentrified(func):
def _(*a, **kw):
try:
func(*a, **kw)
except:
e = sys.exc_info()[0]
tell_sentry(e, {})
return _

subcommands[args.command](env, args, db, sentrified)
subcommands[args.command](env, args, db)
7 changes: 4 additions & 3 deletions gratipay/sync_npm/serialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import sys
import time

from . import log
from . import log, sentry


def import_ijson(env):
Expand Down Expand Up @@ -97,10 +97,11 @@ def log_stats():
log_stats()


def main(env, args, db, sentrified):
def main(env, args, db):
"""Consume raw JSON from the npm registry via ``args.path``, and spit out
CSV for Postgres to stdout. Uses ``ijson``, requiring the ``yajl_cffi``
backend if ``env.require_yajl`` is ``True``.
"""
sentrified(serialize)(env, args, db)
with sentry(env):
serialize(env, args, db)
7 changes: 5 additions & 2 deletions gratipay/sync_npm/upsert.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

import uuid

from . import sentry


# Coordinate with Postgres on how to say "NULL".
# ==============================================
Expand Down Expand Up @@ -45,10 +47,11 @@ def upsert(env, args, db):
""")


def main(env, args, db, sentrified):
def main(env, args, db):
"""Take a CSV file from stdin and load it into Postgres using an `ingenious algorithm`_.
.. _ingenious algorithm: http://tapoueh.org/blog/2013/03/15-batch-update.html
"""
sentrified(upsert)(env, args, db)
with sentry(env):
upsert(env, args, db)
5 changes: 2 additions & 3 deletions gratipay/wireup.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,10 @@ def username_restrictions(website):
gratipay.RESTRICTED_USERNAMES = os.listdir(website.www_root)


def make_sentry_teller(env):
def make_sentry_teller(env, _noop=None):
if not env.sentry_dsn:
aspen.log_dammit("Won't log to Sentry (SENTRY_DSN is empty).")
def noop(*a, **kw):
pass
noop = _noop or (lambda *a, **kw: None)
Participant._tell_sentry = noop
return noop

Expand Down
34 changes: 16 additions & 18 deletions tests/py/test_sync_npm.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import pytest

from gratipay import sync_npm
from gratipay.testing import Harness


Expand All @@ -17,21 +18,17 @@ def load(raw):
).communicate(serialized)[0]


class Sentrifier:
class FailCollector:

def __init__(self):
self.ncalls = 0
self.fails = []

def __call__(self, func):
def _(*a, **kw):
try:
func(*a, **kw)
except:
self.ncalls += 1
return _
def __call__(self, fail, whatever):
self.fails.append(fail)

def fail(self, *a, **kw):
raise RuntimeError

class Heck(Exception):
pass


class Tests(Harness):
Expand Down Expand Up @@ -100,11 +97,12 @@ def test_sn_handles_empty_description_and_emails(self):
assert package.emails == []


# sentrifier

def test_sentrifier_starts_at_zero(self):
sentrified = Sentrifier()
assert sentrified.ncalls == 0
# with sentry(env)

def test_sentrifier_fail_fails(self):
pytest.raises(RuntimeError, Sentrifier().fail)
def test_with_sentry_logs_to_sentry_and_raises(self):
class env: sentry_dsn = ''
noop = FailCollector()
with pytest.raises(Heck):
with sync_npm.sentry(env, noop):
raise Heck
assert noop.fails == [Heck]

0 comments on commit cb1a53f

Please sign in to comment.