Skip to content

Commit

Permalink
Merge pull request #7 from freezingsaddles/black-2024-1
Browse files Browse the repository at this point in the history
Format with black
  • Loading branch information
obscurerichard authored Jan 14, 2024
2 parents 2dcc265 + 9ba4fa2 commit 217bd04
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 70 deletions.
3 changes: 1 addition & 2 deletions freezing/nq/api/health.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@


class HealthResource:

def on_get(self, req: falcon.Request, resp: falcon.Response):
"""
Just an arbitrary response for now.
"""
resp.media = {'status': 'Server is happy.'}
resp.media = {"status": "Server is happy."}
20 changes: 13 additions & 7 deletions freezing/nq/api/webhook.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@
from freezing.nq.config import config
from freezing.nq.publish import ActivityPublisher

from freezing.model.msg.strava import SubscriptionUpdate, SubscriptionUpdateSchema, SubscriptionCallbackSchema, \
SubscriptionCallback, ObjectType
from freezing.model.msg.strava import (
SubscriptionUpdate,
SubscriptionUpdateSchema,
SubscriptionCallbackSchema,
SubscriptionCallback,
ObjectType,
)
from freezing.model.msg.mq import DefinedTubes, ActivityUpdate, ActivityUpdateSchema


class WebhookResource:

def __init__(self, publisher: ActivityPublisher):
self.publisher = publisher

Expand All @@ -22,14 +26,17 @@ def on_get(self, req: falcon.Request, resp: falcon.Response):
See: http://strava.github.io/api/partner/v3/events/
"""

strava_request = {k: req.get_param(k) for k in ('hub.challenge', 'hub.mode', 'hub.verify_token')}
strava_request = {
k: req.get_param(k)
for k in ("hub.challenge", "hub.mode", "hub.verify_token")
}

schema = SubscriptionCallbackSchema()
callback: SubscriptionCallback = schema.load(strava_request).data
assert config.STRAVA_VERIFY_TOKEN == callback.hub_verify_token

resp.status = falcon.HTTP_200
resp.body = json.dumps({'hub.challenge': callback.hub_challenge})
resp.body = json.dumps({"hub.challenge": callback.hub_challenge})

def on_post(self, req: falcon.Request, resp: falcon.Response):
"""
Expand Down Expand Up @@ -66,5 +73,4 @@ def on_post(self, req: falcon.Request, resp: falcon.Response):
json_data = ActivityUpdateSchema().dump(message)

log.info("Publishing activity-update: {}".format(message))
self.publisher.publish_message(json_data,
dest=DefinedTubes.activity_update)
self.publisher.publish_message(json_data, dest=DefinedTubes.activity_update)
33 changes: 18 additions & 15 deletions freezing/nq/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,36 @@


class RequireJSON:

def process_request(self, req, resp):
if not req.client_accepts_json:
raise falcon.HTTPNotAcceptable(
'This API only supports responses encoded as JSON.',
href='http://docs.examples.com/api/json')
"This API only supports responses encoded as JSON.",
href="http://docs.examples.com/api/json",
)

if req.method in ('POST', 'PUT'):
if 'application/json' not in req.content_type:
if req.method in ("POST", "PUT"):
if "application/json" not in req.content_type:
raise falcon.HTTPUnsupportedMediaType(
'This API only supports requests encoded as JSON.',
href='http://docs.examples.com/api/json')
"This API only supports requests encoded as JSON.",
href="http://docs.examples.com/api/json",
)


def make_app(publisher:ActivityPublisher = None) -> falcon.API:
def make_app(publisher: ActivityPublisher = None) -> falcon.API:
"""
Builds the WSGI application we'll be serving.
"""
if publisher is None:
publisher = configured_publisher()

app = falcon.API(middleware=[
RequireJSON(),
])
app = falcon.API(
middleware=[
RequireJSON(),
]
)

app.add_route('/health', HealthResource())
app.add_route('/webhook', WebhookResource(publisher=publisher))
app.add_route("/health", HealthResource())
app.add_route("/webhook", WebhookResource(publisher=publisher))

return app

