diff --git a/activitypub.py b/activitypub.py
index c56abc2..28a586a 100644
--- a/activitypub.py
+++ b/activitypub.py
@@ -28,7 +28,7 @@ from common import (
redirect_wrap,
TLD_BLOCKLIST,
)
-from models import Follower, Object, PROTOCOLS, Target, User
+from models import Follower, Object, PROTOCOLS, User
from protocol import Protocol
# TODO: remove this. we only need it to make sure Web is registered in PROTOCOLS
@@ -263,8 +263,8 @@ class ActivityPub(User, Protocol):
key_actor = cls.load(keyId)
except BadGateway:
obj_id = as1.get_object(activity).get('id')
- if (activity.get('type') == 'Delete' and obj_id and
- keyId == fragmentless(obj_id)):
+ if (activity.get('type') == 'Delete' and obj_id
+ and keyId == fragmentless(obj_id)):
logger.info('Object/actor being deleted is also keyId')
key_actor = Object(id=keyId, source_protocol='activitypub', deleted=True)
key_actor.put()
@@ -356,12 +356,13 @@ def signed_request(fn, url, data=None, log_data=True, headers=None, **kwargs):
# handle GET redirects manually so that we generate a new HTTP signature
if resp.is_redirect and fn == util.requests_get:
- return signed_request(fn, resp.headers['Location'], data=data,
- headers=headers, log_data=log_data, **kwargs)
+ return signed_request(fn, resp.headers['Location'], data=data,
+ headers=headers, log_data=log_data, **kwargs)
type = common.content_type(resp)
if (type and type != 'text/html' and
- (type.startswith('text/') or type.endswith('+json') or type.endswith('/json'))):
+ (type.startswith('text/') or type.endswith('+json')
+ or type.endswith('/json'))):
logger.info(resp.text)
return resp
@@ -546,7 +547,7 @@ def postprocess_as2_actor(actor, wrap=True):
url = g.user.web_url() if g.user else None
urls = util.get_list(actor, 'url')
if not urls and url:
- urls = [url]
+ urls = [url]
domain = util.domain_from_link(urls[0], minimize=False)
if wrap:
@@ -565,11 +566,11 @@ def postprocess_as2_actor(actor, wrap=True):
# Override the label for their home page to be "Web site"
for att in util.get_list(actor, 'attachment'):
- if att.get('type') == 'PropertyValue':
- val = att.get('value', '')
- link = util.parse_html(val).find('a')
- if url and (val == url or link.get('href') == url):
- att['name'] = 'Web site'
+ if att.get('type') == 'PropertyValue':
+ val = att.get('value', '')
+ link = util.parse_html(val).find('a')
+ if url and (val == url or link.get('href') == url):
+ att['name'] = 'Web site'
# required by pixelfed. https://github.com/snarfed/bridgy-fed/issues/39
actor.setdefault('summary', '')
@@ -591,7 +592,7 @@ def actor(protocol, domain):
if not g.user:
try:
obj = cls.load(f'https://{domain}/', gateway=True)
- except NoMicroformats as e:
+ except NoMicroformats:
obj = None
g.user = cls.get_or_create(id=domain, obj=obj)
diff --git a/appengine_config.py b/appengine_config.py
index 5b96eae..d6cb616 100644
--- a/appengine_config.py
+++ b/appengine_config.py
@@ -1,16 +1,19 @@
"""Bridgy App Engine config.
"""
-# suppress these INFO logs:
-# Sandbox prevented access to file "/usr/local/Caskroom/google-cloud-sdk"
-# If it is a static file, check that `application_readable: true` is set in your app.yaml
import logging
+
class StubsFilter(logging.Filter):
- def filter(self, record):
- msg = record.getMessage()
- if (msg.startswith('Sandbox prevented access to file') or
- msg.startswith('If it is a static file, check that')):
- return 0
- return 1
+ """Suppress these INFO logs:
+ Sandbox prevented access to file "/usr/local/Caskroom/google-cloud-sdk"
+ If it is a static file, check that `application_readable: true` is set in your app.yaml
+ """
+ def filter(self, record):
+ msg = record.getMessage()
+ if (msg.startswith('Sandbox prevented access to file')
+ or msg.startswith('If it is a static file, check that')):
+ return 0
+ return 1
+
logging.getLogger().addFilter(StubsFilter())
diff --git a/common.py b/common.py
index b9f69fa..f67fb5f 100644
--- a/common.py
+++ b/common.py
@@ -2,7 +2,6 @@
"""Misc common utilities.
"""
import base64
-import copy
from datetime import timedelta
import logging
import re
@@ -12,11 +11,8 @@ import urllib.parse
import cachetools
from Crypto.Util import number
from flask import abort, g, make_response, request
-from granary import as1, as2, microformats2
-import mf2util
from oauth_dropins.webutil import util, webmention
from oauth_dropins.webutil.appengine_info import DEBUG
-from oauth_dropins.webutil.util import json_dumps, json_loads
from werkzeug.exceptions import BadRequest
logger = logging.getLogger(__name__)
@@ -90,10 +86,10 @@ def long_to_base64(x):
def host_url(path_query=None):
base = request.host_url
- if (util.domain_or_parent_in(request.host, OTHER_DOMAINS) or
- # when running locally against prod datastore
- (not DEBUG and request.host in LOCAL_DOMAINS)):
- base = f'https://{PRIMARY_DOMAIN}'
+ if (util.domain_or_parent_in(request.host, OTHER_DOMAINS)
+ # when running locally against prod datastore
+ or (not DEBUG and request.host in LOCAL_DOMAINS)):
+ base = f'https://{PRIMARY_DOMAIN}'
return urllib.parse.urljoin(base, path_query)
@@ -105,26 +101,26 @@ def error(msg, status=400, exc_info=None, **kwargs):
def pretty_link(url, text=None, **kwargs):
- """Wrapper around util.pretty_link() that converts Mastodon user URLs to @-@.
+ """Wrapper around util.pretty_link() that converts Mastodon user URLs to @-@.
- Eg for URLs like https://mastodon.social/@foo and
- https://mastodon.social/users/foo, defaults text to @foo@mastodon.social if
- it's not provided.
+ Eg for URLs like https://mastodon.social/@foo and
+ https://mastodon.social/users/foo, defaults text to @foo@mastodon.social if
+ it's not provided.
- Args:
- url: str
- text: str
- kwargs: passed through to :func:`webutil.util.pretty_link`
- """
- if g.user and g.user.is_web_url(url):
- return g.user.user_page_link()
+ Args:
+ url: str
+ text: str
+ kwargs: passed through to :func:`webutil.util.pretty_link`
+ """
+ if g.user and g.user.is_web_url(url):
+ return g.user.user_page_link()
- if text is None:
- match = re.match(r'https?://([^/]+)/(@|users/)([^/]+)$', url)
- if match:
- text = match.expand(r'@\3@\1')
+ if text is None:
+ match = re.match(r'https?://([^/]+)/(@|users/)([^/]+)$', url)
+ if match:
+ text = match.expand(r'@\3@\1')
- return util.pretty_link(url, text=text, **kwargs)
+ return util.pretty_link(url, text=text, **kwargs)
def content_type(resp):
@@ -199,25 +195,25 @@ def redirect_unwrap(val):
def webmention_endpoint_cache_key(url):
- """Returns cache key for a cached webmention endpoint for a given URL.
+ """Returns cache key for a cached webmention endpoint for a given URL.
- Just the domain by default. If the URL is the home page, ie path is / , the
- key includes a / at the end, so that we cache webmention endpoints for home
- pages separate from other pages. https://github.com/snarfed/bridgy/issues/701
+ Just the domain by default. If the URL is the home page, ie path is / , the
+ key includes a / at the end, so that we cache webmention endpoints for home
+ pages separate from other pages. https://github.com/snarfed/bridgy/issues/701
- Example: 'snarfed.org /'
+ Example: 'snarfed.org /'
- https://github.com/snarfed/bridgy-fed/issues/423
+ https://github.com/snarfed/bridgy-fed/issues/423
- Adapted from bridgy/util.py.
- """
- parsed = urllib.parse.urlparse(url)
- key = parsed.netloc
- if parsed.path in ('', '/'):
- key += ' /'
+ Adapted from bridgy/util.py.
+ """
+ parsed = urllib.parse.urlparse(url)
+ key = parsed.netloc
+ if parsed.path in ('', '/'):
+ key += ' /'
- # logger.debug(f'wm cache key {key}')
- return key
+ # logger.debug(f'wm cache key {key}')
+ return key
@cachetools.cached(cachetools.TTLCache(50000, 60 * 60 * 2), # 2h expiration
diff --git a/config.py b/config.py
index 0ef321e..617ec29 100644
--- a/config.py
+++ b/config.py
@@ -14,10 +14,10 @@ SESSION_COOKIE_SAMESITE = 'Lax'
CACHE_THRESHOLD = 3000
if appengine_info.DEBUG:
- ENV = 'development'
- CACHE_TYPE = 'NullCache'
- SECRET_KEY = 'sooper seekret'
+ ENV = 'development'
+ CACHE_TYPE = 'NullCache'
+ SECRET_KEY = 'sooper seekret'
else:
- ENV = 'production'
- CACHE_TYPE = 'SimpleCache'
- SECRET_KEY = util.read('flask_secret_key')
+ ENV = 'production'
+ CACHE_TYPE = 'SimpleCache'
+ SECRET_KEY = util.read('flask_secret_key')
diff --git a/convert.py b/convert.py
index 6377a6a..16d2557 100644
--- a/convert.py
+++ b/convert.py
@@ -5,7 +5,6 @@ constants from the :class:`Protocol` subclasses.
"""
import logging
import re
-import urllib.parse
from flask import g, redirect, request
from granary import as1
@@ -78,8 +77,8 @@ def convert(dest, _):
if obj_id:
# TODO: PROTOCOLS[src].load() this instead?
obj_obj = Object.get_by_id(obj_id)
- if (obj_obj and obj_obj.as1 and
- not obj_obj.as1.keys() <= set(['id', 'url', 'objectType'])):
+ if (obj_obj and obj_obj.as1
+ and not obj_obj.as1.keys() <= set(['id', 'url', 'objectType'])):
logger.info(f'{type} activity, redirecting to Object {obj_id}')
return redirect(f'/{path_prefix}{obj_id}', code=301)
diff --git a/flask_app.py b/flask_app.py
index 5baadce..5dd6e6f 100644
--- a/flask_app.py
+++ b/flask_app.py
@@ -15,8 +15,6 @@ from oauth_dropins.webutil import (
util,
)
-import common
-
logger = logging.getLogger(__name__)
logging.getLogger('lexrpc').setLevel(logging.INFO)
logging.getLogger('negotiator').setLevel(logging.WARNING)
@@ -34,6 +32,7 @@ app.register_error_handler(Exception, flask_util.handle_exception)
if appengine_info.LOCAL:
flask_gae_static.init_app(app)
+
@app.before_request
def init_globals():
"""Set request globals.
@@ -42,6 +41,7 @@ def init_globals():
"""
g.user = None
+
# don't redirect API requests with blank path elements
app.url_map.merge_slashes = False
app.url_map.redirect_defaults = False
diff --git a/follow.py b/follow.py
index 9e7ff5b..319473a 100644
--- a/follow.py
+++ b/follow.py
@@ -5,16 +5,13 @@ https://socialhub.activitypub.rocks/t/what-is-the-current-spec-for-remote-follow
https://www.rfc-editor.org/rfc/rfc7033
"""
import logging
-import urllib.parse
from flask import g, redirect, request, session
from granary import as2
from oauth_dropins import indieauth
-from oauth_dropins.webutil import flask_util, util
-from oauth_dropins.webutil.flask_util import error, flash
from oauth_dropins.webutil import util
+from oauth_dropins.webutil.flask_util import error, flash
from oauth_dropins.webutil.testutil import NOW
-from oauth_dropins.webutil.util import json_dumps, json_loads
from activitypub import ActivityPub
from flask_app import app
diff --git a/models.py b/models.py
index 2690528..961b7f2 100644
--- a/models.py
+++ b/models.py
@@ -7,7 +7,6 @@ import random
import urllib.parse
from arroba.mst import dag_cbor_cid
-from Crypto import Random
from Crypto.PublicKey import ECC, RSA
import dag_json
from flask import g, request
@@ -18,10 +17,9 @@ from oauth_dropins.webutil.appengine_info import DEBUG
from oauth_dropins.webutil.flask_util import error
from oauth_dropins.webutil.models import ComputedJsonProperty, JsonProperty, StringIdModel
from oauth_dropins.webutil.util import json_dumps, json_loads
-import requests
import common
-from common import base64_to_long, long_to_base64, redirect_unwrap, redirect_wrap
+from common import base64_to_long, long_to_base64, redirect_unwrap
# maps string label to Protocol subclass. populated by ProtocolUserMeta.
# seed with old and upcoming protocols that don't have their own classes (yet).
@@ -475,8 +473,8 @@ class Object(StringIdModel):
"""Returns a pretty actor link with their name and profile picture."""
attrs = {'class': 'h-card u-author'}
- if (self.source_protocol in ('web', 'webmention', 'ui') and g.user and
- (g.user.key in self.users or g.user.key.id() in self.domains)):
+ if (self.source_protocol in ('web', 'webmention', 'ui') and g.user
+ and (g.user.key in self.users or g.user.key.id() in self.domains)):
# outbound; show a nice link to the user
return g.user.user_page_link()
@@ -498,6 +496,7 @@ class Object(StringIdModel):
{util.ellipsize(name, chars=40)}
"""
+
class AtpNode(StringIdModel):
"""An AT Protocol (Bluesky) node.
diff --git a/pages.py b/pages.py
index ad807ac..a8f9c1b 100644
--- a/pages.py
+++ b/pages.py
@@ -1,26 +1,20 @@
"""UI pages."""
-import calendar
import datetime
import logging
import os
-import re
-import urllib.parse
-from flask import g, redirect, render_template, request
-from google.cloud.ndb.model import get_multi
+from flask import g, render_template, request
from google.cloud.ndb.query import OR
from google.cloud.ndb.stats import KindStat
from granary import as1, as2, atom, microformats2, rss
import humanize
from oauth_dropins.webutil import flask_util, logs, util
-from oauth_dropins.webutil.flask_util import error, flash, redirect
-from oauth_dropins.webutil.util import json_dumps, json_loads
+from oauth_dropins.webutil.flask_util import error, redirect
import common
from common import DOMAIN_RE
from flask_app import app, cache
-from models import fetch_page, Follower, Object, PAGE_SIZE, PROTOCOLS, User
-from web import Web
+from models import fetch_page, Follower, Object, PAGE_SIZE, PROTOCOLS
FOLLOWERS_UI_LIMIT = 999
@@ -192,7 +186,6 @@ def fetch_objects(query):
to fetch the previous and next pages, respectively
"""
objects, new_before, new_after = fetch_page(query, Object)
- seen = set()
# synthesize human-friendly content for objects
for i, obj in enumerate(objects):
diff --git a/protocol.py b/protocol.py
index dacf5eb..c280d3b 100644
--- a/protocol.py
+++ b/protocol.py
@@ -3,18 +3,17 @@ import logging
import threading
from urllib.parse import urljoin
-from cachetools import cached, LRUCache
+from cachetools import LRUCache
from flask import g, request
from google.cloud import ndb
from google.cloud.ndb import OR
-from granary import as1, as2
-import requests
+from granary import as1
import werkzeug.exceptions
import common
from common import error
from models import Follower, Object, PROTOCOLS, Target
-from oauth_dropins.webutil import util, webmention
+from oauth_dropins.webutil import util
from oauth_dropins.webutil.util import json_dumps, json_loads
SUPPORTED_TYPES = (
@@ -433,8 +432,8 @@ class Protocol:
# deliver original posts and reposts to followers
is_reply = (obj.type == 'comment' or
(inner_obj and inner_obj.get('inReplyTo')))
- if (actor and actor_id and
- (obj.type == 'share' or obj.type in ('create', 'post') and not is_reply)):
+ if ((obj.type == 'share' or obj.type in ('create', 'post') and not is_reply)
+ and actor and actor_id):
logger.info(f'Delivering to followers of {actor_id}')
for f in Follower.query(Follower.to == from_cls(id=actor_id).key,
Follower.status == 'active'):
@@ -580,11 +579,11 @@ class Protocol:
if 'notification' not in obj.labels:
obj.labels.append('notification')
except BaseException as e:
- code, body = util.interpret_http_exception(e)
- if not code and not body:
- raise
- errors.append((code, body))
- obj.failed.append(target)
+ code, body = util.interpret_http_exception(e)
+ if not code and not body:
+ raise
+ errors.append((code, body))
+ obj.failed.append(target)
obj.put()
diff --git a/redirect.py b/redirect.py
index 99ba1b2..b81fe51 100644
--- a/redirect.py
+++ b/redirect.py
@@ -18,7 +18,7 @@ import logging
import re
import urllib.parse
-from flask import g, redirect, request
+from flask import g, request
from granary import as2
from negotiator import ContentNegotiator, AcceptParameters, ContentType
from oauth_dropins.webutil import flask_util, util
@@ -28,7 +28,6 @@ from oauth_dropins.webutil.util import json_dumps, json_loads
from activitypub import ActivityPub
from flask_app import app, cache
from common import CACHE_TIME, CONTENT_TYPE_HTML
-from models import Object, User
from web import Web
logger = logging.getLogger(__name__)
diff --git a/tests/test_activitypub.py b/tests/test_activitypub.py
index db57082..f19f52a 100644
--- a/tests/test_activitypub.py
+++ b/tests/test_activitypub.py
@@ -6,14 +6,12 @@ from datetime import datetime, timedelta
from hashlib import sha256
import logging
from unittest import skip
-from unittest.mock import ANY, call, patch
-import urllib.parse
+from unittest.mock import patch
from flask import g
from google.cloud import ndb
from granary import as2, microformats2
from httpsig import HeaderSigner
-from oauth_dropins.webutil import util
from oauth_dropins.webutil.testutil import requests_response
from oauth_dropins.webutil.util import json_dumps, json_loads
import requests
@@ -26,10 +24,8 @@ from .testutil import Fake, TestCase
import activitypub
from activitypub import ActivityPub, postprocess_as2
import common
-import models
from models import Follower, Object
import protocol
-from protocol import Protocol
from web import Web
# have to import module, not attrs, to avoid circular import
@@ -49,7 +45,7 @@ ACTOR_BASE = {
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1',
],
- 'type' : 'Person',
+ 'type': 'Person',
'id': 'http://localhost/user.com',
'url': 'http://localhost/r/https://user.com/',
'preferredUsername': 'user.com',
@@ -387,7 +383,7 @@ class ActivityPubTest(TestCase):
**REPLY,
'actor': LIKE_ACTOR,
}
- got = self._test_inbox_reply(reply, {
+ self._test_inbox_reply(reply, {
'as2': reply,
'type': 'post',
'labels': ['activity', 'notification'],
@@ -749,7 +745,6 @@ class ActivityPubTest(TestCase):
self.assert_user(ActivityPub, 'https://user.com/actor',
obj_as2=LIKE_ACTOR, direct=True)
-
def test_inbox_follow_accept_with_id(self, *mocks):
self._test_inbox_follow_accept(FOLLOW_WRAPPED, ACCEPT, *mocks)
@@ -768,10 +763,6 @@ class ActivityPubTest(TestCase):
object_ids=[FOLLOW['object']])
def test_inbox_follow_accept_with_object(self, *mocks):
- wrapped_user = {
- 'id': FOLLOW_WRAPPED['object'],
- 'url': FOLLOW_WRAPPED['object'],
- }
unwrapped_user = {
'id': FOLLOW['object'],
'url': FOLLOW['object'],
@@ -905,7 +896,6 @@ class ActivityPubTest(TestCase):
self.assertEqual('https://mas.to/users/swentel#followed-https://user.com/',
follower.follow.get().as2['url'])
-
def test_inbox_undo_follow(self, mock_head, mock_get, mock_post):
follower = Follower(to=self.user.key,
from_=ActivityPub.get_or_create(ACTOR['id']).key,
@@ -1065,7 +1055,6 @@ class ActivityPubTest(TestCase):
# invalid signature, header changed
protocol.seen_ids.clear()
obj_key.delete()
- orig_date = headers['Date']
resp = self.client.post('/ap/sharedInbox', data=body, headers={**headers, 'Date': 'X'})
self.assertEqual(401, resp.status_code)
@@ -1505,7 +1494,7 @@ class ActivityPubUtilsTest(TestCase):
}, postprocess_as2({
'tag': [
{'name': 'bar', 'href': 'bar'},
- {'type': 'Tag','name': '#baz'},
+ {'type': 'Tag', 'name': '#baz'},
# should leave alone
{'type': 'Mention', 'href': 'foo'},
],
@@ -1644,7 +1633,7 @@ class ActivityPubUtilsTest(TestCase):
allow_redirects=False),
requests_response(status=200, allow_redirects=False),
]
- resp = activitypub.signed_get('https://first')
+ activitypub.signed_get('https://first')
first = mock_get.call_args_list[0][1]
second = mock_get.call_args_list[1][1]
@@ -1697,7 +1686,7 @@ class ActivityPubUtilsTest(TestCase):
mock_get.assert_has_calls((
self.as2_req('http://orig'),
- self.as2_req('http://as2', headers=common.as2.CONNEG_HEADERS),
+ self.as2_req('http://as2', headers=as2.CONNEG_HEADERS),
))
@patch('requests.get')
@@ -1708,7 +1697,7 @@ class ActivityPubUtilsTest(TestCase):
@patch('requests.get')
def test_fetch_not_acceptable(self, mock_get):
- mock_get.return_value=NOT_ACCEPTABLE
+ mock_get.return_value = NOT_ACCEPTABLE
with self.assertRaises(BadGateway):
ActivityPub.fetch(Object(id='http://orig'))
diff --git a/tests/test_common.py b/tests/test_common.py
index cd4ba28..3692943 100644
--- a/tests/test_common.py
+++ b/tests/test_common.py
@@ -1,19 +1,11 @@
"""Unit tests for common.py."""
-from unittest import mock
-
from flask import g
-from granary import as2
-from oauth_dropins.webutil import appengine_config, util
-from oauth_dropins.webutil.testutil import requests_response
-import requests
# import first so that Fake is defined before URL routes are registered
from .testutil import Fake, TestCase
import common
from flask_app import app
-from models import Object, User
-import protocol
from web import Web
diff --git a/tests/test_convert.py b/tests/test_convert.py
index 461c769..c6dcff4 100644
--- a/tests/test_convert.py
+++ b/tests/test_convert.py
@@ -8,7 +8,6 @@ from granary.tests.test_as1 import ACTOR, COMMENT, DELETE_OF_ID, UPDATE
from models import Object
from oauth_dropins.webutil.testutil import requests_response
from oauth_dropins.webutil.util import parse_mf2
-import requests
# import first so that Fake is defined before URL routes are registered
from . import testutil
@@ -191,7 +190,7 @@ class ConvertTest(testutil.TestCase):
resp.headers['Location'])
def test_activitypub_to_web_update_no_inner_obj_serve_as_is(self):
- # UPDATE's object field is a full object
+ # Update's object field is a full object
Object(id='http://foo', our_as1=UPDATE).put()
resp = self.client.get('/convert/web/http://foo',
@@ -205,7 +204,7 @@ A ☕ reply
""", resp.get_data(as_text=True), ignore_blanks=True)
def test_activitypub_to_web_update_inner_obj_too_minimal_serve_as_is(self):
- # UPDATE's object field is a full object
+ # Update's object field is a full object
Object(id='http://foo', our_as1=UPDATE).put()
Object(id=UPDATE['object']['id'], as2={'id': 'foo'}).put()
@@ -259,4 +258,3 @@ A ☕ reply
resp = self.client.get(f'/convert/ap/http://nope.com/post',
base_url='https://ap.brid.gy/')
self.assertEqual(400, resp.status_code)
-
diff --git a/tests/test_follow.py b/tests/test_follow.py
index c3b32e3..4f6d8c2 100644
--- a/tests/test_follow.py
+++ b/tests/test_follow.py
@@ -14,10 +14,7 @@ from oauth_dropins.webutil.util import json_dumps, json_loads
from .testutil import Fake, TestCase
from activitypub import ActivityPub
-import common
-from common import redirect_unwrap
-from models import Follower, Object, User
-from web import Web
+from models import Follower, Object
WEBFINGER = requests_response({
'subject': 'acct:foo@bar',
@@ -191,7 +188,7 @@ class FollowTest(TestCase):
def check(self, input, resp, expected_follow, mock_get, mock_post):
self.assertEqual(302, resp.status_code)
- self.assertEqual('/web/alice.com/following',resp.headers['Location'])
+ self.assertEqual('/web/alice.com/following', resp.headers['Location'])
self.assertEqual([f'Followed {input}.'],
get_flashed_messages())
diff --git a/tests/test_models.py b/tests/test_models.py
index e2ea5aa..a5c2d7c 100644
--- a/tests/test_models.py
+++ b/tests/test_models.py
@@ -1,20 +1,15 @@
# coding=utf-8
"""Unit tests for models.py."""
-from unittest import mock
-
from arroba.mst import dag_cbor_cid
from Crypto.PublicKey import ECC
-from flask import g, get_flashed_messages
-from granary import as2
+from flask import g
from granary.tests.test_bluesky import ACTOR_PROFILE_BSKY
-from multiformats import CID
-from oauth_dropins.webutil.testutil import NOW, requests_response
+from oauth_dropins.webutil.testutil import NOW
# import first so that Fake is defined before URL routes are registered
from .testutil import Fake, TestCase
-import common
-from models import AtpNode, Follower, Object, OBJECT_EXPIRE_AGE, User
+from models import AtpNode, Follower, Object, OBJECT_EXPIRE_AGE
import protocol
from web import Web
@@ -158,9 +153,9 @@ class ObjectTest(TestCase):
title="Alice">
Alice""", {'actor': {
- 'name': 'Alice',
- 'icon': {'type': 'Image', 'url': 'http://pic'},
- }}),
+ 'name': 'Alice',
+ 'icon': {'type': 'Image', 'url': 'http://pic'},
+ }}),
):
obj = Object(id='x', as2=as2)
self.assert_multiline_in(expected, obj.actor_link())
diff --git a/tests/test_pages.py b/tests/test_pages.py
index f4255a1..9945957 100644
--- a/tests/test_pages.py
+++ b/tests/test_pages.py
@@ -1,32 +1,26 @@
"""Unit tests for pages.py."""
-from granary import as2, atom, microformats2, rss
-from granary.tests.test_bluesky import REPLY_BSKY
+from granary import atom, microformats2, rss
from granary.tests.test_as1 import (
ACTOR,
COMMENT,
- FOLLOW_WITH_ACTOR,
- FOLLOW_WITH_OBJECT,
- LIKE,
NOTE,
)
from oauth_dropins.webutil import util
-from oauth_dropins.webutil.testutil import requests_response
# import first so that Fake is defined before URL routes are registered
from .testutil import Fake, TestCase
from activitypub import ActivityPub
-import common
-from models import Object, Follower, User
-from web import Web
+from models import Object, Follower
-from .test_web import ACTOR_AS2, ACTOR_HTML, ACTOR_MF2, REPOST_AS2
+from .test_web import ACTOR_AS2, REPOST_AS2
ACTOR_WITH_PREFERRED_USERNAME = {
**ACTOR,
'preferredUsername': 'me',
}
+
def contents(activities):
return [(a.get('object') or a)['content'] for a in activities]
diff --git a/tests/test_protocol.py b/tests/test_protocol.py
index 0353626..e3079c7 100644
--- a/tests/test_protocol.py
+++ b/tests/test_protocol.py
@@ -13,7 +13,6 @@ from app import app
from models import Follower, Object, PROTOCOLS, User
import protocol
from protocol import Protocol
-import requests
from ui import UIProtocol
from web import Web
diff --git a/tests/test_redirect.py b/tests/test_redirect.py
index 25864ee..3da6a13 100644
--- a/tests/test_redirect.py
+++ b/tests/test_redirect.py
@@ -5,20 +5,17 @@ from unittest.mock import patch
from granary import as2
from oauth_dropins.webutil.testutil import requests_response
-import requests
# import first so that Fake is defined before URL routes are registered
from . import testutil
-from common import redirect_unwrap
from flask_app import app, cache
-from models import Object, User
+from models import Object
from web import Web
from .test_activitypub import ACTOR_BASE_FULL
from .test_web import (
ACTOR_AS2,
- ACTOR_AS2_FULL,
ACTOR_HTML,
REPOST_AS2,
REPOST_HTML,
@@ -146,7 +143,7 @@ class RedirectTest(testutil.TestCase):
self._test_as2(as2.CONTENT_TYPE)
resp = self.client.get('/r/https://user.com/bar',
- headers={'Accept': 'text/html'})
+ headers={'Accept': 'text/html'})
self.assertEqual(301, resp.status_code)
self.assertEqual('https://user.com/bar', resp.headers['Location'])
@@ -162,5 +159,5 @@ class RedirectTest(testutil.TestCase):
Object(id='https://user.com/bar', as2={}, deleted=True).put()
resp = self.client.get('/r/https://user.com/bar',
- headers={'Accept': as2.CONTENT_TYPE})
+ headers={'Accept': as2.CONTENT_TYPE})
self.assertEqual(404, resp.status_code, resp.get_data(as_text=True))
diff --git a/tests/test_web.py b/tests/test_web.py
index 3c573c4..4e1f3cf 100644
--- a/tests/test_web.py
+++ b/tests/test_web.py
@@ -4,28 +4,21 @@ import copy
from unittest.mock import patch
from urllib.parse import urlencode
-import feedparser
from flask import g, get_flashed_messages
-from granary import as1, as2, atom, microformats2
-from httpsig.sign import HeaderSigner
-from oauth_dropins.webutil import appengine_config, util
-from oauth_dropins.webutil.appengine_config import tasks_client
+from granary import as1, as2, microformats2
+from oauth_dropins.webutil import util
from oauth_dropins.webutil.appengine_info import APP_ID
from oauth_dropins.webutil.testutil import NOW, requests_response
from oauth_dropins.webutil.util import json_dumps, json_loads
import requests
-from requests import HTTPError
from werkzeug.exceptions import BadGateway, BadRequest
# import first so that Fake is defined before URL routes are registered
from . import testutil
from activitypub import ActivityPub, postprocess_as2
-from common import (
- CONTENT_TYPE_HTML,
- redirect_unwrap,
-)
-from models import Follower, Object, Target, User
+from common import CONTENT_TYPE_HTML
+from models import Follower, Object
from web import TASKS_LOCATION, Web
from . import test_activitypub
from .testutil import TestCase
@@ -210,7 +203,7 @@ REPLY_HTML = """\