Expand All @@ -43,6 +46,6 @@ def make_app(publisher:ActivityPublisher = None) -> falcon.API:
# can also use Gunicorn to host your app. Gunicorn can be configured to
# auto-restart workers when it detects a code change, and it also works
# with pdb.
if __name__ == '__main__':
httpd = simple_server.make_server('127.0.0.1', 8000, make_app())
if __name__ == "__main__":
httpd = simple_server.make_server("127.0.0.1", 8000, make_app())
httpd.serve_forever()
30 changes: 19 additions & 11 deletions freezing/nq/autolog.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def _eagerFormat(self, msg, level, args):
# Otherwise, just drop the message completely to avoid anything going
# wrong in the future. This text shoudl clue one in to what's going
# on in the bizarre edge case where this ever does show up.
return '(log message suppressed due to insufficient log level)'
return "(log message suppressed due to insufficient log level)"

def _getUnterpolatedMessage(self, msg, args):
"""
Expand All @@ -64,7 +64,10 @@ def _getUnterpolatedMessage(self, msg, args):
# by casting the left side (the "msg" variable) in this context
# to unicode. So we'll do that here

if sys.version_info >= (3, 0,):
if sys.version_info >= (
3,
0,
):
# this is most likely unnecessary on python 3, but it's here
# for completeness, in the case of someone manually creating
# a bytestring
Expand All @@ -81,15 +84,15 @@ def _getUnterpolatedMessage(self, msg, args):
# From PEP-3101, value errors are of the type raised by the format
# method itself, so see if we should fall back to original
# formatting since there was an issue
if '%' in msg:
if "%" in msg:
msg = msg % args
else:
# we should NOT fall back, since there's no possible string
# interpolation happening and we want a meaningful error
# message
raise

if msg == original_msg and '%' in msg:
if msg == original_msg and "%" in msg:
# there must have been no string formatting methods
# used, given the presence of args without a change in the msg
# fall back to original formatting, including the special case
Expand Down Expand Up @@ -191,15 +194,20 @@ def __init__(self, adapter_class=None, adapter_args=None, adapter_kwargs=None):
self.adapter_kwargs = adapter_kwargs

def __getattr__(self, name):
if 'self' in inspect.currentframe().f_locals:
other = inspect.currentframe().f_locals['self']
caller_name = '%s.%s' % (other.__class__.__module__, other.__class__.__name__)
if "self" in inspect.currentframe().f_locals:
other = inspect.currentframe().f_locals["self"]
caller_name = "%s.%s" % (
other.__class__.__module__,
other.__class__.__name__,
)
else:
caller_name = inspect.currentframe(1).f_globals['__name__']
caller_name = inspect.currentframe(1).f_globals["__name__"]
logger = logging.getLogger(caller_name)

if self.adapter_class:
logger = self.adapter_class(logger, *self.adapter_args, **self.adapter_kwargs)
logger = self.adapter_class(
logger, *self.adapter_args, **self.adapter_kwargs
)

return getattr(logger, name)

Expand All @@ -208,7 +216,7 @@ def __getattr__(self, name):


def log_exceptions(fn):
""" A decorator designed to wrap a function and log any exception that method produces.
"""A decorator designed to wrap a function and log any exception that method produces.
The exception will still be raised after being logged.
Expand All @@ -224,7 +232,7 @@ def wrapper(*args, **kwargs):
a = [str(x)[:255] for x in a]
kw = kwargs or {}
kw = dict([(str(k)[:255], str(v)[:255]) for k, v in kw.items()])
log.debug('Calling %s.%s %r %r' % (fn.__module__, fn.__name__, a, kw))
log.debug("Calling %s.%s %r %r" % (fn.__module__, fn.__name__, a, kw))
return fn(*args, **kwargs)
except Exception as e:
log.error("Error calling function %s: %s" % (fn.__name__, e))
Expand Down
10 changes: 5 additions & 5 deletions freezing/nq/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@
import logging
from envparse import env

envfile = os.environ.get('APP_SETTINGS', os.path.join(os.getcwd(), '.env'))
envfile = os.environ.get("APP_SETTINGS", os.path.join(os.getcwd(), ".env"))

if os.path.exists(envfile):
env.read_envfile(envfile)


class Config:
DEBUG: bool = env('DEBUG', default=False)
STRAVA_VERIFY_TOKEN: str = env('STRAVA_VERIFY_TOKEN', default='STRAVA')
BEANSTALKD_HOST: str = env('BEANSTALKD_HOST', default='127.0.0.1')
BEANSTALKD_PORT: int = env('BEANSTALKD_PORT', cast=int, default=11300)
DEBUG: bool = env("DEBUG", default=False)
STRAVA_VERIFY_TOKEN: str = env("STRAVA_VERIFY_TOKEN", default="STRAVA")
BEANSTALKD_HOST: str = env("BEANSTALKD_HOST", default="127.0.0.1")
BEANSTALKD_PORT: int = env("BEANSTALKD_PORT", cast=int, default=11300)


config = Config()
Expand Down
6 changes: 3 additions & 3 deletions freezing/nq/publish.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class ActivityPublisher:
(Currently uses beanstalkd, but that may change. May also switch to using threads & queues to speed up.)
"""

def __init__(self, host:str, port:int):
def __init__(self, host: str, port: int):
self.host = host
self.port = port

Expand All @@ -25,7 +25,7 @@ def serialize_message(self, message) -> str:
else:
return json.dumps(message)

def publish_message(self, message:Any, dest: DefinedTubes):
def publish_message(self, message: Any, dest: DefinedTubes):
"""
Publish the json-serializable message object (e.g. dict) to configured destination (e.g. queue, tube).
Expand All @@ -41,4 +41,4 @@ def publish_message(self, message:Any, dest: DefinedTubes):


def configured_publisher() -> ActivityPublisher:
return ActivityPublisher(host=config.BEANSTALKD_HOST, port=config.BEANSTALKD_PORT)
return ActivityPublisher(host=config.BEANSTALKD_HOST, port=config.BEANSTALKD_PORT)
57 changes: 30 additions & 27 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,54 +12,57 @@


def test_get_webhook(client):
d = {
"hub.challenge": "asdf",
"hub.mode": "mode",
"hub.verify_token": config.STRAVA_VERIFY_TOKEN,
}

d = {'hub.challenge': 'asdf', 'hub.mode': 'mode', 'hub.verify_token': config.STRAVA_VERIFY_TOKEN}

result = client.simulate_get('/webhook', params=d)
result = client.simulate_get("/webhook", params=d)
print(result)
assert result.json == {'hub.challenge': 'asdf'}
assert result.json == {"hub.challenge": "asdf"}


def test_get_webhook_bad_token(client):

d = {'hub.challenge': 'asdf', 'hub.mode': 'mode', 'hub.verify_token': 'wrong'}
d = {"hub.challenge": "asdf", "hub.mode": "mode", "hub.verify_token": "wrong"}

with pytest.raises(AssertionError):
result = client.simulate_get('/webhook', params=d)

result = client.simulate_get("/webhook", params=d)

def test_post_webhook(client, publisher:ActivityPublisher):

def test_post_webhook(client, publisher: ActivityPublisher):
d = dict(
subscription_id=111,
owner_id=222,
object_type='activity',
object_type="activity",
object_id=999,
aspect_type='update',
updates={'title': 'Hello world.'},
aspect_type="update",
updates={"title": "Hello world."},
event_time=1358919359,
)

result = client.simulate_post('/webhook', body=json.dumps(d), headers={'content-type': 'application/json'}

result = client.simulate_post(
"/webhook", body=json.dumps(d), headers={"content-type": "application/json"}
)

message = ActivityUpdate()
message.athlete_id = d['owner_id']
message.event_time = arrow.get(d['event_time']).datetime
message.activity_id = d['object_id']
message.operation = AspectType(d['aspect_type'])
message.updates = d['updates']
message = ActivityUpdate()
message.athlete_id = d["owner_id"]
message.event_time = arrow.get(d["event_time"]).datetime
message.activity_id = d["object_id"]
message.operation = AspectType(d["aspect_type"])
message.updates = d["updates"]

called_with = dict(
activity_id=d['object_id'],
athlete_id=d['owner_id'],
operation=d['aspect_type'],
event_time='2013-01-23T05:35:59+00:00',
updates=d['updates']
activity_id=d["object_id"],
athlete_id=d["owner_id"],
operation=d["aspect_type"],
event_time="2013-01-23T05:35:59+00:00",
updates=d["updates"],
)

publisher.publish_message.assert_called_with(called_with, dest=DefinedTubes.activity_update)
publisher.publish_message.assert_called_with(
called_with, dest=DefinedTubes.activity_update
)


# def test_post_webhook_noop(client, publisher:ActivityPublisher):
Expand All @@ -76,4 +79,4 @@ def test_post_webhook(client, publisher:ActivityPublisher):
#
# client.simulate_post('/webhook', body=json.dumps(d), headers={'content-type': 'application/json'})
#
# publisher.publish_message.assert_not_called()
# publisher.publish_message.assert_not_called()

0 comments on commit 217bd04

Please sign in to comment.