launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #28875
[Merge] ~cjwatson/launchpad:black-testing into launchpad:master
Colin Watson has proposed merging ~cjwatson/launchpad:black-testing into launchpad:master.
Commit message:
lp.testing: Apply black
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/427281
--
The attached diff has been truncated due to its size.
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:black-testing into launchpad:master.
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index 4961658..2298cc3 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -88,3 +88,5 @@ ed7d7b97b8fb4ebe92799f922b0fa9c4bd1714e8
cf7c6a08bd010dd260bff4690d64479fadf37e67
# apply black to lp.soyuz
5a98ef6df022b52adc06787b56f2482bc4a28a3e
+# apply black to lp.testing
+15e1c80d57296e830e0dd85f1e03245281a88f02
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index b0c79ac..9593ef2 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -58,6 +58,7 @@ repos:
|services
|snappy
|soyuz
+ |testing
)/
- repo: https://github.com/PyCQA/isort
rev: 5.9.2
@@ -92,6 +93,7 @@ repos:
|services
|snappy
|soyuz
+ |testing
)/
- id: isort
alias: isort-black
@@ -116,6 +118,7 @@ repos:
|services
|snappy
|soyuz
+ |testing
)/
- repo: https://github.com/PyCQA/flake8
rev: 3.9.2
diff --git a/lib/lp/testing/__init__.py b/lib/lp/testing/__init__.py
index 63a45fc..604d2ff 100644
--- a/lib/lp/testing/__init__.py
+++ b/lib/lp/testing/__init__.py
@@ -2,115 +2,99 @@
# GNU Affero General Public License version 3 (see the file LICENSE).
__all__ = [
- 'AbstractYUITestCase',
- 'ANONYMOUS',
- 'admin_logged_in',
- 'anonymous_logged_in',
- 'api_url',
- 'BrowserTestCase',
- 'build_yui_unittest_suite',
- 'celebrity_logged_in',
- 'clean_up_reactor',
- 'ExpectedException',
- 'extract_lp_cache',
- 'FakeAdapterMixin',
- 'FakeLaunchpadRequest',
- 'FakeTime',
- 'launchpadlib_credentials_for',
- 'launchpadlib_for',
- 'login',
- 'login_admin',
- 'login_as',
- 'login_celebrity',
- 'login_person',
- 'login_team',
- 'logout',
- 'map_branch_contents',
- 'normalize_whitespace',
- 'nonblocking_readline',
- 'oauth_access_token_for',
- 'person_logged_in',
- 'record_statements',
- 'reset_logging',
- 'run_process',
- 'run_script',
- 'run_with_login',
- 'run_with_storm_debug',
- 'RunIsolatedTest',
- 'StormStatementRecorder',
- 'test_tales',
- 'TestCase',
- 'TestCaseWithFactory',
- 'time_counter',
- 'unlink_source_packages',
- 'verifyObject',
- 'with_anonymous_login',
- 'with_celebrity_logged_in',
- 'with_person_logged_in',
- 'ws_object',
- 'YUIUnitTestCase',
- ]
+ "AbstractYUITestCase",
+ "ANONYMOUS",
+ "admin_logged_in",
+ "anonymous_logged_in",
+ "api_url",
+ "BrowserTestCase",
+ "build_yui_unittest_suite",
+ "celebrity_logged_in",
+ "clean_up_reactor",
+ "ExpectedException",
+ "extract_lp_cache",
+ "FakeAdapterMixin",
+ "FakeLaunchpadRequest",
+ "FakeTime",
+ "launchpadlib_credentials_for",
+ "launchpadlib_for",
+ "login",
+ "login_admin",
+ "login_as",
+ "login_celebrity",
+ "login_person",
+ "login_team",
+ "logout",
+ "map_branch_contents",
+ "normalize_whitespace",
+ "nonblocking_readline",
+ "oauth_access_token_for",
+ "person_logged_in",
+ "record_statements",
+ "reset_logging",
+ "run_process",
+ "run_script",
+ "run_with_login",
+ "run_with_storm_debug",
+ "RunIsolatedTest",
+ "StormStatementRecorder",
+ "test_tales",
+ "TestCase",
+ "TestCaseWithFactory",
+ "time_counter",
+ "unlink_source_packages",
+ "verifyObject",
+ "with_anonymous_login",
+ "with_celebrity_logged_in",
+ "with_person_logged_in",
+ "ws_object",
+ "YUIUnitTestCase",
+]
-from contextlib import contextmanager
-from datetime import (
- datetime,
- timedelta,
- )
-from fnmatch import fnmatchcase
-from functools import partial
import io
import logging
import os
import re
-from select import select
import shutil
import subprocess
import sys
import tempfile
import time
import unittest
+from contextlib import contextmanager
+from datetime import datetime, timedelta
+from fnmatch import fnmatchcase
+from functools import partial
+from select import select
-from breezy import trace
-from breezy.controldir import (
- ControlDir,
- format_registry,
- )
import fixtures
-from lazr.restful.testing.tales import test_tales
-from lazr.restful.testing.webservice import FakeRequest
import lp_sitecustomize
import oops_datedir_repo.serializer_rfc822
import pytz
import simplejson
import six
-from storm.store import Store
import subunit
import testtools
+import transaction
+import zope.event
+from breezy import trace
+from breezy.controldir import ControlDir, format_registry
+from lazr.restful.testing.tales import test_tales
+from lazr.restful.testing.webservice import FakeRequest
+from storm.store import Store
from testtools.content import Content
from testtools.content_type import UTF8_TEXT
-from testtools.matchers import (
- Equals,
- MatchesRegex,
- MatchesSetwise,
- )
+from testtools.matchers import Equals, MatchesRegex, MatchesSetwise
from testtools.testcase import ExpectedException as TTExpectedException
-import transaction
-from zope.component import (
- getMultiAdapter,
- getSiteManager,
- getUtility,
- )
-import zope.event
+from zope.component import getMultiAdapter, getSiteManager, getUtility
from zope.interface import Interface
from zope.interface.interfaces import ComponentLookupError
from zope.interface.verify import verifyObject as zope_verifyObject
from zope.publisher.interfaces import IEndRequestEvent
from zope.publisher.interfaces.browser import IBrowserRequest
from zope.security.management import queryInteraction
-from zope.security.proxy import (
- isinstance as zope_isinstance,
- removeSecurityProxy,
- )
+from zope.security.proxy import isinstance as zope_isinstance
+from zope.security.proxy import removeSecurityProxy
from lp.app.interfaces.launchpad import ILaunchpadCelebrities
from lp.app.interfaces.security import IAuthorization
@@ -120,10 +104,7 @@ from lp.services import features
from lp.services.config import config
from lp.services.database.sqlbase import flush_database_caches
from lp.services.features.flags import FeatureController
-from lp.services.features.model import (
- FeatureFlag,
- getFeatureStore,
- )
+from lp.services.features.model import FeatureFlag, getFeatureStore
from lp.services.features.webapp import ScopesFromRequest
from lp.services.osutils import override_environ
from lp.services.webapp import canonical_url
@@ -132,16 +113,17 @@ from lp.services.webapp.adapter import (
print_queries,
start_sql_logging,
stop_sql_logging,
- )
+)
from lp.services.webapp.authorization import (
clear_cache as clear_permission_cache,
- )
+)
from lp.services.webapp.interaction import ANONYMOUS
from lp.services.webapp.servers import (
LaunchpadTestRequest,
StepsToGo,
WebServiceTestRequest,
- )
+)
+
# Import the login helper functions here as it is a much better
# place to import them from in tests.
from lp.testing._login import (
@@ -160,22 +142,18 @@ from lp.testing._login import (
with_anonymous_login,
with_celebrity_logged_in,
with_person_logged_in,
- )
+)
from lp.testing._webservice import (
api_url,
launchpadlib_credentials_for,
launchpadlib_for,
oauth_access_token_for,
- )
+)
from lp.testing.dbuser import switch_dbuser
-from lp.testing.fixture import (
- CaptureOops,
- ZopeEventHandlerFixture,
- )
+from lp.testing.fixture import CaptureOops, ZopeEventHandlerFixture
from lp.testing.karma import KarmaRecorder
from lp.testing.mail_helpers import pop_notifications
-
# The following names have been imported for the purpose of being
# exported. They are referred to here to silence lint warnings.
admin_logged_in
@@ -207,7 +185,7 @@ def reset_logging():
# Remove all handlers from non-root loggers, and remove the loggers too.
loggerDict = logging.Logger.manager.loggerDict
for name, logger in list(loggerDict.items()):
- if name == 'pagetests-access':
+ if name == "pagetests-access":
# Don't reset the hit logger used by the test infrastructure.
continue
if not isinstance(logger, logging.PlaceHolder):
@@ -216,7 +194,7 @@ def reset_logging():
del loggerDict[name]
# Remove all handlers from the root logger
- root = logging.getLogger('')
+ root = logging.getLogger("")
for handler in root.handlers:
root.removeHandler(handler)
@@ -232,6 +210,7 @@ def reset_logging():
# Reset the setup
from zope.testrunner.logsupport import Logging
from zope.testrunner.runner import Runner
+
Logging(Runner()).global_setup()
lp_sitecustomize.customize_logger()
@@ -324,6 +303,7 @@ class StormStatementRecorder:
of every SQL query, or a callable that takes the SQL query string and
returns a boolean decision as to whether a traceback is desired.
"""
+
# Note that tests for this are in lp.services.webapp.tests.
# test_statementtracer, because this is really just a small wrapper of
# the functionality found there.
@@ -334,7 +314,7 @@ class StormStatementRecorder:
@property
def queries(self):
- return [record['sql'] for record in self.query_data]
+ return [record["sql"] for record in self.query_data]
@property
def count(self):
@@ -342,7 +322,7 @@ class StormStatementRecorder:
@property
def statements(self):
- return [record['sql'][3] for record in self.query_data]
+ return [record["sql"][3] for record in self.query_data]
def __enter__(self):
self.query_data = start_sql_logging(self.tracebacks_if)
@@ -387,7 +367,8 @@ class RequestTimelineCollector:
After each web request the count and queries attributes are updated.
"""
self._event_fixture = ZopeEventHandlerFixture(
- self, (IEndRequestEvent, ))
+ self, (IEndRequestEvent,)
+ )
self._event_fixture.setUp()
self._active = True
@@ -421,9 +402,14 @@ def record_statements(function, *args, **kwargs):
return (ret, recorder.statements)
-def record_two_runs(tested_method, item_creator, first_round_number,
- second_round_number=None, login_method=None,
- record_request=False):
+def record_two_runs(
+ tested_method,
+ item_creator,
+ first_round_number,
+ second_round_number=None,
+ login_method=None,
+ record_request=False,
+):
"""A helper that returns the two storm statement recorders
obtained when running tested_method after having run the
method {item_creator} {first_round_number} times and then
@@ -477,6 +463,7 @@ def record_two_runs(tested_method, item_creator, first_round_number,
def run_with_storm_debug(function, *args, **kwargs):
"""A helper function to run a function with storm debug tracing on."""
from storm.tracer import debug
+
debug(True)
try:
return function(*args, **kwargs)
@@ -534,10 +521,12 @@ class TestCase(testtools.TestCase, fixtures.TestWithFixtures):
def assertProvides(self, obj, interface):
"""Assert 'obj' correctly provides 'interface'."""
from lp.testing.matchers import Provides
+
self.assertThat(obj, Provides(interface))
- def assertNotifies(self, event_types, propagate, callable_obj,
- *args, **kwargs):
+ def assertNotifies(
+ self, event_types, propagate, callable_obj, *args, **kwargs
+ ):
"""Assert that a callable performs a given notification.
:param event_type: One or more event types that notification is
@@ -555,7 +544,7 @@ class TestCase(testtools.TestCase, fixtures.TestWithFixtures):
with EventRecorder(propagate=propagate) as recorder:
result = callable_obj(*args, **kwargs)
if len(recorder.events) == 0:
- raise AssertionError('No notification was performed.')
+ raise AssertionError("No notification was performed.")
self.assertEqual(len(event_types), len(recorder.events))
for event, expected_type in zip(recorder.events, event_types):
self.assertIsInstance(event, expected_type)
@@ -572,12 +561,11 @@ class TestCase(testtools.TestCase, fixtures.TestWithFixtures):
result = callable_obj(*args, **kwargs)
if len(recorder.events) == 1:
raise AssertionError(
- 'An event was generated: %r.' % recorder.events[0])
+ "An event was generated: %r." % recorder.events[0]
+ )
elif len(recorder.events) > 1:
- event_list = ', '.join(
- [repr(event) for event in recorder.events])
- raise AssertionError(
- 'Events were generated: %s.' % event_list)
+ event_list = ", ".join([repr(event) for event in recorder.events])
+ raise AssertionError("Events were generated: %s." % event_list)
return result
def assertSqlAttributeEqualsDate(self, sql_object, attribute_name, date):
@@ -599,22 +587,26 @@ class TestCase(testtools.TestCase, fixtures.TestWithFixtures):
sql_class = type(sql_object)
store = Store.of(sql_object)
found_object = store.find(
- sql_class, **({'id': sql_object.id, attribute_name: date})).one()
+ sql_class, **({"id": sql_object.id, attribute_name: date})
+ ).one()
if found_object is None:
self.fail(
"Expected %s to be %s, but it was %s."
- % (attribute_name, date, getattr(sql_object, attribute_name)))
-
- def assertTextMatchesExpressionIgnoreWhitespace(self,
- regular_expression_txt,
- text):
+ % (attribute_name, date, getattr(sql_object, attribute_name))
+ )
+ def assertTextMatchesExpressionIgnoreWhitespace(
+ self, regular_expression_txt, text
+ ):
def normalise_whitespace(text):
- return ' '.join(text.split())
+ return " ".join(text.split())
+
pattern = re.compile(
- normalise_whitespace(regular_expression_txt), re.S)
+ normalise_whitespace(regular_expression_txt), re.S
+ )
self.assertIsNot(
- None, pattern.search(normalise_whitespace(text)), text)
+ None, pattern.search(normalise_whitespace(text)), text
+ )
def assertIsInstance(self, instance, assert_class, msg=None):
"""Assert that an instance is an instance of assert_class.
@@ -623,7 +615,7 @@ class TestCase(testtools.TestCase, fixtures.TestWithFixtures):
to isinstance.
"""
if msg is None:
- msg = '%r is not an instance of %r' % (instance, assert_class)
+ msg = "%r is not an instance of %r" % (instance, assert_class)
self.assertTrue(zope_isinstance(instance, assert_class), msg)
def assertIsNot(self, expected, observed, msg=None):
@@ -636,8 +628,9 @@ class TestCase(testtools.TestCase, fixtures.TestWithFixtures):
"""Assert that 'iter1' has the same content as 'iter2'."""
self.assertThat(iter1, MatchesSetwise(*(map(Equals, iter2))))
- def assertRaisesWithContent(self, exception, exception_content,
- func, *args, **kwargs):
+ def assertRaisesWithContent(
+ self, exception, exception_content, func, *args, **kwargs
+ ):
"""Check if the given exception is raised with given content.
If the exception isn't raised or the exception_content doesn't
@@ -650,7 +643,8 @@ class TestCase(testtools.TestCase, fixtures.TestWithFixtures):
"""Assert that 'variable' is strictly between two boundaries."""
self.assertTrue(
lower_bound < variable < upper_bound,
- "%r < %r < %r" % (lower_bound, variable, upper_bound))
+ "%r < %r < %r" % (lower_bound, variable, upper_bound),
+ )
def assertVectorEqual(self, *args):
"""Apply assertEqual to all given pairs in one go.
@@ -681,32 +675,36 @@ class TestCase(testtools.TestCase, fixtures.TestWithFixtures):
The config values will be restored during test tearDown.
"""
name = self.factory.getUniqueString()
- body = '\n'.join("%s: %s" % (k, v) for k, v in kwargs.items())
+ body = "\n".join("%s: %s" % (k, v) for k, v in kwargs.items())
config.push(name, "\n[%s]\n%s\n" % (section, body))
self.addCleanup(config.pop, name)
def attachOopses(self):
if len(self.oopses) > 0:
for (i, report) in enumerate(self.oopses):
- content = Content(UTF8_TEXT,
- partial(oops_datedir_repo.serializer_rfc822.to_chunks,
- report))
+ content = Content(
+ UTF8_TEXT,
+ partial(
+ oops_datedir_repo.serializer_rfc822.to_chunks, report
+ ),
+ )
self.addDetail("oops-%d" % i, content)
def attachLibrarianLog(self, fixture):
"""Include the logChunks from fixture in the test details."""
# Evaluate the log when called, not later, to permit the librarian to
# be shutdown before the detail is rendered.
- if 'librarian-log' not in self.getDetails():
+ if "librarian-log" not in self.getDetails():
chunks = fixture.getLogChunks()
content = Content(UTF8_TEXT, lambda: chunks)
- self.addDetail('librarian-log', content)
+ self.addDetail("librarian-log", content)
def setUp(self):
super().setUp()
# Circular imports.
from lp.testing.factory import ObjectFactory
from lp.testing.layers import LibrarianLayer
+
self.factory = ObjectFactory()
# Record the oopses generated during the test run.
# You can call self.oops_capture.sync() to collect oopses from
@@ -716,8 +714,8 @@ class TestCase(testtools.TestCase, fixtures.TestWithFixtures):
self.addCleanup(self.attachOopses)
if LibrarianLayer.librarian_fixture is not None:
self.addCleanup(
- self.attachLibrarianLog,
- LibrarianLayer.librarian_fixture)
+ self.attachLibrarianLog, LibrarianLayer.librarian_fixture
+ )
# Remove all log handlers, tests should not depend on global logging
# config but should make their own config instead.
logger = logging.getLogger()
@@ -733,7 +731,8 @@ class TestCase(testtools.TestCase, fixtures.TestWithFixtures):
if len(statements) != expected_count:
self.fail(
"Expected %d statements, got %d:\n%s"
- % (expected_count, len(statements), "\n".join(statements)))
+ % (expected_count, len(statements), "\n".join(statements))
+ )
return ret
def useTempDir(self):
@@ -746,8 +745,8 @@ class TestCase(testtools.TestCase, fixtures.TestWithFixtures):
def _unfoldEmailHeader(self, header):
"""Unfold a multiline email header."""
- header = ''.join(header.splitlines())
- return header.replace('\t', ' ')
+ header = "".join(header.splitlines())
+ return header.replace("\t", " ")
def assertEmailHeadersEqual(self, expected, observed):
"""Assert that two email headers are equal.
@@ -756,21 +755,23 @@ class TestCase(testtools.TestCase, fixtures.TestWithFixtures):
"""
return self.assertEqual(
self._unfoldEmailHeader(expected),
- self._unfoldEmailHeader(observed))
+ self._unfoldEmailHeader(observed),
+ )
def assertStartsWith(self, s, prefix):
if not s.startswith(prefix):
raise AssertionError(
- 'string %r does not start with %r' % (s, prefix))
+ "string %r does not start with %r" % (s, prefix)
+ )
def assertEndsWith(self, s, suffix):
"""Asserts that s ends with suffix."""
if not s.endswith(suffix):
raise AssertionError(
- 'string %r does not end with %r' % (s, suffix))
+ "string %r does not end with %r" % (s, suffix)
+ )
- def checkPermissions(self, expected_permissions, used_permissions,
- type_):
+ def checkPermissions(self, expected_permissions, used_permissions, type_):
"""Check if the used_permissions match expected_permissions.
:param expected_permissions: A dictionary mapping a permission
@@ -781,23 +782,29 @@ class TestCase(testtools.TestCase, fixtures.TestWithFixtures):
"""
expected = set(expected_permissions.keys())
self.assertEqual(
- expected, set(used_permissions.values()),
- 'Unexpected %s permissions' % type_)
+ expected,
+ set(used_permissions.values()),
+ "Unexpected %s permissions" % type_,
+ )
for permission in expected_permissions:
attribute_names = {
- name for name, value in used_permissions.items()
- if value == permission}
+ name
+ for name, value in used_permissions.items()
+ if value == permission
+ }
self.assertEqual(
- expected_permissions[permission], attribute_names,
- 'Unexpected set of attributes with %s permission %s:\n'
- 'Defined but not expected: %s\n'
- 'Expected but not defined: %s'
+ expected_permissions[permission],
+ attribute_names,
+ "Unexpected set of attributes with %s permission %s:\n"
+ "Defined but not expected: %s\n"
+ "Expected but not defined: %s"
% (
- type_, permission,
- sorted(
- attribute_names - expected_permissions[permission]),
- sorted(
- expected_permissions[permission] - attribute_names)))
+ type_,
+ permission,
+ sorted(attribute_names - expected_permissions[permission]),
+ sorted(expected_permissions[permission] - attribute_names),
+ ),
+ )
def assertEmailQueueLength(self, length, sort_key=None):
"""Pop the email queue, assert its length, and return it.
@@ -806,10 +813,15 @@ class TestCase(testtools.TestCase, fixtures.TestWithFixtures):
"""
notifications = pop_notifications(sort_key=sort_key)
self.assertEqual(
- length, len(notifications),
- "Expected %d emails, got %d:\n\n%s" % (
- length, len(notifications),
- "\n\n".join(str(n) for n in notifications)))
+ length,
+ len(notifications),
+ "Expected %d emails, got %d:\n\n%s"
+ % (
+ length,
+ len(notifications),
+ "\n\n".join(str(n) for n in notifications),
+ ),
+ )
return notifications
def getWebserviceJSON(self, webservice, url):
@@ -820,12 +832,12 @@ class TestCase(testtools.TestCase, fixtures.TestWithFixtures):
class TestCaseWithFactory(TestCase):
-
def setUp(self, user=ANONYMOUS):
super().setUp()
login(user)
self.addCleanup(logout)
from lp.testing.factory import LaunchpadObjectFactory
+
self.factory = LaunchpadObjectFactory()
self.direct_database_server = False
self._use_bzr_branch_called = False
@@ -835,7 +847,7 @@ class TestCaseWithFactory(TestCase):
# necessarily equal logging.getLogger('brz'), so we have to explicitly
# make it so in order to avoid "No handlers for "brz" logger'
# messages.
- trace._brz_logger = logging.getLogger('brz')
+ trace._brz_logger = logging.getLogger("brz")
def getUserBrowser(self, url=None, user=None):
"""Return a Browser logged in as a fresh user, maybe opened at `url`.
@@ -844,6 +856,7 @@ class TestCaseWithFactory(TestCase):
"""
# Do the import here to avoid issues with import cycles.
from lp.testing.pages import setupBrowserForUser
+
login(ANONYMOUS)
if user is None:
user = self.factory.makePerson()
@@ -854,6 +867,7 @@ class TestCaseWithFactory(TestCase):
def getNonRedirectingBrowser(self, url=None, user=None):
from lp.testing.pages import setupBrowser
+
if user == ANONYMOUS:
browser = setupBrowser()
else:
@@ -874,9 +888,14 @@ class TestCaseWithFactory(TestCase):
format = format_registry.get(format)()
return ControlDir.create_branch_convenience(branch_url, format=format)
- def create_branch_and_tree(self, tree_location=None, product=None,
- db_branch=None, format=None,
- **kwargs):
+ def create_branch_and_tree(
+ self,
+ tree_location=None,
+ product=None,
+ db_branch=None,
+ format=None,
+ **kwargs
+ ):
"""Create a database branch, bzr branch and bzr checkout.
:param tree_location: The path on disk to create the tree at.
@@ -891,7 +910,8 @@ class TestCaseWithFactory(TestCase):
else:
db_branch = self.factory.makeProductBranch(product, **kwargs)
branch_url = (
- 'lp-internal:///' + removeSecurityProxy(db_branch).unique_name)
+ "lp-internal:///" + removeSecurityProxy(db_branch).unique_name
+ )
if not self.direct_database_server:
transaction.commit()
bzr_branch = self.createBranchAtURL(branch_url, format=format)
@@ -899,7 +919,8 @@ class TestCaseWithFactory(TestCase):
tree_location = tempfile.mkdtemp()
self.addCleanup(lambda: shutil.rmtree(tree_location))
return db_branch, bzr_branch.create_checkout(
- tree_location, lightweight=True)
+ tree_location, lightweight=True
+ )
def createBzrBranch(self, db_branch, parent=None):
"""Create a bzr branch for a database branch.
@@ -912,16 +933,22 @@ class TestCaseWithFactory(TestCase):
bzr_branch.pull(parent)
naked_branch = removeSecurityProxy(db_branch)
naked_branch.last_scanned_id = six.ensure_text(
- bzr_branch.last_revision())
+ bzr_branch.last_revision()
+ )
return bzr_branch
def useTempBzrHome(self):
self.useTempDir()
# Avoid leaking local user configuration into tests.
- self.useContext(override_environ(
- BRZ_HOME=os.getcwd(), BRZ_EMAIL=None,
- BZR_HOME=os.getcwd(), BZR_EMAIL=None, EMAIL=None,
- ))
+ self.useContext(
+ override_environ(
+ BRZ_HOME=os.getcwd(),
+ BRZ_EMAIL=None,
+ BZR_HOME=os.getcwd(),
+ BZR_EMAIL=None,
+ EMAIL=None,
+ )
+ )
def useBzrBranches(self, direct_database=False):
"""Prepare for using bzr branches.
@@ -939,7 +966,8 @@ class TestCaseWithFactory(TestCase):
if direct_database != self.direct_database_server:
raise AssertionError(
"useBzrBranches called with inconsistent values for "
- "direct_database")
+ "direct_database"
+ )
return
self._use_bzr_branch_called = True
self.useTempBzrHome()
@@ -961,8 +989,9 @@ class BrowserTestCase(TestCaseWithFactory):
super().setUp()
self.user = self.factory.makePerson()
- def getViewBrowser(self, context, view_name=None, no_login=False,
- rootsite=None, user=None):
+ def getViewBrowser(
+ self, context, view_name=None, no_login=False, rootsite=None, user=None
+ ):
# Make sure that there is a user interaction in order to generate the
# canonical url for the context object.
if no_login:
@@ -975,27 +1004,33 @@ class BrowserTestCase(TestCaseWithFactory):
logout()
if no_login:
from lp.testing.pages import setupBrowser
+
browser = setupBrowser()
browser.open(url)
return browser
else:
return self.getUserBrowser(url, user)
- def getMainContent(self, context, view_name=None, rootsite=None,
- no_login=False, user=None):
+ def getMainContent(
+ self, context, view_name=None, rootsite=None, no_login=False, user=None
+ ):
"""Beautiful soup of the main content area of context's page."""
from lp.testing.pages import find_main_content
+
browser = self.getViewBrowser(
- context, view_name, rootsite=rootsite, no_login=no_login,
- user=user)
+ context, view_name, rootsite=rootsite, no_login=no_login, user=user
+ )
return find_main_content(browser.contents)
- def getMainText(self, context, view_name=None, rootsite=None,
- no_login=False, user=None):
+ def getMainText(
+ self, context, view_name=None, rootsite=None, no_login=False, user=None
+ ):
"""Return the main text of a context's page."""
from lp.testing.pages import extract_text
+
return extract_text(
- self.getMainContent(context, view_name, rootsite, no_login, user))
+ self.getMainContent(context, view_name, rootsite, no_login, user)
+ )
class WebServiceTestCase(TestCaseWithFactory):
@@ -1007,13 +1042,15 @@ class WebServiceTestCase(TestCaseWithFactory):
# TestTwistedJobRunner.test_timeout fails if this is at the
# module level. There is probably some hidden circular import.
from lp.testing.layers import AppServerLayer
+
return AppServerLayer
def setUp(self):
super().setUp()
- self.ws_version = 'devel'
+ self.ws_version = "devel"
self.service = self.factory.makeLaunchpadService(
- version=self.ws_version)
+ version=self.ws_version
+ )
def wsObject(self, obj, user=None):
"""Return the launchpadlib version of the supplied object.
@@ -1024,7 +1061,8 @@ class WebServiceTestCase(TestCaseWithFactory):
"""
if user is not None:
service = self.factory.makeLaunchpadService(
- user, version=self.ws_version)
+ user, version=self.ws_version
+ )
else:
service = self.service
return ws_object(service, obj)
@@ -1033,7 +1071,7 @@ class WebServiceTestCase(TestCaseWithFactory):
class AbstractYUITestCase(TestCase):
layer = None
- suite_name = ''
+ suite_name = ""
# 30 seconds for the suite.
suite_timeout = 30000
# By default we do not restrict per-test or times. yuixhr tests do.
@@ -1068,11 +1106,14 @@ class AbstractYUITestCase(TestCase):
# html5browser imports from the gir/pygtk stack which causes
# twisted tests to break because of gtk's initialize.
from lp.testing import html5browser
+
client = html5browser.Browser()
- page = client.load_page(self.html_uri,
- timeout=self.suite_timeout,
- initial_timeout=self.initial_timeout,
- incremental_timeout=self.incremental_timeout)
+ page = client.load_page(
+ self.html_uri,
+ timeout=self.suite_timeout,
+ initial_timeout=self.initial_timeout,
+ incremental_timeout=self.incremental_timeout,
+ )
report = None
if page.content:
report = simplejson.loads(page.content)
@@ -1084,21 +1125,22 @@ class AbstractYUITestCase(TestCase):
# Data['results'] is a dict (type=report)
# with 1 or more dicts (type=testcase)
# with 1 for more dicts (type=test).
- if report.get('type', None) != 'complete':
+ if report.get("type", None) != "complete":
# Did not get a report back.
self._yui_results = self.MISSING_REPORT
return
self._yui_results = {}
- for key, value in report['results'].items():
- if isinstance(value, dict) and value['type'] == 'testcase':
+ for key, value in report["results"].items():
+ if isinstance(value, dict) and value["type"] == "testcase":
testcase_name = key
test_case = value
for key, value in test_case.items():
- if isinstance(value, dict) and value['type'] == 'test':
- test_name = '%s.%s' % (testcase_name, key)
+ if isinstance(value, dict) and value["type"] == "test":
+ test_name = "%s.%s" % (testcase_name, key)
test = value
self._yui_results[test_name] = dict(
- result=test['result'], message=test['message'])
+ result=test["result"], message=test["message"]
+ )
def checkResults(self):
"""Check the results.
@@ -1107,21 +1149,27 @@ class AbstractYUITestCase(TestCase):
from here.
"""
if self._yui_results == self.TIMEOUT:
- msg = 'JS timed out.'
+ msg = "JS timed out."
if self._last_test_info is not None:
try:
- msg += (' The last test that ran to '
- 'completion before timing out was '
- '%(testCase)s:%(testName)s. The test %(type)sed.'
- % self._last_test_info)
+ msg += (
+ " The last test that ran to "
+ "completion before timing out was "
+ "%(testCase)s:%(testName)s. The test %(type)sed."
+ % self._last_test_info
+ )
except (KeyError, TypeError):
- msg += (' The test runner received an unexpected error '
- 'when trying to show information about the last '
- 'test to run. The data it received was %r.'
- % (self._last_test_info,))
- elif (self.incremental_timeout is not None or
- self.initial_timeout is not None):
- msg += ' The test may never have started.'
+ msg += (
+ " The test runner received an unexpected error "
+ "when trying to show information about the last "
+ "test to run. The data it received was %r."
+ % (self._last_test_info,)
+ )
+ elif (
+ self.incremental_timeout is not None
+ or self.initial_timeout is not None
+ ):
+ msg += " The test may never have started."
self.fail(msg)
elif self._yui_results == self.MISSING_REPORT:
self.fail("The data returned by js is not a test report.")
@@ -1130,27 +1178,29 @@ class AbstractYUITestCase(TestCase):
failures = []
for test_name in self._yui_results:
result = self._yui_results[test_name]
- if result['result'] not in ('pass', 'ignore'):
+ if result["result"] not in ("pass", "ignore"):
failures.append(
- 'Failure in %s.%s: %s' % (
- self.test_path, test_name, result['message']))
- self.assertEqual([], failures, '\n'.join(failures))
+ "Failure in %s.%s: %s"
+ % (self.test_path, test_name, result["message"])
+ )
+ self.assertEqual([], failures, "\n".join(failures))
class YUIUnitTestCase(AbstractYUITestCase):
- _testMethodName = 'checkResults'
+ _testMethodName = "checkResults"
def initialize(self, test_path):
# The path is a .html file.
self.test_path = test_path
- self.html_uri = 'file://%s' % os.path.join(
- config.root, 'lib', self.test_path)
+ self.html_uri = "file://%s" % os.path.join(
+ config.root, "lib", self.test_path
+ )
def build_yui_unittest_suite(app_testing_path, yui_test_class):
suite = unittest.TestSuite()
- testing_path = os.path.join(config.root, 'lib', app_testing_path)
+ testing_path = os.path.join(config.root, "lib", app_testing_path)
unit_test_names = _harvest_yui_test_files(testing_path)
for unit_test_path in unit_test_names:
test_case = yui_test_class()
@@ -1200,7 +1250,9 @@ class RunIsolatedTest(testtools.RunTest):
try:
return self._run_started(
_StartedTestResult(
- testtools.ExtendedToOriginalDecorator(result)))
+ testtools.ExtendedToOriginalDecorator(result)
+ )
+ )
finally:
result.stopTest(self.case)
@@ -1224,7 +1276,7 @@ class RunIsolatedTest(testtools.RunTest):
if pid == 0:
# Child.
os.close(pread)
- fdwrite = os.fdopen(pwrite, 'wb', 1)
+ fdwrite = os.fdopen(pwrite, "wb", 1)
# Send results to the subunit stream client so that the parent
# process can obtain the result.
super().run(subunit.TestProtocolClient(fdwrite))
@@ -1239,15 +1291,16 @@ class RunIsolatedTest(testtools.RunTest):
else:
# Parent.
os.close(pwrite)
- fdread = os.fdopen(pread, 'rb')
+ fdread = os.fdopen(pread, "rb")
# Accept the result from the child process, but don't write a
# duplicate copy to stdout.
protocol = subunit.TestProtocolServer(
- result, stream=subunit.DiscardStream())
+ result, stream=subunit.DiscardStream()
+ )
protocol.readFrom(fdread)
fdread.close()
os.waitpid(pid, 0)
- layer = getattr(self.case, 'layer', None)
+ layer = getattr(self.case, "layer", None)
if layer is not None and issubclass(layer, DatabaseLayer):
layer.force_dirty_database()
@@ -1275,8 +1328,9 @@ class EventRecorder:
return self
def __exit__(self, exc_type, exc_value, traceback):
- assert zope.event.subscribers == self.new_subscribers, (
- 'Subscriber list has been changed while running!')
+ assert (
+ zope.event.subscribers == self.new_subscribers
+ ), "Subscriber list has been changed while running!"
zope.event.subscribers[:] = self.old_subscribers
@@ -1285,8 +1339,9 @@ def feature_flags():
"""Provide a context in which feature flags work."""
empty_request = LaunchpadTestRequest()
old_features = features.get_relevant_feature_controller()
- features.install_feature_controller(FeatureController(
- ScopesFromRequest(empty_request).lookup))
+ features.install_feature_controller(
+ FeatureController(ScopesFromRequest(empty_request).lookup)
+ )
try:
yield
finally:
@@ -1330,11 +1385,17 @@ def run_script(cmd_line, env=None, cwd=None, universal_newlines=True):
"""
if env is None:
env = os.environ.copy()
- env.pop('PYTHONPATH', None)
+ env.pop("PYTHONPATH", None)
process = subprocess.Popen(
- cmd_line, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE, env=env, cwd=cwd,
- universal_newlines=universal_newlines)
+ cmd_line,
+ shell=True,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ env=env,
+ cwd=cwd,
+ universal_newlines=universal_newlines,
+ )
(out, err) = process.communicate()
return out, err, process.returncode
@@ -1356,12 +1417,16 @@ def run_process(cmd, env=None, universal_newlines=True):
"""
if env is None:
env = os.environ.copy()
- env.pop('PYTHONPATH', None)
+ env.pop("PYTHONPATH", None)
with open(os.devnull, "rb") as devnull:
process = subprocess.Popen(
- cmd, stdin=devnull, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE, env=env,
- universal_newlines=universal_newlines)
+ cmd,
+ stdin=devnull,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ env=env,
+ universal_newlines=universal_newlines,
+ )
stdout, stderr = process.communicate()
return stdout, stderr, process.returncode
@@ -1392,7 +1457,7 @@ def map_branch_contents(branch):
for _, entries in tree.walkdirs():
for entry in entries:
file_path, file_name, file_type = entry[:3]
- if file_type == 'file':
+ if file_type == "file":
stored_file = tree.get_file(file_path)
contents[file_path] = stored_file.read()
finally:
@@ -1401,7 +1466,7 @@ def map_branch_contents(branch):
return contents
-def set_feature_flag(name, value, scope='default', priority=1):
+def set_feature_flag(name, value, scope="default", priority=1):
"""Set a feature flag to the specified value.
In order to access the flag, use the feature_flags context manager or
@@ -1411,8 +1476,7 @@ def set_feature_flag(name, value, scope='default', priority=1):
:param scope: The scope in which the specified value applies.
"""
assert features.get_relevant_feature_controller() is not None
- flag = FeatureFlag(
- scope=scope, flag=name, value=value, priority=priority)
+ flag = FeatureFlag(scope=scope, flag=name, value=value, priority=priority)
store = getFeatureStore()
store.add(flag)
# Make sure that the feature is saved into the db right now.
@@ -1463,7 +1527,8 @@ def unlink_source_packages(product):
packaging_util.deletePackaging(
source_package.productseries,
source_package.sourcepackagename,
- source_package.distroseries)
+ source_package.distroseries,
+ )
class ExpectedException(TTExpectedException):
@@ -1479,9 +1544,9 @@ class ExpectedException(TTExpectedException):
def extract_lp_cache(text):
- match = re.search(r'<script[^>]*>LP.cache = (\{.*\});</script>', text)
+ match = re.search(r"<script[^>]*>LP.cache = (\{.*\});</script>", text)
if match is None:
- raise ValueError('No JSON cache found.')
+ raise ValueError("No JSON cache found.")
return simplejson.loads(match.group(1))
@@ -1494,7 +1559,7 @@ def nonblocking_readline(instream, timeout):
result = io.BytesIO()
start = now = time.time()
deadline = start + timeout
- while (now < deadline and not result.getvalue().endswith(b'\n')):
+ while now < deadline and not result.getvalue().endswith(b"\n"):
rlist = select([instream], [], [], deadline - now)
if rlist:
# Reading 1 character at a time is inefficient, but means
@@ -1508,7 +1573,6 @@ def nonblocking_readline(instream, timeout):
class FakeLaunchpadRequest(FakeRequest):
-
@property
def stepstogo(self):
"""See `IBasicLaunchpadRequest`."""
@@ -1522,29 +1586,40 @@ class FakeAdapterMixin:
during the setup of a test and they will be unregistered when the
test completes.
"""
- def registerAdapter(self, adapter_class, for_interfaces,
- provided_interface, name=None):
+
+ def registerAdapter(
+ self, adapter_class, for_interfaces, provided_interface, name=None
+ ):
"""Register an adapter from the required interfacs to the provided.
eg. registerAdapter(
TestOtherThing, (IThing, ILayer), IOther, name='fnord')
"""
getSiteManager().registerAdapter(
- adapter_class, for_interfaces, provided_interface, name=name)
+ adapter_class, for_interfaces, provided_interface, name=name
+ )
self.addCleanup(
- getSiteManager().unregisterAdapter, adapter_class,
- for_interfaces, provided_interface, name=name)
-
- def registerAuthorizationAdapter(self, authorization_class,
- for_interface, permission_name):
+ getSiteManager().unregisterAdapter,
+ adapter_class,
+ for_interfaces,
+ provided_interface,
+ name=name,
+ )
+
+ def registerAuthorizationAdapter(
+ self, authorization_class, for_interface, permission_name
+ ):
"""Register a security checker to test authorisation.
eg. registerAuthorizationAdapter(
TestChecker, IPerson, 'launchpad.View')
"""
self.registerAdapter(
- authorization_class, (for_interface, ), IAuthorization,
- name=permission_name)
+ authorization_class,
+ (for_interface,),
+ IAuthorization,
+ name=permission_name,
+ )
def registerBrowserViewAdapter(self, view_class, for_interface, name):
"""Register a security checker to test authorization.
@@ -1552,13 +1627,13 @@ class FakeAdapterMixin:
eg registerBrowserViewAdapter(TestView, IPerson, '+test-view')
"""
self.registerAdapter(
- view_class, (for_interface, IBrowserRequest), Interface,
- name=name)
+ view_class, (for_interface, IBrowserRequest), Interface, name=name
+ )
def getAdapter(self, for_interfaces, provided_interface, name=None):
return getMultiAdapter(for_interfaces, provided_interface, name=name)
- def registerUtility(self, component, for_interface, name=''):
+ def registerUtility(self, component, for_interface, name=""):
try:
current_commponent = getUtility(for_interface, name=name)
except ComponentLookupError:
@@ -1566,12 +1641,16 @@ class FakeAdapterMixin:
site_manager = getSiteManager()
site_manager.registerUtility(component, for_interface, name)
self.addCleanup(
- site_manager.unregisterUtility, component, for_interface, name)
+ site_manager.unregisterUtility, component, for_interface, name
+ )
if current_commponent is not None:
# Restore the default utility.
self.addCleanup(
- site_manager.registerUtility, current_commponent,
- for_interface, name)
+ site_manager.registerUtility,
+ current_commponent,
+ for_interface,
+ name,
+ )
def clean_up_reactor():
@@ -1579,6 +1658,7 @@ def clean_up_reactor():
# calls around. They need to be updated to use Twisted correctly.
# For the meantime, just blat the reactor.
from twisted.internet import reactor
+
for delayed_call in reactor.getDelayedCalls():
delayed_call.cancel()
diff --git a/lib/lp/testing/_login.py b/lib/lp/testing/_login.py
index a90b3ec..e206eb8 100644
--- a/lib/lp/testing/_login.py
+++ b/lib/lp/testing/_login.py
@@ -2,31 +2,28 @@
# GNU Affero General Public License version 3 (see the file LICENSE).
__all__ = [
- 'admin_logged_in',
- 'anonymous_logged_in',
- 'celebrity_logged_in',
- 'login',
- 'login_admin',
- 'login_as',
- 'login_celebrity',
- 'login_person',
- 'login_team',
- 'logout',
- 'person_logged_in',
- 'run_with_login',
- 'with_anonymous_login',
- 'with_celebrity_logged_in',
- 'with_person_logged_in',
- ]
+ "admin_logged_in",
+ "anonymous_logged_in",
+ "celebrity_logged_in",
+ "login",
+ "login_admin",
+ "login_as",
+ "login_celebrity",
+ "login_person",
+ "login_team",
+ "logout",
+ "person_logged_in",
+ "run_with_login",
+ "with_anonymous_login",
+ "with_celebrity_logged_in",
+ "with_person_logged_in",
+]
from contextlib import contextmanager
from zope.component import getUtility
-from zope.security.management import (
- endInteraction,
- queryInteraction,
- thread_local as zope_security_thread_local,
- )
+from zope.security.management import endInteraction, queryInteraction
+from zope.security.management import thread_local as zope_security_thread_local
from lp.app.interfaces.launchpad import ILaunchpadCelebrities
from lp.services.utils import decorate_with
@@ -34,7 +31,7 @@ from lp.services.webapp.interaction import (
ANONYMOUS,
setupInteractionByEmail,
setupInteractionForPerson,
- )
+)
from lp.services.webapp.interfaces import ILaunchBag
from lp.services.webapp.servers import LaunchpadTestRequest
from lp.services.webapp.vhosts import allvhosts
@@ -50,8 +47,11 @@ def _test_login_impl(participation):
# canonical_url produce a real-looking host name rather than
# 127.0.0.1.
participation = LaunchpadTestRequest(
- environ={'HTTP_HOST': allvhosts.configs['mainsite'].hostname,
- 'SERVER_URL': allvhosts.configs['mainsite'].rooturl})
+ environ={
+ "HTTP_HOST": allvhosts.configs["mainsite"].hostname,
+ "SERVER_URL": allvhosts.configs["mainsite"].rooturl,
+ }
+ )
return participation
@@ -79,7 +79,7 @@ def login_person(person, participation=None):
if person is not None:
# The login will fail even without this check, but this gives us a
# nice error message, which can save time when debugging.
- if getattr(person, 'is_team', None):
+ if getattr(person, "is_team", None):
raise ValueError("Got team, expected person: %r" % (person,))
participation = _test_login_impl(participation)
setupInteractionForPerson(person, participation)
@@ -90,6 +90,7 @@ def login_team(team, participation=None):
"""Login as a member of 'team'."""
# Prevent import loop.
from lp.testing.factory import LaunchpadObjectFactory
+
if not team.is_team:
raise ValueError("Got person, expected team: %r" % (team,))
login(ADMIN_EMAIL)
diff --git a/lib/lp/testing/_webservice.py b/lib/lp/testing/_webservice.py
index c705f68..1ca16cc 100644
--- a/lib/lp/testing/_webservice.py
+++ b/lib/lp/testing/_webservice.py
@@ -2,35 +2,32 @@
# GNU Affero General Public License version 3 (see the file LICENSE).
__all__ = [
- 'launchpadlib_credentials_for',
- 'launchpadlib_for',
- 'oauth_access_token_for',
- ]
+ "launchpadlib_credentials_for",
+ "launchpadlib_for",
+ "oauth_access_token_for",
+]
import shutil
import tempfile
+import six
+import transaction
+import zope.testing.cleanup
from launchpadlib.credentials import (
AccessToken,
AnonymousAccessToken,
Credentials,
- )
+)
from launchpadlib.launchpad import Launchpad
-import six
-import transaction
from zope.component import getUtility
-import zope.testing.cleanup
from lp.registry.interfaces.person import IPersonSet
from lp.services.oauth.interfaces import IOAuthConsumerSet
from lp.services.webapp.interaction import ANONYMOUS
from lp.services.webapp.interfaces import OAuthPermission
from lp.services.webapp.publisher import canonical_url
-from lp.testing._login import (
- login,
- logout,
- )
+from lp.testing._login import login, logout
def api_url(obj):
@@ -65,6 +62,7 @@ def oauth_access_token_for(consumer_name, person, permission, context=None):
# Turn an OAuth context string into the corresponding object.
# Avoid an import loop by importing from launchpad.browser here.
from lp.services.oauth.browser import lookup_oauth_context
+
context = lookup_oauth_context(context)
if isinstance(permission, str):
# Look up a permission by its token string.
@@ -83,8 +81,11 @@ def oauth_access_token_for(consumer_name, person, permission, context=None):
def launchpadlib_credentials_for(
- consumer_name, person, permission=OAuthPermission.WRITE_PRIVATE,
- context=None):
+ consumer_name,
+ person,
+ permission=OAuthPermission.WRITE_PRIVATE,
+ context=None,
+):
"""Create launchpadlib credentials for the given person.
:param consumer_name: An OAuth consumer name.
@@ -102,11 +103,13 @@ def launchpadlib_credentials_for(
# launchpadlib to use.
login(ANONYMOUS)
access_token, access_secret = oauth_access_token_for(
- consumer_name, person, permission, context)
+ consumer_name, person, permission, context
+ )
logout()
launchpadlib_token = AccessToken(access_token.key, access_secret)
- return Credentials(consumer_name=consumer_name,
- access_token=launchpadlib_token)
+ return Credentials(
+ consumer_name=consumer_name, access_token=launchpadlib_token
+ )
def _clean_up_cache(cache):
@@ -115,8 +118,13 @@ def _clean_up_cache(cache):
def launchpadlib_for(
- consumer_name, person=None, permission=OAuthPermission.WRITE_PRIVATE,
- context=None, version="devel", service_root="http://api.launchpad.test/"):
+ consumer_name,
+ person=None,
+ permission=OAuthPermission.WRITE_PRIVATE,
+ context=None,
+ version="devel",
+ service_root="http://api.launchpad.test/",
+):
"""Create a Launchpad object for the given person.
:param consumer_name: An OAuth consumer name.
@@ -138,9 +146,16 @@ def launchpadlib_for(
credentials = Credentials(consumer_name, access_token=token)
else:
credentials = launchpadlib_credentials_for(
- consumer_name, person, permission, context)
+ consumer_name, person, permission, context
+ )
transaction.commit()
- cache = tempfile.mkdtemp(prefix='launchpadlib-cache-')
+ cache = tempfile.mkdtemp(prefix="launchpadlib-cache-")
zope.testing.cleanup.addCleanUp(_clean_up_cache, (cache,))
- return Launchpad(credentials, None, None, service_root=service_root,
- version=version, cache=cache)
+ return Launchpad(
+ credentials,
+ None,
+ None,
+ service_root=service_root,
+ version=version,
+ cache=cache,
+ )
diff --git a/lib/lp/testing/branding.py b/lib/lp/testing/branding.py
index 05bd3a7..f7210b6 100644
--- a/lib/lp/testing/branding.py
+++ b/lib/lp/testing/branding.py
@@ -1,7 +1,7 @@
# Copyright 2009-2010 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
-__all__ = ['set_branding']
+__all__ = ["set_branding"]
import os.path
@@ -22,24 +22,28 @@ def set_branding(browser, icon=True, logo=True, mugshot=True):
"""
# make sure we have relevant-sized files handy
icon_file = os.path.join(
- os.path.dirname(canonical.launchpad.__file__),
- 'images/team.png')
+ os.path.dirname(canonical.launchpad.__file__), "images/team.png"
+ )
logo_file = os.path.join(
- os.path.dirname(canonical.launchpad.__file__),
- 'images/team-logo.png')
+ os.path.dirname(canonical.launchpad.__file__), "images/team-logo.png"
+ )
mugshot_file = os.path.join(
- os.path.dirname(canonical.launchpad.__file__),
- 'images/team-mugshot.png')
+ os.path.dirname(canonical.launchpad.__file__),
+ "images/team-mugshot.png",
+ )
# set each of the branding elements in turn, if requested
if icon:
- browser.getControl(name='field.icon.action').value = ['change']
- browser.getControl(name='field.icon.image').add_file(
- open(icon_file, 'rb'), 'image/png', 'icon.png')
+ browser.getControl(name="field.icon.action").value = ["change"]
+ browser.getControl(name="field.icon.image").add_file(
+ open(icon_file, "rb"), "image/png", "icon.png"
+ )
if logo:
- browser.getControl(name='field.logo.action').value = ['change']
- browser.getControl(name='field.logo.image').add_file(
- open(logo_file, 'rb'), 'image/png', 'logo.png')
+ browser.getControl(name="field.logo.action").value = ["change"]
+ browser.getControl(name="field.logo.image").add_file(
+ open(logo_file, "rb"), "image/png", "logo.png"
+ )
if mugshot:
- browser.getControl(name='field.mugshot.action').value = ['change']
- browser.getControl(name='field.mugshot.image').add_file(
- open(mugshot_file, 'rb'), 'image/png', 'mugshot.png')
+ browser.getControl(name="field.mugshot.action").value = ["change"]
+ browser.getControl(name="field.mugshot.image").add_file(
+ open(mugshot_file, "rb"), "image/png", "mugshot.png"
+ )
diff --git a/lib/lp/testing/breadcrumbs.py b/lib/lp/testing/breadcrumbs.py
index f47121e..c6c5ad5 100644
--- a/lib/lp/testing/breadcrumbs.py
+++ b/lib/lp/testing/breadcrumbs.py
@@ -21,17 +21,19 @@ class BaseBreadcrumbTestCase(TestCaseWithFactory):
"""
crumbs = self.getBreadcrumbsForObject(obj, view_name, rootsite)
self.assertEqual(
- expected,
- [(crumb.text, crumb.url) for crumb in crumbs])
+ expected, [(crumb.text, crumb.url) for crumb in crumbs]
+ )
- def assertBreadcrumbTexts(self, expected, obj, view_name=None,
- rootsite=None):
+ def assertBreadcrumbTexts(
+ self, expected, obj, view_name=None, rootsite=None
+ ):
"""The text of the breadcrumbs for obj match the expected values."""
crumbs = self.getBreadcrumbsForObject(obj, view_name, rootsite)
self.assertEqual(expected, [crumb.text for crumb in crumbs])
- def assertBreadcrumbUrls(self, expected, obj, view_name=None,
- rootsite=None):
+ def assertBreadcrumbUrls(
+ self, expected, obj, view_name=None, rootsite=None
+ ):
"""The urls of the breadcrumbs for obj match the expected values."""
crumbs = self.getBreadcrumbsForObject(obj, view_name, rootsite)
self.assertEqual(expected, [crumb.url for crumb in crumbs])
@@ -50,6 +52,6 @@ class BaseBreadcrumbTestCase(TestCaseWithFactory):
obj, view, request = test_traverse(url)
# Sometimes test_traverse returns the __call__, while the template
# always has access to the instance.
- view = getattr(removeSecurityProxy(view), '__self__', view)
- hier = create_initialized_view(view, '+hierarchy', request=request)
+ view = getattr(removeSecurityProxy(view), "__self__", view)
+ hier = create_initialized_view(view, "+hierarchy", request=request)
return hier.items
diff --git a/lib/lp/testing/browser.py b/lib/lp/testing/browser.py
index ed2f222..6a4a665 100644
--- a/lib/lp/testing/browser.py
+++ b/lib/lp/testing/browser.py
@@ -10,20 +10,18 @@ that's not good enough.
"""
__all__ = [
- 'setUp',
- ]
+ "setUp",
+]
import ssl
-from lazr.uri import URI
import six
+from lazr.uri import URI
from urllib3 import PoolManager
from wsgiproxy.proxies import TransparentProxy
from wsgiproxy.urllib3_client import HttpClient
-from zope.testbrowser.wsgi import (
- AuthorizationMiddleware,
- Browser as _Browser,
- )
+from zope.testbrowser.wsgi import AuthorizationMiddleware
+from zope.testbrowser.wsgi import Browser as _Browser
from lp.testing.layers import TransactionMiddleware
from lp.testing.pages import (
@@ -31,12 +29,11 @@ from lp.testing.pages import (
find_main_content,
find_tag_by_id,
print_feedback_messages,
- )
+)
from lp.testing.systemdocs import PrettyPrinter
class Browser(_Browser):
-
def __init__(self, url=None, wsgi_app=None):
if wsgi_app is None:
# urllib3 is carefully-chosen: both the httplib and requests
@@ -47,19 +44,19 @@ class Browser(_Browser):
# +logout redirecting to https://bazaar.launchpad.test/+logout.
client = HttpClient(pool=PoolManager(10, cert_reqs=ssl.CERT_NONE))
wsgi_app = AuthorizationMiddleware(
- TransactionMiddleware(
- TransparentProxy(client=client)))
+ TransactionMiddleware(TransparentProxy(client=client))
+ )
super().__init__(url=url, wsgi_app=wsgi_app)
@property
def vhost(self):
uri = URI(self.url)
- return '%s://%s' % (uri.scheme, uri.host)
+ return "%s://%s" % (uri.scheme, uri.host)
@property
def rooturl(self):
uri = URI(self.url)
- return '%s://%s:%s' % (uri.scheme, uri.host, uri.port)
+ return "%s://%s:%s" % (uri.scheme, uri.host, uri.port)
@property
def urlpath(self):
@@ -69,11 +66,11 @@ class Browser(_Browser):
def setUp(test):
"""Set up appserver tests."""
- test.globs['Browser'] = Browser
- test.globs['browser'] = Browser()
- test.globs['find_tag_by_id'] = find_tag_by_id
- test.globs['find_main_content'] = find_main_content
- test.globs['print_feedback_messages'] = print_feedback_messages
- test.globs['extract_text'] = extract_text
- test.globs['pretty'] = PrettyPrinter(width=1).pformat
- test.globs['six'] = six
+ test.globs["Browser"] = Browser
+ test.globs["browser"] = Browser()
+ test.globs["find_tag_by_id"] = find_tag_by_id
+ test.globs["find_main_content"] = find_main_content
+ test.globs["print_feedback_messages"] = print_feedback_messages
+ test.globs["extract_text"] = extract_text
+ test.globs["pretty"] = PrettyPrinter(width=1).pformat
+ test.globs["six"] = six
diff --git a/lib/lp/testing/dbuser.py b/lib/lp/testing/dbuser.py
index deb9b14..3441593 100644
--- a/lib/lp/testing/dbuser.py
+++ b/lib/lp/testing/dbuser.py
@@ -4,19 +4,16 @@
"""Provides a context manager to run parts of a test as a different dbuser."""
__all__ = [
- 'dbuser',
- 'lp_dbuser',
- 'switch_dbuser',
- ]
+ "dbuser",
+ "lp_dbuser",
+ "switch_dbuser",
+]
from contextlib import contextmanager
-from storm.database import (
- STATE_CONNECTED,
- STATE_DISCONNECTED,
- )
-from storm.zope.interfaces import IZStorm
import transaction
+from storm.database import STATE_CONNECTED, STATE_DISCONNECTED
+from storm.zope.interfaces import IZStorm
from zope.component import getUtility
from lp.services.config import dbconfig
@@ -47,7 +44,7 @@ def update_store_connections():
# only called by the test suite to kill the existing
# connections so the Store's reconnect with updated
# connection settings.
- store._event.emit('register-transaction')
+ store._event.emit("register-transaction")
connection._raw_connection = None
connection._state = STATE_DISCONNECTED
@@ -73,7 +70,7 @@ def dbuser(temporary_name):
temporary_name is the name of the dbuser that should be in place for the
code in the "with" block.
"""
- old_name = getattr(dbconfig.overrides, 'dbuser', None)
+ old_name = getattr(dbconfig.overrides, "dbuser", None)
switch_dbuser(temporary_name)
yield
switch_dbuser(old_name)
@@ -84,4 +81,4 @@ def lp_dbuser():
Use with the LaunchpadZopelessLayer layer and subclasses.
"""
- return dbuser('launchpad')
+ return dbuser("launchpad")
diff --git a/lib/lp/testing/deprecated.py b/lib/lp/testing/deprecated.py
index 6849332..16b7753 100644
--- a/lib/lp/testing/deprecated.py
+++ b/lib/lp/testing/deprecated.py
@@ -11,26 +11,34 @@ from zope.security.management import (
newInteraction,
queryInteraction,
restoreInteraction,
- )
+)
from lp.services.webapp.interaction import get_current_principal
from lp.services.webapp.servers import LaunchpadTestRequest
class LaunchpadFormHarness:
-
- def __init__(self, context, view_class, form_values=None,
- request_class=LaunchpadTestRequest, request_environ=None):
+ def __init__(
+ self,
+ context,
+ view_class,
+ form_values=None,
+ request_class=LaunchpadTestRequest,
+ request_environ=None,
+ ):
self.context = context
self.view_class = view_class
self.request_class = request_class
self.request_environ = request_environ
self._render(form_values)
- def _render(self, form_values=None, method='GET'):
+ def _render(self, form_values=None, method="GET"):
self.request = self.request_class(
- method=method, form=form_values, PATH_INFO='/',
- environ=self.request_environ)
+ method=method,
+ form=form_values,
+ PATH_INFO="/",
+ environ=self.request_environ,
+ )
if queryInteraction() is not None:
self.request.setPrincipal(get_current_principal())
# Setup a new interaction using self.request, create the view,
@@ -41,10 +49,10 @@ class LaunchpadFormHarness:
self.view.initialize()
restoreInteraction()
- def submit(self, action_name, form_values, method='POST'):
- action_name = '%s.actions.%s' % (self.view.prefix, action_name)
+ def submit(self, action_name, form_values, method="POST"):
+ action_name = "%s.actions.%s" % (self.view.prefix, action_name)
form_values = dict(form_values)
- form_values[action_name] = ''
+ form_values[action_name] = ""
self._render(form_values, method)
def hasErrors(self):
@@ -60,4 +68,4 @@ class LaunchpadFormHarness:
return self.request.response.getStatus() in [302, 303]
def redirectionTarget(self):
- return self.request.response.getHeader('location')
+ return self.request.response.getHeader("location")
diff --git a/lib/lp/testing/factory.py b/lib/lp/testing/factory.py
index a589045..4cdfa06 100644
--- a/lib/lp/testing/factory.py
+++ b/lib/lp/testing/factory.py
@@ -7,67 +7,51 @@ This module should not contain tests (but it should be tested).
"""
__all__ = [
- 'GPGSigningContext',
- 'is_security_proxied_or_harmless',
- 'LaunchpadObjectFactory',
- 'ObjectFactory',
- 'remove_security_proxy_and_shout_at_engineer',
- ]
+ "GPGSigningContext",
+ "is_security_proxied_or_harmless",
+ "LaunchpadObjectFactory",
+ "ObjectFactory",
+ "remove_security_proxy_and_shout_at_engineer",
+]
import base64
-from collections.abc import (
- Mapping,
- Sequence,
- )
-from datetime import (
- datetime,
- timedelta,
- )
+import hashlib
+import os
+import sys
+import uuid
+import warnings
+from collections.abc import Mapping, Sequence
+from datetime import datetime, timedelta
from email.encoders import encode_base64
from email.message import Message as EmailMessage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
-from email.utils import (
- formatdate,
- make_msgid,
- )
+from email.utils import formatdate, make_msgid
from functools import wraps
-import hashlib
from io import BytesIO
from itertools import count
-import os
-import sys
from textwrap import dedent
-import uuid
-import warnings
+import pytz
+import six
from breezy.plugins.builder.recipe import BaseRecipeBranch
from breezy.revision import Revision as BzrRevision
from cryptography.utils import int_to_bytes
from lazr.jobrunner.jobrunner import SuspendJobException
-import pytz
from pytz import UTC
-import six
-from twisted.conch.ssh.common import (
- MP,
- NS,
- )
+from twisted.conch.ssh.common import MP, NS
from twisted.conch.test import keydata
from twisted.python.util import mergeFunctionMetadata
from zope.component import getUtility
from zope.interface.interfaces import ComponentLookupError
-from zope.security.proxy import (
- Proxy,
- ProxyFactory,
- removeSecurityProxy,
- )
+from zope.security.proxy import Proxy, ProxyFactory, removeSecurityProxy
from lp.app.enums import (
- InformationType,
PROPRIETARY_INFORMATION_TYPES,
PUBLIC_INFORMATION_TYPES,
+ InformationType,
ServiceUsage,
- )
+)
from lp.app.interfaces.launchpad import ILaunchpadCelebrities
from lp.archivepublisher.interfaces.publisherconfig import IPublisherConfigSet
from lp.archiveuploader.dscfile import DSCFile
@@ -75,45 +59,36 @@ from lp.blueprints.enums import (
NewSpecificationDefinitionStatus,
SpecificationDefinitionStatus,
SpecificationWorkItemStatus,
- )
+)
from lp.blueprints.interfaces.specification import ISpecificationSet
from lp.blueprints.interfaces.sprint import ISprintSet
from lp.bugs.interfaces.apportjob import IProcessApportBlobJobSource
-from lp.bugs.interfaces.bug import (
- CreateBugParams,
- IBugSet,
- )
+from lp.bugs.interfaces.bug import CreateBugParams, IBugSet
from lp.bugs.interfaces.bugtask import (
BugTaskImportance,
BugTaskStatus,
IBugTaskSet,
- )
-from lp.bugs.interfaces.bugtracker import (
- BugTrackerType,
- IBugTrackerSet,
- )
+)
+from lp.bugs.interfaces.bugtracker import BugTrackerType, IBugTrackerSet
from lp.bugs.interfaces.bugwatch import IBugWatchSet
-from lp.bugs.interfaces.cve import (
- CveStatus,
- ICveSet,
- )
+from lp.bugs.interfaces.cve import CveStatus, ICveSet
from lp.bugs.interfaces.vulnerability import (
IVulnerabilityActivitySet,
IVulnerabilitySet,
VulnerabilityChange,
VulnerabilityStatus,
- )
+)
from lp.bugs.model.bug import FileBugData
from lp.buildmaster.enums import (
BuildBaseImageType,
BuilderResetProtocol,
BuildStatus,
- )
+)
from lp.buildmaster.interfaces.builder import IBuilderSet
from lp.buildmaster.interfaces.processor import (
IProcessorSet,
ProcessorNotFound,
- )
+)
from lp.charms.interfaces.charmbase import ICharmBaseSet
from lp.charms.interfaces.charmrecipe import ICharmRecipeSet
from lp.charms.interfaces.charmrecipebuild import ICharmRecipeBuildSet
@@ -131,7 +106,7 @@ from lp.code.enums import (
RevisionControlSystems,
RevisionStatusArtifactType,
TargetRevisionControlSystems,
- )
+)
from lp.code.errors import UnknownBranchTypeError
from lp.code.interfaces.branch import IBranch
from lp.code.interfaces.branchnamespace import get_branch_namespace
@@ -141,42 +116,34 @@ from lp.code.interfaces.codeimportevent import ICodeImportEventSet
from lp.code.interfaces.codeimportmachine import ICodeImportMachineSet
from lp.code.interfaces.codeimportresult import ICodeImportResultSet
from lp.code.interfaces.gitnamespace import get_git_namespace
-from lp.code.interfaces.gitref import (
- IGitRef,
- IGitRefRemoteSet,
- )
+from lp.code.interfaces.gitref import IGitRef, IGitRefRemoteSet
from lp.code.interfaces.gitrepository import IGitRepository
from lp.code.interfaces.linkedbranch import ICanHasLinkedBranch
from lp.code.interfaces.revision import IRevisionSet
from lp.code.interfaces.revisionstatus import (
IRevisionStatusArtifactSet,
IRevisionStatusReportSet,
- )
+)
from lp.code.interfaces.sourcepackagerecipe import (
- ISourcePackageRecipeSource,
MINIMAL_RECIPE_TEXT_BZR,
MINIMAL_RECIPE_TEXT_GIT,
- )
+ ISourcePackageRecipeSource,
+)
from lp.code.interfaces.sourcepackagerecipebuild import (
ISourcePackageRecipeBuildSource,
- )
-from lp.code.model.diff import (
- Diff,
- PreviewDiff,
- )
+)
+from lp.code.model.diff import Diff, PreviewDiff
from lp.code.tests.helpers import GitHostingFixture
from lp.oci.interfaces.ocipushrule import IOCIPushRuleSet
from lp.oci.interfaces.ocirecipe import IOCIRecipeSet
from lp.oci.interfaces.ocirecipebuild import IOCIRecipeBuildSet
-from lp.oci.interfaces.ociregistrycredentials import (
- IOCIRegistryCredentialsSet,
- )
+from lp.oci.interfaces.ociregistrycredentials import IOCIRegistryCredentialsSet
from lp.oci.model.ocirecipe import OCIRecipeArch
from lp.oci.model.ocirecipebuild import OCIFile
from lp.oci.model.ocirecipebuildjob import (
OCIRecipeBuildJob,
OCIRecipeBuildJobType,
- )
+)
from lp.registry.enums import (
BranchSharingPolicy,
BugSharingPolicy,
@@ -184,63 +151,49 @@ from lp.registry.enums import (
DistroSeriesDifferenceType,
SpecificationSharingPolicy,
TeamMembershipPolicy,
- )
+)
from lp.registry.interfaces.accesspolicy import (
IAccessArtifactGrantSource,
IAccessArtifactSource,
IAccessPolicyArtifactSource,
IAccessPolicyGrantSource,
IAccessPolicySource,
- )
-from lp.registry.interfaces.distribution import (
- IDistribution,
- IDistributionSet,
- )
+)
+from lp.registry.interfaces.distribution import IDistribution, IDistributionSet
from lp.registry.interfaces.distributionmirror import (
MirrorContent,
MirrorSpeed,
- )
+)
from lp.registry.interfaces.distributionsourcepackage import (
IDistributionSourcePackage,
- )
+)
from lp.registry.interfaces.distroseries import IDistroSeries
from lp.registry.interfaces.distroseriesdifference import (
IDistroSeriesDifferenceSource,
- )
+)
from lp.registry.interfaces.distroseriesdifferencecomment import (
IDistroSeriesDifferenceCommentSource,
- )
+)
from lp.registry.interfaces.distroseriesparent import IDistroSeriesParentSet
from lp.registry.interfaces.gpg import IGPGKeySet
from lp.registry.interfaces.mailinglist import (
IMailingListSet,
MailingListStatus,
- )
+)
from lp.registry.interfaces.mailinglistsubscription import (
MailingListAutoSubscribePolicy,
- )
+)
from lp.registry.interfaces.ociproject import IOCIProjectSet
from lp.registry.interfaces.ociprojectname import IOCIProjectNameSet
-from lp.registry.interfaces.packaging import (
- IPackagingUtil,
- PackagingType,
- )
+from lp.registry.interfaces.packaging import IPackagingUtil, PackagingType
from lp.registry.interfaces.person import (
IPerson,
IPersonSet,
PersonCreationRationale,
- )
+)
from lp.registry.interfaces.pocket import PackagePublishingPocket
-from lp.registry.interfaces.poll import (
- IPollSet,
- PollAlgorithm,
- PollSecrecy,
- )
-from lp.registry.interfaces.product import (
- IProduct,
- IProductSet,
- License,
- )
+from lp.registry.interfaces.poll import IPollSet, PollAlgorithm, PollSecrecy
+from lp.registry.interfaces.product import IProduct, IProductSet, License
from lp.registry.interfaces.productseries import IProductSeries
from lp.registry.interfaces.projectgroup import IProjectGroupSet
from lp.registry.interfaces.series import SeriesStatus
@@ -249,7 +202,7 @@ from lp.registry.interfaces.sourcepackage import (
SourcePackageFileType,
SourcePackageType,
SourcePackageUrgency,
- )
+)
from lp.registry.interfaces.sourcepackagename import ISourcePackageNameSet
from lp.registry.interfaces.ssh import ISSHKeySet
from lp.registry.model.commercialsubscription import CommercialSubscription
@@ -260,53 +213,38 @@ from lp.services.auth.interfaces import IAccessTokenSet
from lp.services.auth.utils import create_access_token_secret
from lp.services.compat import message_as_bytes
from lp.services.config import config
-from lp.services.database.constants import (
- DEFAULT,
- UTC_NOW,
- )
+from lp.services.database.constants import DEFAULT, UTC_NOW
from lp.services.database.interfaces import (
IMasterStore,
IStore,
IStoreSelector,
- )
+)
from lp.services.database.policy import PrimaryDatabasePolicy
from lp.services.database.sqlbase import flush_database_updates
-from lp.services.gpg.interfaces import (
- GPGKeyAlgorithm,
- IGPGHandler,
- )
+from lp.services.gpg.interfaces import GPGKeyAlgorithm, IGPGHandler
from lp.services.identity.interfaces.account import (
AccountCreationRationale,
AccountStatus,
IAccountSet,
- )
+)
from lp.services.identity.interfaces.emailaddress import (
EmailAddressStatus,
IEmailAddressSet,
- )
+)
from lp.services.identity.model.account import Account
from lp.services.librarian.interfaces import ILibraryFileAliasSet
-from lp.services.librarian.model import (
- LibraryFileAlias,
- LibraryFileContent,
- )
+from lp.services.librarian.model import LibraryFileAlias, LibraryFileContent
from lp.services.mail.signedmessage import SignedMessage
-from lp.services.messages.model.message import (
- Message,
- MessageChunk,
- )
+from lp.services.messages.model.message import Message, MessageChunk
from lp.services.oauth.interfaces import IOAuthConsumerSet
from lp.services.openid.model.openididentifier import OpenIdIdentifier
-from lp.services.propertycache import (
- clear_property_cache,
- get_property_cache,
- )
+from lp.services.propertycache import clear_property_cache, get_property_cache
from lp.services.signing.enums import SigningKeyType
from lp.services.signing.interfaces.signingkey import IArchiveSigningKeySet
from lp.services.signing.model.signingkey import SigningKey
from lp.services.temporaryblobstorage.interfaces import (
ITemporaryStorageManager,
- )
+)
from lp.services.temporaryblobstorage.model import TemporaryBlobStorage
from lp.services.utils import AutoDecorateMetaClass
from lp.services.webapp.interfaces import OAuthPermission
@@ -333,19 +271,13 @@ from lp.soyuz.enums import (
PackagePublishingStatus,
PackageUploadCustomFormat,
PackageUploadStatus,
- )
-from lp.soyuz.interfaces.archive import (
- default_name_by_purpose,
- IArchiveSet,
- )
+)
+from lp.soyuz.interfaces.archive import IArchiveSet, default_name_by_purpose
from lp.soyuz.interfaces.archivefile import IArchiveFileSet
from lp.soyuz.interfaces.archivepermission import IArchivePermissionSet
from lp.soyuz.interfaces.binarypackagebuild import IBinaryPackageBuildSet
from lp.soyuz.interfaces.binarypackagename import IBinaryPackageNameSet
-from lp.soyuz.interfaces.component import (
- IComponent,
- IComponentSet,
- )
+from lp.soyuz.interfaces.component import IComponent, IComponentSet
from lp.soyuz.interfaces.livefs import ILiveFSSet
from lp.soyuz.interfaces.livefsbuild import ILiveFSBuildSet
from lp.soyuz.interfaces.packagecopyjob import IPlainPackageCopyJobSource
@@ -356,14 +288,14 @@ from lp.soyuz.interfaces.section import ISectionSet
from lp.soyuz.model.component import ComponentSelection
from lp.soyuz.model.distributionsourcepackagecache import (
DistributionSourcePackageCache,
- )
+)
from lp.soyuz.model.distroarchseriesfilter import DistroArchSeriesFilter
from lp.soyuz.model.files import BinaryPackageFile
from lp.soyuz.model.livefsbuild import LiveFSFile
from lp.soyuz.model.packagediff import PackageDiff
from lp.testing import (
- admin_logged_in,
ANONYMOUS,
+ admin_logged_in,
celebrity_logged_in,
launchpadlib_for,
login,
@@ -373,39 +305,33 @@ from lp.testing import (
run_with_login,
time_counter,
with_celebrity_logged_in,
- )
+)
from lp.testing.dbuser import dbuser
-from lp.translations.enums import (
- LanguagePackType,
- RosettaImportStatus,
- )
+from lp.translations.enums import LanguagePackType, RosettaImportStatus
from lp.translations.interfaces.languagepack import ILanguagePackSet
from lp.translations.interfaces.potemplate import IPOTemplateSet
from lp.translations.interfaces.side import TranslationSide
from lp.translations.interfaces.translationfileformat import (
TranslationFileFormat,
- )
+)
from lp.translations.interfaces.translationgroup import ITranslationGroupSet
from lp.translations.interfaces.translationimportqueue import (
ITranslationImportQueue,
- )
+)
from lp.translations.interfaces.translationmessage import (
RosettaTranslationOrigin,
- )
+)
from lp.translations.interfaces.translationsperson import ITranslationsPerson
from lp.translations.interfaces.translationtemplatesbuild import (
ITranslationTemplatesBuildSource,
- )
+)
from lp.translations.interfaces.translator import ITranslatorSet
from lp.translations.model.translationtemplateitem import (
TranslationTemplateItem,
- )
-from lp.translations.utilities.sanitize import (
- sanitize_translations_from_webui,
- )
-
+)
+from lp.translations.utilities.sanitize import sanitize_translations_from_webui
-SPACE = ' '
+SPACE = " "
def default_master_store(func):
@@ -430,6 +356,7 @@ def default_master_store(func):
return func(*args, **kw)
finally:
store_selector.pop()
+
return mergeFunctionMetadata(func, with_default_master_store)
@@ -442,7 +369,7 @@ _DEFAULT = object()
class GPGSigningContext:
"""A helper object to hold the key, password and mode."""
- def __init__(self, key, password='', mode=None):
+ def __init__(self, key, password="", mode=None):
self.key = key
self.password = password
self.mode = mode
@@ -454,12 +381,12 @@ class ObjectFactory(metaclass=AutoDecorateMetaClass):
# This allocates process-wide unique integers. We count on Python doing
# only cooperative threading to make this safe across threads.
- __decorators = (default_master_store, )
+ __decorators = (default_master_store,)
_unique_int_counter = count(100000)
def getUniqueEmailAddress(self):
- return "%s@xxxxxxxxxxx" % self.getUniqueUnicode('email')
+ return "%s@xxxxxxxxxxx" % self.getUniqueUnicode("email")
def getUniqueInteger(self):
"""Return an integer unique to this factory instance.
@@ -476,7 +403,7 @@ class ObjectFactory(metaclass=AutoDecorateMetaClass):
don't care.
:return: A hexadecimal string, with 'a'-'f' in lower case.
"""
- hex_number = '%x' % self.getUniqueInteger()
+ hex_number = "%x" % self.getUniqueInteger()
if digits is not None:
hex_number = hex_number.zfill(digits)
return hex_number
@@ -502,17 +429,17 @@ class ObjectFactory(metaclass=AutoDecorateMetaClass):
# names.
source = (
os.path.basename(source_filename)
- .replace('_', '-')
- .replace('.', '-'))
- if source.startswith(
- '<doctest '):
+ .replace("_", "-")
+ .replace(".", "-")
+ )
+ if source.startswith("<doctest "):
# Like '-<doctest xx-build-summary-rst[10]>'.
- source = (source
- .replace('<doctest ', '')
- .replace('[', '')
- .replace(']>', ''))
- prefix = 'unique-from-%s-line%d' % (
- source, frame.f_lineno)
+ source = (
+ source.replace("<doctest ", "")
+ .replace("[", "")
+ .replace("]>", "")
+ )
+ prefix = "unique-from-%s-line%d" % (source, frame.f_lineno)
string = "%s-%s" % (prefix, self.getUniqueInteger())
return string
@@ -525,10 +452,10 @@ class ObjectFactory(metaclass=AutoDecorateMetaClass):
def getUniqueURL(self, scheme=None, host=None):
"""Return a URL unique to this run of the test case."""
if scheme is None:
- scheme = 'http'
+ scheme = "http"
if host is None:
- host = "%s.example.com" % self.getUniqueUnicode('domain')
- return '%s://%s/%s' % (scheme, host, self.getUniqueUnicode('path'))
+ host = "%s.example.com" % self.getUniqueUnicode("domain")
+ return "%s://%s/%s" % (scheme, host, self.getUniqueUnicode("path"))
def getUniqueDate(self):
"""Return a unique date since January 1 2009.
@@ -566,7 +493,7 @@ class LaunchpadObjectFactory(ObjectFactory):
for any other required objects.
"""
- __decorators = (check_security_proxy, )
+ __decorators = (check_security_proxy,)
def loginAsAnyone(self, participation=None):
"""Log in as an arbitrary person.
@@ -579,43 +506,56 @@ class LaunchpadObjectFactory(ObjectFactory):
login_as(person, participation)
return person
- @with_celebrity_logged_in('admin')
+ @with_celebrity_logged_in("admin")
def makeAdministrator(self, name=None, email=None):
return self.makePerson(
- name=name, email=email,
- member_of=[getUtility(ILaunchpadCelebrities).admin])
+ name=name,
+ email=email,
+ member_of=[getUtility(ILaunchpadCelebrities).admin],
+ )
- @with_celebrity_logged_in('admin')
- def makeRegistryExpert(self, name=None, email='expert@xxxxxxxxxxx'):
+ @with_celebrity_logged_in("admin")
+ def makeRegistryExpert(self, name=None, email="expert@xxxxxxxxxxx"):
return self.makePerson(
- name=name, email=email,
- member_of=[getUtility(ILaunchpadCelebrities).registry_experts])
+ name=name,
+ email=email,
+ member_of=[getUtility(ILaunchpadCelebrities).registry_experts],
+ )
- @with_celebrity_logged_in('admin')
+ @with_celebrity_logged_in("admin")
def makeCommercialAdmin(self, name=None, email=None):
return self.makePerson(
- name=name, email=email,
- member_of=[getUtility(ILaunchpadCelebrities).commercial_admin])
+ name=name,
+ email=email,
+ member_of=[getUtility(ILaunchpadCelebrities).commercial_admin],
+ )
- def makeCopyArchiveLocation(self, distribution=None, owner=None,
- name=None, enabled=True):
+ def makeCopyArchiveLocation(
+ self, distribution=None, owner=None, name=None, enabled=True
+ ):
"""Create and return a new arbitrary location for copy packages."""
- copy_archive = self.makeArchive(distribution, owner, name,
- ArchivePurpose.COPY, enabled)
+ copy_archive = self.makeArchive(
+ distribution, owner, name, ArchivePurpose.COPY, enabled
+ )
distribution = copy_archive.distribution
distroseries = distribution.currentseries
pocket = PackagePublishingPocket.RELEASE
- location = PackageLocation(copy_archive, distribution, distroseries,
- pocket)
+ location = PackageLocation(
+ copy_archive, distribution, distroseries, pocket
+ )
return ProxyFactory(location)
- def makeAccount(self, displayname=None, status=AccountStatus.ACTIVE,
- rationale=AccountCreationRationale.UNKNOWN):
+ def makeAccount(
+ self,
+ displayname=None,
+ status=AccountStatus.ACTIVE,
+ rationale=AccountCreationRationale.UNKNOWN,
+ ):
"""Create and return a new Account."""
if displayname is None:
- displayname = self.getUniqueString('displayname')
+ displayname = self.getUniqueString("displayname")
account = getUtility(IAccountSet).new(rationale, displayname)
removeSecurityProxy(account).status = status
self.makeOpenIdIdentifier(account)
@@ -635,12 +575,13 @@ class LaunchpadObjectFactory(ObjectFactory):
# production environments so access to execute this stored
# procedure cannot be used to compromise accounts.
IMasterStore(OpenIdIdentifier).execute(
- "SELECT add_test_openid_identifier(%s)", (account.id, ))
+ "SELECT add_test_openid_identifier(%s)", (account.id,)
+ )
def makeGPGKey(self, owner):
"""Give 'owner' a crappy GPG key for the purposes of testing."""
key_id = self.getUniqueHexString(digits=8).upper()
- fingerprint = key_id + 'A' * 32
+ fingerprint = key_id + "A" * 32
keyset = getUtility(IGPGKeySet)
key = keyset.new(
owner.id,
@@ -649,14 +590,26 @@ class LaunchpadObjectFactory(ObjectFactory):
keysize=self.getUniqueInteger(),
algorithm=GPGKeyAlgorithm.R,
active=True,
- can_encrypt=False)
+ can_encrypt=False,
+ )
return key
def makePerson(
- self, email=None, name=None, displayname=None, account_status=None,
- email_address_status=None, hide_email_addresses=False,
- time_zone=None, latitude=None, longitude=None, description=None,
- selfgenerated_bugnotifications=False, member_of=(), karma=None):
+ self,
+ email=None,
+ name=None,
+ displayname=None,
+ account_status=None,
+ email_address_status=None,
+ hide_email_addresses=False,
+ time_zone=None,
+ latitude=None,
+ longitude=None,
+ description=None,
+ selfgenerated_bugnotifications=False,
+ member_of=(),
+ karma=None,
+ ):
"""Create and return a new, arbitrary Person.
:param email: The email address for the new person.
@@ -672,32 +625,41 @@ class LaunchpadObjectFactory(ObjectFactory):
:param selfgenerated_bugnotifications: Receive own bugmail.
"""
if name is None:
- name = self.getUniqueString('person-name')
+ name = self.getUniqueString("person-name")
if account_status == AccountStatus.PLACEHOLDER:
# Placeholder people are pretty special, so just create and
# bail out.
- openid = self.getUniqueUnicode('%s-openid' % name)
+ openid = self.getUniqueUnicode("%s-openid" % name)
person = getUtility(IPersonSet).createPlaceholderPerson(
- openid, name)
+ openid, name
+ )
return person
# By default, make the email address preferred.
if email is None:
email = self.getUniqueEmailAddress()
- if (email_address_status is None
- or email_address_status == EmailAddressStatus.VALIDATED):
+ if (
+ email_address_status is None
+ or email_address_status == EmailAddressStatus.VALIDATED
+ ):
email_address_status = EmailAddressStatus.PREFERRED
if account_status == AccountStatus.NOACCOUNT:
email_address_status = EmailAddressStatus.NEW
person, email = getUtility(IPersonSet).createPersonAndEmail(
- email, rationale=PersonCreationRationale.UNKNOWN, name=name,
+ email,
+ rationale=PersonCreationRationale.UNKNOWN,
+ name=name,
displayname=displayname,
- hide_email_addresses=hide_email_addresses)
+ hide_email_addresses=hide_email_addresses,
+ )
naked_person = removeSecurityProxy(person)
if description is not None:
naked_person.description = description
- if (time_zone is not None or latitude is not None or
- longitude is not None):
+ if (
+ time_zone is not None
+ or latitude is not None
+ or longitude is not None
+ ):
naked_person.setLocation(latitude, longitude, time_zone, person)
# Make sure the non-security-proxied object is not returned.
@@ -711,20 +673,22 @@ class LaunchpadObjectFactory(ObjectFactory):
# To make the person someone valid in Launchpad, validate the
# email.
if email_address_status == EmailAddressStatus.PREFERRED:
- account = IMasterStore(Account).get(
- Account, person.accountID)
+ account = IMasterStore(Account).get(Account, person.accountID)
account.status = AccountStatus.ACTIVE
person.setPreferredEmail(email)
removeSecurityProxy(email).status = email_address_status
once_active = (
- AccountStatus.DEACTIVATED, AccountStatus.SUSPENDED,
- AccountStatus.DECEASED)
+ AccountStatus.DEACTIVATED,
+ AccountStatus.SUSPENDED,
+ AccountStatus.DECEASED,
+ )
if account_status:
if account_status in once_active:
- removeSecurityProxy(person.account).status = (
- AccountStatus.ACTIVE)
+ removeSecurityProxy(
+ person.account
+ ).status = AccountStatus.ACTIVE
removeSecurityProxy(person.account).status = account_status
self.makeOpenIdIdentifier(person.account)
@@ -733,15 +697,19 @@ class LaunchpadObjectFactory(ObjectFactory):
team.addMember(person, team.teamowner)
if karma is not None:
- with dbuser('karma'):
+ with dbuser("karma"):
# Give the user karma to make the user non-probationary.
KarmaTotalCache(person=person, karma_total=karma)
# Ensure updated ValidPersonCache
flush_database_updates()
return person
- def makePersonByName(self, first_name, set_preferred_email=True,
- use_default_autosubscribe_policy=False):
+ def makePersonByName(
+ self,
+ first_name,
+ set_preferred_email=True,
+ use_default_autosubscribe_policy=False,
+ ):
"""Create a new person with the given first name.
The person will be given two email addresses, with the 'long form'
@@ -767,15 +735,17 @@ class LaunchpadObjectFactory(ObjectFactory):
:rtype: `IPerson`
"""
variable_name = first_name.lower()
- full_name = first_name + ' Person'
+ full_name = first_name + " Person"
# E.g. firstname.person@xxxxxxxxxxx will be an alternative address.
- preferred_address = variable_name + '.person@xxxxxxxxxxx'
+ preferred_address = variable_name + ".person@xxxxxxxxxxx"
# E.g. aperson@xxxxxxxxxxx will be the preferred address.
- alternative_address = variable_name[0] + 'person@xxxxxxxxxxx'
+ alternative_address = variable_name[0] + "person@xxxxxxxxxxx"
person, email = getUtility(IPersonSet).createPersonAndEmail(
preferred_address,
PersonCreationRationale.OWNER_CREATED_LAUNCHPAD,
- name=variable_name, displayname=full_name)
+ name=variable_name,
+ displayname=full_name,
+ )
if set_preferred_email:
# setPreferredEmail no longer activates the account
# automatically.
@@ -788,10 +758,12 @@ class LaunchpadObjectFactory(ObjectFactory):
# over subscriptions in the doctests.
with person_logged_in(person):
person.mailing_list_auto_subscribe_policy = (
- MailingListAutoSubscribePolicy.NEVER)
+ MailingListAutoSubscribePolicy.NEVER
+ )
account = IMasterStore(Account).get(Account, person.accountID)
getUtility(IEmailAddressSet).new(
- alternative_address, person, EmailAddressStatus.VALIDATED)
+ alternative_address, person, EmailAddressStatus.VALIDATED
+ )
return person
def makeEmail(self, address, person, email_status=None):
@@ -810,13 +782,21 @@ class LaunchpadObjectFactory(ObjectFactory):
"""
if email_status is None:
email_status = EmailAddressStatus.VALIDATED
- return getUtility(IEmailAddressSet).new(
- address, person, email_status)
-
- def makeTeam(self, owner=None, displayname=None, email=None, name=None,
- description=None, icon=None, logo=None,
- membership_policy=TeamMembershipPolicy.OPEN,
- visibility=None, members=None):
+ return getUtility(IEmailAddressSet).new(address, person, email_status)
+
+ def makeTeam(
+ self,
+ owner=None,
+ displayname=None,
+ email=None,
+ name=None,
+ description=None,
+ icon=None,
+ logo=None,
+ membership_policy=TeamMembershipPolicy.OPEN,
+ visibility=None,
+ members=None,
+ ):
"""Create and return a new, arbitrary Team.
:param owner: The person or person name to use as the team's owner.
@@ -847,13 +827,18 @@ class LaunchpadObjectFactory(ObjectFactory):
else:
pass
if name is None:
- name = self.getUniqueString('team-name')
+ name = self.getUniqueString("team-name")
if displayname is None:
displayname = SPACE.join(
- word.capitalize() for word in name.split('-'))
+ word.capitalize() for word in name.split("-")
+ )
team = getUtility(IPersonSet).newTeam(
- owner, name, displayname, description,
- membership_policy=membership_policy)
+ owner,
+ name,
+ displayname,
+ description,
+ membership_policy=membership_policy,
+ )
naked_team = removeSecurityProxy(team)
if visibility is not None:
# Visibility is normally restricted to launchpad.Commercial, so
@@ -862,7 +847,8 @@ class LaunchpadObjectFactory(ObjectFactory):
naked_team._ensurePolicies()
if email is not None:
removeSecurityProxy(team).setContactAddress(
- getUtility(IEmailAddressSet).new(email, team))
+ getUtility(IEmailAddressSet).new(email, team)
+ )
if icon is not None:
naked_team.icon = icon
if logo is not None:
@@ -872,18 +858,28 @@ class LaunchpadObjectFactory(ObjectFactory):
naked_team.addMember(member, owner)
return team
- def makePoll(self, team, name, title, proposition,
- poll_type=PollAlgorithm.SIMPLE):
+ def makePoll(
+ self, team, name, title, proposition, poll_type=PollAlgorithm.SIMPLE
+ ):
"""Create a new poll which starts tomorrow and lasts for a week."""
dateopens = datetime.now(pytz.UTC) + timedelta(days=1)
datecloses = dateopens + timedelta(days=7)
return getUtility(IPollSet).new(
- team, name, title, proposition, dateopens, datecloses,
- PollSecrecy.SECRET, allowspoilt=True,
- poll_type=poll_type, check_permissions=False)
+ team,
+ name,
+ title,
+ proposition,
+ dateopens,
+ datecloses,
+ PollSecrecy.SECRET,
+ allowspoilt=True,
+ poll_type=poll_type,
+ check_permissions=False,
+ )
- def makeTranslationGroup(self, owner=None, name=None, title=None,
- summary=None, url=None):
+ def makeTranslationGroup(
+ self, owner=None, name=None, title=None, summary=None, url=None
+ ):
"""Create a new, arbitrary `TranslationGroup`."""
if owner is None:
owner = self.makePerson()
@@ -894,20 +890,29 @@ class LaunchpadObjectFactory(ObjectFactory):
if summary is None:
summary = self.getUniqueString("summary")
return getUtility(ITranslationGroupSet).new(
- name, title, summary, url, owner)
+ name, title, summary, url, owner
+ )
- def makeTranslator(self, language_code=None, group=None, person=None,
- license=True, language=None):
+ def makeTranslator(
+ self,
+ language_code=None,
+ group=None,
+ person=None,
+ license=True,
+ language=None,
+ ):
"""Create a new, arbitrary `Translator`."""
- assert language_code is None or language is None, (
- "Please specify only one of language_code and language.")
+ assert (
+ language_code is None or language is None
+ ), "Please specify only one of language_code and language."
if language_code is None:
if language is None:
language = self.makeLanguage()
language_code = language.code
else:
language = getUtility(ILanguageSet).getLanguageByCode(
- language_code)
+ language_code
+ )
if language is None:
language = self.makeLanguage(language_code=language_code)
@@ -920,11 +925,22 @@ class LaunchpadObjectFactory(ObjectFactory):
insecure_tx_person.translations_relicensing_agreement = license
return getUtility(ITranslatorSet).new(group, language, person)
- def makeMilestone(self, product=None, distribution=None,
- productseries=None, name=None, active=True,
- dateexpected=None, distroseries=None):
- if (product is None and distribution is None and productseries is None
- and distroseries is None):
+ def makeMilestone(
+ self,
+ product=None,
+ distribution=None,
+ productseries=None,
+ name=None,
+ active=True,
+ dateexpected=None,
+ distroseries=None,
+ ):
+ if (
+ product is None
+ and distribution is None
+ and productseries is None
+ and distroseries is None
+ ):
product = self.makeProduct()
if distribution is None and distroseries is None:
if productseries is not None:
@@ -938,14 +954,27 @@ class LaunchpadObjectFactory(ObjectFactory):
if name is None:
name = self.getUniqueString()
return ProxyFactory(
- Milestone(product=product, distribution=distribution,
- productseries=productseries, distroseries=distroseries,
- name=name, active=active, dateexpected=dateexpected))
-
- def makeProcessor(self, name=None, title=None, description=None,
- restricted=False, build_by_default=True,
- supports_virtualized=False,
- supports_nonvirtualized=True):
+ Milestone(
+ product=product,
+ distribution=distribution,
+ productseries=productseries,
+ distroseries=distroseries,
+ name=name,
+ active=active,
+ dateexpected=dateexpected,
+ )
+ )
+
+ def makeProcessor(
+ self,
+ name=None,
+ title=None,
+ description=None,
+ restricted=False,
+ build_by_default=True,
+ supports_virtualized=False,
+ supports_nonvirtualized=True,
+ ):
"""Create a new processor.
:param name: Name of the processor
@@ -961,81 +990,118 @@ class LaunchpadObjectFactory(ObjectFactory):
if description is None:
description = "The %s processor and compatible processors" % name
return getUtility(IProcessorSet).new(
- name, title, description, restricted=restricted,
+ name,
+ title,
+ description,
+ restricted=restricted,
build_by_default=build_by_default,
supports_virtualized=supports_virtualized,
- supports_nonvirtualized=supports_nonvirtualized)
+ supports_nonvirtualized=supports_nonvirtualized,
+ )
- def makeProductRelease(self, milestone=None, product=None,
- productseries=None):
+ def makeProductRelease(
+ self, milestone=None, product=None, productseries=None
+ ):
if milestone is None:
- milestone = self.makeMilestone(product=product,
- productseries=productseries)
+ milestone = self.makeMilestone(
+ product=product, productseries=productseries
+ )
with person_logged_in(milestone.productseries.product.owner):
release = milestone.createProductRelease(
- milestone.product.owner, datetime.now(pytz.UTC))
+ milestone.product.owner, datetime.now(pytz.UTC)
+ )
return release
- def makeProductReleaseFile(self, signed=True,
- product=None, productseries=None,
- milestone=None,
- release=None,
- description="test file",
- filename='test.txt'):
+ def makeProductReleaseFile(
+ self,
+ signed=True,
+ product=None,
+ productseries=None,
+ milestone=None,
+ release=None,
+ description="test file",
+ filename="test.txt",
+ ):
signature_filename = None
signature_content = None
if signed:
- signature_filename = '%s.asc' % filename
- signature_content = b'123'
+ signature_filename = "%s.asc" % filename
+ signature_content = b"123"
if release is None:
- release = self.makeProductRelease(product=product,
- productseries=productseries,
- milestone=milestone)
+ release = self.makeProductRelease(
+ product=product,
+ productseries=productseries,
+ milestone=milestone,
+ )
with person_logged_in(release.milestone.product.owner):
release_file = release.addReleaseFile(
- filename, b'test', 'text/plain',
+ filename,
+ b"test",
+ "text/plain",
uploader=release.milestone.product.owner,
signature_filename=signature_filename,
signature_content=signature_content,
- description=description)
+ description=description,
+ )
IStore(release).flush()
return release_file
def makeProduct(
- self, name=None, projectgroup=None, displayname=None,
- licenses=None, owner=None, registrant=None,
- title=None, summary=None, official_malone=None,
- translations_usage=None, bug_supervisor=None, driver=None, icon=None,
- bug_sharing_policy=None, branch_sharing_policy=None,
- specification_sharing_policy=None, information_type=None,
- answers_usage=None, vcs=None):
+ self,
+ name=None,
+ projectgroup=None,
+ displayname=None,
+ licenses=None,
+ owner=None,
+ registrant=None,
+ title=None,
+ summary=None,
+ official_malone=None,
+ translations_usage=None,
+ bug_supervisor=None,
+ driver=None,
+ icon=None,
+ bug_sharing_policy=None,
+ branch_sharing_policy=None,
+ specification_sharing_policy=None,
+ information_type=None,
+ answers_usage=None,
+ vcs=None,
+ ):
"""Create and return a new, arbitrary Product."""
if owner is None:
owner = self.makePerson()
if name is None:
- name = self.getUniqueString('product-name')
+ name = self.getUniqueString("product-name")
if displayname is None:
if name is None:
- displayname = self.getUniqueString('displayname')
+ displayname = self.getUniqueString("displayname")
else:
displayname = name.capitalize()
if licenses is None:
- if (information_type in PROPRIETARY_INFORMATION_TYPES or
- (bug_sharing_policy is not None and
- bug_sharing_policy != BugSharingPolicy.PUBLIC) or
- (branch_sharing_policy is not None and
- branch_sharing_policy != BranchSharingPolicy.PUBLIC) or
- (specification_sharing_policy is not None and
- specification_sharing_policy !=
- SpecificationSharingPolicy.PUBLIC)
- ):
+ if (
+ information_type in PROPRIETARY_INFORMATION_TYPES
+ or (
+ bug_sharing_policy is not None
+ and bug_sharing_policy != BugSharingPolicy.PUBLIC
+ )
+ or (
+ branch_sharing_policy is not None
+ and branch_sharing_policy != BranchSharingPolicy.PUBLIC
+ )
+ or (
+ specification_sharing_policy is not None
+ and specification_sharing_policy
+ != SpecificationSharingPolicy.PUBLIC
+ )
+ ):
licenses = [License.OTHER_PROPRIETARY]
else:
licenses = [License.GNU_GPL_V2]
if title is None:
- title = self.getUniqueString('title')
+ title = self.getUniqueString("title")
if summary is None:
- summary = self.getUniqueString('summary')
+ summary = self.getUniqueString("summary")
admins = getUtility(ILaunchpadCelebrities).admin
with person_logged_in(admins.teamowner):
product = getUtility(IProductSet).createProduct(
@@ -1044,13 +1110,14 @@ class LaunchpadObjectFactory(ObjectFactory):
displayname,
title,
summary,
- self.getUniqueString('description'),
+ self.getUniqueString("description"),
licenses=licenses,
projectgroup=projectgroup,
registrant=registrant,
icon=icon,
information_type=information_type,
- vcs=vcs)
+ vcs=vcs,
+ )
naked_product = removeSecurityProxy(product)
if official_malone is not None:
naked_product.official_malone = official_malone
@@ -1068,11 +1135,19 @@ class LaunchpadObjectFactory(ObjectFactory):
naked_product.setBugSharingPolicy(bug_sharing_policy)
if specification_sharing_policy:
naked_product.setSpecificationSharingPolicy(
- specification_sharing_policy)
+ specification_sharing_policy
+ )
return product
- def makeProductSeries(self, product=None, name=None, owner=None,
- summary=None, date_created=None, branch=None):
+ def makeProductSeries(
+ self,
+ product=None,
+ name=None,
+ owner=None,
+ summary=None,
+ date_created=None,
+ branch=None,
+ ):
"""Create a new, arbitrary ProductSeries.
:param branch: If supplied, the branch to set as
@@ -1096,27 +1171,36 @@ class LaunchpadObjectFactory(ObjectFactory):
# so we remove the security proxy before creating the series.
naked_product = removeSecurityProxy(product)
series = naked_product.newSeries(
- owner=owner, name=name, summary=summary, branch=branch)
+ owner=owner, name=name, summary=summary, branch=branch
+ )
if date_created is not None:
series.datecreated = date_created
return ProxyFactory(series)
- def makeProject(self, name=None, displayname=None, title=None,
- homepageurl=None, summary=None, owner=None, driver=None,
- description=None):
+ def makeProject(
+ self,
+ name=None,
+ displayname=None,
+ title=None,
+ homepageurl=None,
+ summary=None,
+ owner=None,
+ driver=None,
+ description=None,
+ ):
"""Create and return a new, arbitrary ProjectGroup."""
if owner is None:
owner = self.makePerson()
if name is None:
- name = self.getUniqueString('project-name')
+ name = self.getUniqueString("project-name")
if displayname is None:
- displayname = self.getUniqueString('displayname')
+ displayname = self.getUniqueString("displayname")
if summary is None:
- summary = self.getUniqueString('summary')
+ summary = self.getUniqueString("summary")
if description is None:
- description = self.getUniqueString('description')
+ description = self.getUniqueString("description")
if title is None:
- title = self.getUniqueString('title')
+ title = self.getUniqueString("title")
project = getUtility(IProjectGroupSet).new(
name=name,
display_name=displayname,
@@ -1124,7 +1208,8 @@ class LaunchpadObjectFactory(ObjectFactory):
homepageurl=homepageurl,
summary=summary,
description=description,
- owner=owner)
+ owner=owner,
+ )
if driver is not None:
removeSecurityProxy(project).driver = driver
return project
@@ -1132,18 +1217,24 @@ class LaunchpadObjectFactory(ObjectFactory):
def makeSprint(self, title=None, name=None, time_starts=None):
"""Make a sprint."""
if title is None:
- title = self.getUniqueUnicode('title')
+ title = self.getUniqueUnicode("title")
owner = self.makePerson()
if name is None:
- name = self.getUniqueUnicode('name')
+ name = self.getUniqueUnicode("name")
if time_starts is None:
time_starts = datetime(2009, 1, 1, tzinfo=pytz.UTC)
time_ends = time_starts + timedelta(days=1)
- time_zone = 'UTC'
- summary = self.getUniqueUnicode('summary')
+ time_zone = "UTC"
+ summary = self.getUniqueUnicode("summary")
return getUtility(ISprintSet).new(
- owner=owner, name=name, title=title, time_zone=time_zone,
- time_starts=time_starts, time_ends=time_ends, summary=summary)
+ owner=owner,
+ name=name,
+ title=title,
+ time_zone=time_zone,
+ time_starts=time_starts,
+ time_ends=time_ends,
+ summary=summary,
+ )
def makeStackedOnBranchChain(self, depth=5, **kwargs):
branch = None
@@ -1151,11 +1242,21 @@ class LaunchpadObjectFactory(ObjectFactory):
branch = self.makeAnyBranch(stacked_on=branch, **kwargs)
return branch
- def makeBranch(self, branch_type=None, owner=None,
- name=None, product=_DEFAULT, url=_DEFAULT, registrant=None,
- information_type=None, stacked_on=None,
- sourcepackage=None, reviewer=None, target=None,
- **optional_branch_args):
+ def makeBranch(
+ self,
+ branch_type=None,
+ owner=None,
+ name=None,
+ product=_DEFAULT,
+ url=_DEFAULT,
+ registrant=None,
+ information_type=None,
+ stacked_on=None,
+ sourcepackage=None,
+ reviewer=None,
+ target=None,
+ **optional_branch_args
+ ):
"""Create and return a new, arbitrary Branch of the given type.
Any parameters for `IBranchNamespace.createBranch` can be specified to
@@ -1166,7 +1267,7 @@ class LaunchpadObjectFactory(ObjectFactory):
if owner is None:
owner = self.makePerson()
if name is None:
- name = self.getUniqueString('branch')
+ name = self.getUniqueString("branch")
if target is not None:
assert product is _DEFAULT
assert sourcepackage is None
@@ -1183,8 +1284,9 @@ class LaunchpadObjectFactory(ObjectFactory):
sourcepackagename = None
distroseries = None
else:
- assert product is _DEFAULT, (
- "Passed source package AND product details")
+ assert (
+ product is _DEFAULT
+ ), "Passed source package AND product details"
product = None
sourcepackagename = sourcepackage.sourcepackagename
distroseries = sourcepackage.distroseries
@@ -1202,45 +1304,68 @@ class LaunchpadObjectFactory(ObjectFactory):
url = self.getUniqueURL()
else:
raise UnknownBranchTypeError(
- 'Unrecognized branch type: %r' % (branch_type, ))
+ "Unrecognized branch type: %r" % (branch_type,)
+ )
namespace = get_branch_namespace(
- owner, product=product, distroseries=distroseries,
- sourcepackagename=sourcepackagename)
+ owner,
+ product=product,
+ distroseries=distroseries,
+ sourcepackagename=sourcepackagename,
+ )
branch = namespace.createBranch(
- branch_type=branch_type, name=name, registrant=registrant,
- url=url, **optional_branch_args)
+ branch_type=branch_type,
+ name=name,
+ registrant=registrant,
+ url=url,
+ **optional_branch_args,
+ )
naked_branch = removeSecurityProxy(branch)
if information_type is not None:
naked_branch.transitionToInformationType(
- information_type, registrant, verify_policy=False)
+ information_type, registrant, verify_policy=False
+ )
if stacked_on is not None:
naked_branch.branchChanged(
- removeSecurityProxy(stacked_on).unique_name, 'rev1', None,
- None, None)
+ removeSecurityProxy(stacked_on).unique_name,
+ "rev1",
+ None,
+ None,
+ None,
+ )
if reviewer is not None:
naked_branch.reviewer = reviewer
return branch
- def makePackagingLink(self, productseries=None, sourcepackagename=None,
- distroseries=None, packaging_type=None, owner=None,
- sourcepackage=None, in_ubuntu=False):
+ def makePackagingLink(
+ self,
+ productseries=None,
+ sourcepackagename=None,
+ distroseries=None,
+ packaging_type=None,
+ owner=None,
+ sourcepackage=None,
+ in_ubuntu=False,
+ ):
assert sourcepackage is None or (
- distroseries is None and sourcepackagename is None), (
+ distroseries is None and sourcepackagename is None
+ ), (
"Specify either a sourcepackage or a "
- "distroseries/sourcepackagename pair")
+ "distroseries/sourcepackagename pair"
+ )
if productseries is None:
productseries = self.makeProduct().development_focus
if sourcepackage is not None:
distroseries = sourcepackage.distroseries
sourcepackagename = sourcepackage.sourcepackagename
else:
- make_sourcepackagename = (
- sourcepackagename is None or
- isinstance(sourcepackagename, str))
+ make_sourcepackagename = sourcepackagename is None or isinstance(
+ sourcepackagename, str
+ )
if make_sourcepackagename:
sourcepackagename = self.makeSourcePackageName(
- sourcepackagename)
+ sourcepackagename
+ )
if distroseries is None:
if in_ubuntu:
distroseries = self.makeUbuntuDistroSeries()
@@ -1255,10 +1380,16 @@ class LaunchpadObjectFactory(ObjectFactory):
sourcepackagename=sourcepackagename,
distroseries=distroseries,
packaging=packaging_type,
- owner=owner)
+ owner=owner,
+ )
- def makePackageBranch(self, sourcepackage=None, distroseries=None,
- sourcepackagename=None, **kwargs):
+ def makePackageBranch(
+ self,
+ sourcepackage=None,
+ distroseries=None,
+ sourcepackagename=None,
+ **kwargs
+ ):
"""Make a package branch on an arbitrary package.
See `makeBranch` for more information on arguments.
@@ -1267,15 +1398,16 @@ class LaunchpadObjectFactory(ObjectFactory):
`distroseries` and `sourcepackagename`, but not combinations or all of
them.
"""
- assert not(sourcepackage is not None and distroseries is not None), (
- "Don't pass in both sourcepackage and distroseries")
- assert not(sourcepackage is not None
- and sourcepackagename is not None), (
- "Don't pass in both sourcepackage and sourcepackagename")
+ assert not (
+ sourcepackage is not None and distroseries is not None
+ ), "Don't pass in both sourcepackage and distroseries"
+ assert not (
+ sourcepackage is not None and sourcepackagename is not None
+ ), "Don't pass in both sourcepackage and sourcepackagename"
if sourcepackage is None:
sourcepackage = self.makeSourcePackage(
- sourcepackagename=sourcepackagename,
- distroseries=distroseries)
+ sourcepackagename=sourcepackagename, distroseries=distroseries
+ )
return self.makeBranch(sourcepackage=sourcepackage, **kwargs)
def makePersonalBranch(self, owner=None, **kwargs):
@@ -1286,7 +1418,8 @@ class LaunchpadObjectFactory(ObjectFactory):
if owner is None:
owner = self.makePerson()
return self.makeBranch(
- owner=owner, product=None, sourcepackage=None, **kwargs)
+ owner=owner, product=None, sourcepackage=None, **kwargs
+ )
def makeProductBranch(self, product=None, **kwargs):
"""Make a product branch on an arbitrary product.
@@ -1304,11 +1437,17 @@ class LaunchpadObjectFactory(ObjectFactory):
"""
return self.makeProductBranch(**kwargs)
- def makeBranchTargetBranch(self, target, branch_type=BranchType.HOSTED,
- name=None, owner=None, creator=None):
+ def makeBranchTargetBranch(
+ self,
+ target,
+ branch_type=BranchType.HOSTED,
+ name=None,
+ owner=None,
+ creator=None,
+ ):
"""Create a branch in a BranchTarget."""
if name is None:
- name = self.getUniqueString('branch')
+ name = self.getUniqueString("branch")
if owner is None:
owner = self.makePerson()
if creator is None:
@@ -1316,25 +1455,31 @@ class LaunchpadObjectFactory(ObjectFactory):
namespace = target.getNamespace(owner)
return namespace.createBranch(branch_type, name, creator)
- def makeRelatedBranchesForSourcePackage(self, sourcepackage=None,
- **kwargs):
+ def makeRelatedBranchesForSourcePackage(
+ self, sourcepackage=None, **kwargs
+ ):
"""Create some branches associated with a sourcepackage."""
reference_branch = self.makePackageBranch(sourcepackage=sourcepackage)
return self.makeRelatedBranches(
- reference_branch=reference_branch, **kwargs)
+ reference_branch=reference_branch, **kwargs
+ )
def makeRelatedBranchesForProduct(self, product=None, **kwargs):
"""Create some branches associated with a product."""
reference_branch = self.makeProductBranch(product=product)
return self.makeRelatedBranches(
- reference_branch=reference_branch, **kwargs)
+ reference_branch=reference_branch, **kwargs
+ )
- def makeRelatedBranches(self, reference_branch=None,
- with_series_branches=True,
- with_package_branches=True,
- with_private_branches=False):
+ def makeRelatedBranches(
+ self,
+ reference_branch=None,
+ with_series_branches=True,
+ with_package_branches=True,
+ with_private_branches=False,
+ ):
"""Create some branches associated with a reference branch.
The other branches are:
- series branches: a set of branches associated with product
@@ -1357,8 +1502,8 @@ class LaunchpadObjectFactory(ObjectFactory):
naked_product = removeSecurityProxy(self.makeProduct())
# Create the 'source' branch ie the base branch of a recipe.
reference_branch = self.makeProductBranch(
- name="reference_branch",
- product=naked_product)
+ name="reference_branch", product=naked_product
+ )
elif reference_branch.product is not None:
naked_product = removeSecurityProxy(reference_branch.product)
@@ -1371,34 +1516,43 @@ class LaunchpadObjectFactory(ObjectFactory):
def makeSeriesBranch(name, information_type):
branch = self.makeBranch(
name=name,
- product=naked_product, owner=related_branch_owner,
- information_type=information_type)
+ product=naked_product,
+ owner=related_branch_owner,
+ information_type=information_type,
+ )
series = self.makeProductSeries(
- product=naked_product, branch=branch)
+ product=naked_product, branch=branch
+ )
return branch, series
+
for x in range(4):
information_type = InformationType.PUBLIC
if x == 0 and with_private_branches:
information_type = InformationType.USERDATA
(branch, series) = makeSeriesBranch(
- ("series_branch_%s" % x), information_type)
+ ("series_branch_%s" % x), information_type
+ )
if information_type == InformationType.PUBLIC:
series_branch_info.append((branch, series))
# Sort them
related_series_branch_info = sorted_version_numbers(
- series_branch_info, key=lambda branch_info: (
- getattr(branch_info[1], 'name')))
+ series_branch_info,
+ key=lambda branch_info: (getattr(branch_info[1], "name")),
+ )
# Add a development branch at the start of the list.
- naked_product.development_focus.name = 'trunk'
+ naked_product.development_focus.name = "trunk"
devel_branch = self.makeProductBranch(
- product=naked_product, name='trunk_branch',
- owner=related_branch_owner)
+ product=naked_product,
+ name="trunk_branch",
+ owner=related_branch_owner,
+ )
linked_branch = ICanHasLinkedBranch(naked_product)
linked_branch.setBranch(devel_branch)
- related_series_branch_info.insert(0,
- (devel_branch, naked_product.development_focus))
+ related_series_branch_info.insert(
+ 0, (devel_branch, naked_product.development_focus)
+ )
if with_package_branches:
# Create related package branches if the base_branch is
@@ -1407,30 +1561,35 @@ class LaunchpadObjectFactory(ObjectFactory):
def makePackageBranch(name, information_type):
distro = self.makeDistribution()
- distroseries = self.makeDistroSeries(
- distribution=distro)
+ distroseries = self.makeDistroSeries(distribution=distro)
sourcepackagename = self.makeSourcePackageName()
suitesourcepackage = self.makeSuiteSourcePackage(
sourcepackagename=sourcepackagename,
distroseries=distroseries,
- pocket=PackagePublishingPocket.RELEASE)
+ pocket=PackagePublishingPocket.RELEASE,
+ )
naked_sourcepackage = removeSecurityProxy(
- suitesourcepackage)
+ suitesourcepackage
+ )
branch = self.makePackageBranch(
- name=name, owner=related_branch_owner,
+ name=name,
+ owner=related_branch_owner,
sourcepackagename=sourcepackagename,
distroseries=distroseries,
- information_type=information_type)
+ information_type=information_type,
+ )
linked_branch = ICanHasLinkedBranch(naked_sourcepackage)
- with celebrity_logged_in('admin'):
+ with celebrity_logged_in("admin"):
linked_branch.setBranch(branch, related_branch_owner)
series = self.makeProductSeries(product=naked_product)
self.makePackagingLink(
- distroseries=distroseries, productseries=series,
- sourcepackagename=sourcepackagename)
+ distroseries=distroseries,
+ productseries=series,
+ sourcepackagename=sourcepackagename,
+ )
return branch, distroseries
for x in range(5):
@@ -1438,39 +1597,42 @@ class LaunchpadObjectFactory(ObjectFactory):
if x == 0 and with_private_branches:
information_type = InformationType.USERDATA
branch, distroseries = makePackageBranch(
- ("product_package_branch_%s" % x),
- information_type)
+ ("product_package_branch_%s" % x), information_type
+ )
if information_type == InformationType.PUBLIC:
related_package_branch_info.append(
- (branch, distroseries))
+ (branch, distroseries)
+ )
# Create related package branches if the base_branch is
# associated with a sourcepackage.
if reference_branch.sourcepackage is not None:
distroseries = reference_branch.sourcepackage.distroseries
for pocket in [
- PackagePublishingPocket.RELEASE,
- PackagePublishingPocket.UPDATES,
- ]:
+ PackagePublishingPocket.RELEASE,
+ PackagePublishingPocket.UPDATES,
+ ]:
branch = self.makePackageBranch(
- name="package_branch_%s" % pocket.name,
- distroseries=distroseries)
- with celebrity_logged_in('admin'):
+ name="package_branch_%s" % pocket.name,
+ distroseries=distroseries,
+ )
+ with celebrity_logged_in("admin"):
reference_branch.sourcepackage.setBranch(
- pocket, branch,
- related_branch_owner)
+ pocket, branch, related_branch_owner
+ )
- related_package_branch_info.append(
- (branch, distroseries))
+ related_package_branch_info.append((branch, distroseries))
related_package_branch_info = sorted_version_numbers(
- related_package_branch_info, key=lambda branch_info: (
- getattr(branch_info[1], 'name')))
+ related_package_branch_info,
+ key=lambda branch_info: (getattr(branch_info[1], "name")),
+ )
return (
reference_branch,
related_series_branch_info,
- related_package_branch_info)
+ related_package_branch_info,
+ )
def enableDefaultStackingForProduct(self, product, branch=None):
"""Give 'product' a default stacked-on branch.
@@ -1483,8 +1645,7 @@ class LaunchpadObjectFactory(ObjectFactory):
branch = self.makeBranch(product=product)
# We just remove the security proxies to be able to change the objects
# here.
- removeSecurityProxy(branch).branchChanged(
- '', 'rev1', None, None, None)
+ removeSecurityProxy(branch).branchChanged("", "rev1", None, None, None)
naked_series = removeSecurityProxy(product.development_focus)
naked_series.branch = branch
return branch
@@ -1498,20 +1659,30 @@ class LaunchpadObjectFactory(ObjectFactory):
"""
# We just remove the security proxies to be able to change the branch
# here.
- removeSecurityProxy(branch).branchChanged(
- '', 'rev1', None, None, None)
+ removeSecurityProxy(branch).branchChanged("", "rev1", None, None, None)
with person_logged_in(package.distribution.owner):
package.development_version.setBranch(
- PackagePublishingPocket.RELEASE, branch,
- package.distribution.owner)
+ PackagePublishingPocket.RELEASE,
+ branch,
+ package.distribution.owner,
+ )
return branch
- def makeBranchMergeProposal(self, target_branch=None, registrant=None,
- set_state=None, prerequisite_branch=None,
- product=None, initial_comment=None,
- source_branch=None, date_created=None,
- commit_message=None, description=None,
- reviewer=None, merged_revno=None):
+ def makeBranchMergeProposal(
+ self,
+ target_branch=None,
+ registrant=None,
+ set_state=None,
+ prerequisite_branch=None,
+ product=None,
+ initial_comment=None,
+ source_branch=None,
+ date_created=None,
+ commit_message=None,
+ description=None,
+ reviewer=None,
+ merged_revno=None,
+ ):
"""Create a proposal to merge based on anonymous branches."""
if target_branch is not None:
target_branch = removeSecurityProxy(target_branch)
@@ -1543,39 +1714,57 @@ class LaunchpadObjectFactory(ObjectFactory):
if reviewer is not None:
review_requests.append((reviewer, None))
proposal = source_branch.addLandingTarget(
- registrant, target_branch, review_requests=review_requests,
- merge_prerequisite=prerequisite_branch, description=description,
- commit_message=commit_message, date_created=date_created)
+ registrant,
+ target_branch,
+ review_requests=review_requests,
+ merge_prerequisite=prerequisite_branch,
+ description=description,
+ commit_message=commit_message,
+ date_created=date_created,
+ )
unsafe_proposal = removeSecurityProxy(proposal)
unsafe_proposal.merged_revno = merged_revno
- if (set_state is None or
- set_state == BranchMergeProposalStatus.WORK_IN_PROGRESS):
+ if (
+ set_state is None
+ or set_state == BranchMergeProposalStatus.WORK_IN_PROGRESS
+ ):
# The initial state is work in progress, so do nothing.
pass
elif set_state == BranchMergeProposalStatus.NEEDS_REVIEW:
unsafe_proposal.requestReview()
elif set_state == BranchMergeProposalStatus.CODE_APPROVED:
unsafe_proposal.approveBranch(
- proposal.merge_target.owner, 'some_revision')
+ proposal.merge_target.owner, "some_revision"
+ )
elif set_state == BranchMergeProposalStatus.REJECTED:
unsafe_proposal.rejectBranch(
- proposal.merge_target.owner, 'some_revision')
+ proposal.merge_target.owner, "some_revision"
+ )
elif set_state == BranchMergeProposalStatus.MERGED:
unsafe_proposal.markAsMerged()
elif set_state == BranchMergeProposalStatus.SUPERSEDED:
unsafe_proposal.resubmit(proposal.registrant)
else:
- raise AssertionError('Unknown status: %s' % set_state)
+ raise AssertionError("Unknown status: %s" % set_state)
return proposal
- def makeBranchMergeProposalForGit(self, target_ref=None, registrant=None,
- set_state=None, prerequisite_ref=None,
- target=_DEFAULT, initial_comment=None,
- source_ref=None, date_created=None,
- commit_message=None, description=None,
- reviewer=None, merged_revision_id=None):
+ def makeBranchMergeProposalForGit(
+ self,
+ target_ref=None,
+ registrant=None,
+ set_state=None,
+ prerequisite_ref=None,
+ target=_DEFAULT,
+ initial_comment=None,
+ source_ref=None,
+ date_created=None,
+ commit_message=None,
+ description=None,
+ reviewer=None,
+ merged_revision_id=None,
+ ):
"""Create a proposal to merge based on anonymous branches."""
if target is not _DEFAULT:
pass
@@ -1607,35 +1796,45 @@ class LaunchpadObjectFactory(ObjectFactory):
if reviewer is not None:
review_requests.append((reviewer, None))
proposal = source_ref.addLandingTarget(
- registrant, target_ref, review_requests=review_requests,
- merge_prerequisite=prerequisite_ref, description=description,
- commit_message=commit_message, date_created=date_created)
+ registrant,
+ target_ref,
+ review_requests=review_requests,
+ merge_prerequisite=prerequisite_ref,
+ description=description,
+ commit_message=commit_message,
+ date_created=date_created,
+ )
unsafe_proposal = removeSecurityProxy(proposal)
unsafe_proposal.merged_revision_id = merged_revision_id
- if (set_state is None or
- set_state == BranchMergeProposalStatus.WORK_IN_PROGRESS):
+ if (
+ set_state is None
+ or set_state == BranchMergeProposalStatus.WORK_IN_PROGRESS
+ ):
# The initial state is work in progress, so do nothing.
pass
elif set_state == BranchMergeProposalStatus.NEEDS_REVIEW:
unsafe_proposal.requestReview()
elif set_state == BranchMergeProposalStatus.CODE_APPROVED:
unsafe_proposal.approveBranch(
- proposal.merge_target.owner, 'some_revision')
+ proposal.merge_target.owner, "some_revision"
+ )
elif set_state == BranchMergeProposalStatus.REJECTED:
unsafe_proposal.rejectBranch(
- proposal.merge_target.owner, 'some_revision')
+ proposal.merge_target.owner, "some_revision"
+ )
elif set_state == BranchMergeProposalStatus.MERGED:
unsafe_proposal.markAsMerged()
elif set_state == BranchMergeProposalStatus.SUPERSEDED:
unsafe_proposal.resubmit(proposal.registrant)
else:
- raise AssertionError('Unknown status: %s' % set_state)
+ raise AssertionError("Unknown status: %s" % set_state)
return proposal
- def makeBranchSubscription(self, branch=None, person=None,
- subscribed_by=None):
+ def makeBranchSubscription(
+ self, branch=None, person=None, subscribed_by=None
+ ):
"""Create a BranchSubscription."""
if branch is None:
branch = self.makeBranch()
@@ -1643,20 +1842,32 @@ class LaunchpadObjectFactory(ObjectFactory):
person = self.makePerson()
if subscribed_by is None:
subscribed_by = person
- return branch.subscribe(removeSecurityProxy(person),
- BranchSubscriptionNotificationLevel.NOEMAIL, None,
- CodeReviewNotificationLevel.NOEMAIL, subscribed_by)
-
- def makeDiff(self, size='small'):
- diff_path = os.path.join(os.path.dirname(__file__),
- 'data/{}.diff'.format(size))
- with open(os.path.join(diff_path), 'rb') as diff:
+ return branch.subscribe(
+ removeSecurityProxy(person),
+ BranchSubscriptionNotificationLevel.NOEMAIL,
+ None,
+ CodeReviewNotificationLevel.NOEMAIL,
+ subscribed_by,
+ )
+
+ def makeDiff(self, size="small"):
+ diff_path = os.path.join(
+ os.path.dirname(__file__), "data/{}.diff".format(size)
+ )
+ with open(os.path.join(diff_path), "rb") as diff:
diff_text = diff.read()
return ProxyFactory(
- Diff.fromFile(BytesIO(diff_text), len(diff_text)))
+ Diff.fromFile(BytesIO(diff_text), len(diff_text))
+ )
- def makePreviewDiff(self, conflicts='', merge_proposal=None,
- date_created=None, size='small', git=False):
+ def makePreviewDiff(
+ self,
+ conflicts="",
+ merge_proposal=None,
+ date_created=None,
+ size="small",
+ git=False,
+ ):
diff = self.makeDiff(size)
if merge_proposal is None:
if git:
@@ -1673,8 +1884,9 @@ class LaunchpadObjectFactory(ObjectFactory):
preview_diff.date_created = date_created
return preview_diff
- def makeIncrementalDiff(self, merge_proposal=None, old_revision=None,
- new_revision=None):
+ def makeIncrementalDiff(
+ self, merge_proposal=None, old_revision=None, new_revision=None
+ ):
diff = self.makeDiff()
if merge_proposal is None:
source_branch = self.makeBranch()
@@ -1688,37 +1900,52 @@ class LaunchpadObjectFactory(ObjectFactory):
else:
parent_ids = [parent.revision_id]
branch_revision = self.makeBranchRevision(
- source_branch, sequence=sequence,
- revision_date=self.getUniqueDate(), parent_ids=parent_ids)
+ source_branch,
+ sequence=sequence,
+ revision_date=self.getUniqueDate(),
+ parent_ids=parent_ids,
+ )
return branch_revision.revision
+
if old_revision is None:
old_revision = make_revision()
if merge_proposal is None:
merge_proposal = self.makeBranchMergeProposal(
- date_created=self.getUniqueDate(),
- source_branch=source_branch)
+ date_created=self.getUniqueDate(), source_branch=source_branch
+ )
if new_revision is None:
new_revision = make_revision(old_revision)
return merge_proposal.generateIncrementalDiff(
- old_revision, new_revision, diff)
+ old_revision, new_revision, diff
+ )
def makeBzrRevision(self, revision_id=None, parent_ids=None, props=None):
if revision_id is None:
- revision_id = self.getUniqueString('revision-id')
+ revision_id = self.getUniqueString("revision-id")
if parent_ids is None:
parent_ids = []
return BzrRevision(
- message=self.getUniqueString('message'),
+ message=self.getUniqueString("message"),
revision_id=revision_id,
- committer=self.getUniqueString('committer'),
+ committer=self.getUniqueString("committer"),
parent_ids=parent_ids,
- timestamp=0, timezone=0, properties=props)
+ timestamp=0,
+ timezone=0,
+ properties=props,
+ )
- def makeRevision(self, author=None, revision_date=None, parent_ids=None,
- rev_id=None, log_body=None, date_created=None):
+ def makeRevision(
+ self,
+ author=None,
+ revision_date=None,
+ parent_ids=None,
+ rev_id=None,
+ log_body=None,
+ date_created=None,
+ ):
"""Create a single `Revision`."""
if author is None:
- author = self.getUniqueString('author')
+ author = self.getUniqueString("author")
elif IPerson.providedBy(author):
author = removeSecurityProxy(author).preferredemail.email
if revision_date is None:
@@ -1726,19 +1953,24 @@ class LaunchpadObjectFactory(ObjectFactory):
if parent_ids is None:
parent_ids = []
if rev_id is None:
- rev_id = self.getUniqueUnicode('revision-id')
+ rev_id = self.getUniqueUnicode("revision-id")
else:
rev_id = six.ensure_text(rev_id)
if log_body is None:
- log_body = self.getUniqueString('log-body')
+ log_body = self.getUniqueString("log-body")
return getUtility(IRevisionSet).new(
- revision_id=rev_id, log_body=log_body,
- revision_date=revision_date, revision_author=author,
- parent_ids=parent_ids, properties={},
- _date_created=date_created)
+ revision_id=rev_id,
+ log_body=log_body,
+ revision_date=revision_date,
+ revision_author=author,
+ parent_ids=parent_ids,
+ properties={},
+ _date_created=date_created,
+ )
- def makeRevisionsForBranch(self, branch, count=5, author=None,
- date_generator=None):
+ def makeRevisionsForBranch(
+ self, branch, count=5, author=None, date_generator=None
+ ):
"""Add `count` revisions to the revision history of `branch`.
:param branch: The branch to add the revisions to.
@@ -1749,8 +1981,8 @@ class LaunchpadObjectFactory(ObjectFactory):
"""
if date_generator is None:
date_generator = time_counter(
- datetime(2007, 1, 1, tzinfo=pytz.UTC),
- delta=timedelta(days=1))
+ datetime(2007, 1, 1, tzinfo=pytz.UTC), delta=timedelta(days=1)
+ )
sequence = branch.revision_count
parent = branch.getTipRevision()
if parent is None:
@@ -1760,15 +1992,16 @@ class LaunchpadObjectFactory(ObjectFactory):
revision_set = getUtility(IRevisionSet)
if author is None:
- author = self.getUniqueString('author')
+ author = self.getUniqueString("author")
for index in range(count):
revision = revision_set.new(
- revision_id=self.getUniqueString('revision-id'),
- log_body=self.getUniqueString('log-body'),
+ revision_id=self.getUniqueString("revision-id"),
+ log_body=self.getUniqueString("log-body"),
revision_date=next(date_generator),
revision_author=author,
parent_ids=parent_ids,
- properties={})
+ properties={},
+ )
sequence += 1
branch.createBranchRevision(sequence, revision)
parent = revision
@@ -1776,24 +2009,40 @@ class LaunchpadObjectFactory(ObjectFactory):
if branch.branch_type not in (BranchType.REMOTE, BranchType.HOSTED):
branch.startMirroring()
removeSecurityProxy(branch).branchChanged(
- '', parent.revision_id, None, None, None)
+ "", parent.revision_id, None, None, None
+ )
branch.updateScannedDetails(parent, sequence)
- def makeBranchRevision(self, branch=None, revision_id=None, sequence=None,
- parent_ids=None, revision_date=None):
+ def makeBranchRevision(
+ self,
+ branch=None,
+ revision_id=None,
+ sequence=None,
+ parent_ids=None,
+ revision_date=None,
+ ):
if branch is None:
branch = self.makeBranch()
else:
branch = removeSecurityProxy(branch)
revision = self.makeRevision(
- rev_id=revision_id, parent_ids=parent_ids,
- revision_date=revision_date)
+ rev_id=revision_id,
+ parent_ids=parent_ids,
+ revision_date=revision_date,
+ )
return branch.createBranchRevision(sequence, revision)
- def makeGitRepository(self, repository_type=None, owner=None,
- reviewer=None, target=_DEFAULT, registrant=None,
- name=None, information_type=None,
- **optional_repository_args):
+ def makeGitRepository(
+ self,
+ repository_type=None,
+ owner=None,
+ reviewer=None,
+ target=_DEFAULT,
+ registrant=None,
+ name=None,
+ information_type=None,
+ **optional_repository_args
+ ):
"""Create and return a new, arbitrary GitRepository.
Any parameters for `IGitNamespace.createRepository` can be specified
@@ -1804,7 +2053,7 @@ class LaunchpadObjectFactory(ObjectFactory):
if owner is None:
owner = self.makePerson()
if name is None:
- name = self.getUniqueUnicode('gitrepository')
+ name = self.getUniqueUnicode("gitrepository")
if target is _DEFAULT:
target = self.makeProduct()
@@ -1817,16 +2066,22 @@ class LaunchpadObjectFactory(ObjectFactory):
namespace = get_git_namespace(target, owner)
repository = namespace.createRepository(
- repository_type=repository_type, registrant=registrant, name=name,
- reviewer=reviewer, **optional_repository_args)
+ repository_type=repository_type,
+ registrant=registrant,
+ name=name,
+ reviewer=reviewer,
+ **optional_repository_args,
+ )
naked_repository = removeSecurityProxy(repository)
if information_type is not None:
naked_repository.transitionToInformationType(
- information_type, registrant, verify_policy=False)
+ information_type, registrant, verify_policy=False
+ )
return repository
- def makeGitSubscription(self, repository=None, person=None,
- subscribed_by=None):
+ def makeGitSubscription(
+ self, repository=None, person=None, subscribed_by=None
+ ):
"""Create a GitSubscription."""
if repository is None:
repository = self.makeGitRepository()
@@ -1834,27 +2089,34 @@ class LaunchpadObjectFactory(ObjectFactory):
person = self.makePerson()
if subscribed_by is None:
subscribed_by = person
- return repository.subscribe(removeSecurityProxy(person),
- BranchSubscriptionNotificationLevel.NOEMAIL, None,
- CodeReviewNotificationLevel.NOEMAIL, subscribed_by)
+ return repository.subscribe(
+ removeSecurityProxy(person),
+ BranchSubscriptionNotificationLevel.NOEMAIL,
+ None,
+ CodeReviewNotificationLevel.NOEMAIL,
+ subscribed_by,
+ )
def makeGitRefs(self, repository=None, paths=None, **repository_kwargs):
"""Create and return a list of new, arbitrary GitRefs."""
if repository is None:
repository = self.makeGitRepository(**repository_kwargs)
if paths is None:
- paths = [self.getUniqueUnicode('refs/heads/path')]
+ paths = [self.getUniqueUnicode("refs/heads/path")]
refs_info = {
path: {
"sha1": hashlib.sha1(path.encode()).hexdigest(),
"type": GitObjectType.COMMIT,
- }
- for path in paths}
+ }
+ for path in paths
+ }
with GitHostingFixture():
refs_by_path = {
ref.path: ref
for ref in removeSecurityProxy(repository).createOrUpdateRefs(
- refs_info, get_objects=True)}
+ refs_info, get_objects=True
+ )
+ }
return [refs_by_path[path] for path in paths]
def makeGitRefRemote(self, repository_url=None, path=None):
@@ -1862,11 +2124,17 @@ class LaunchpadObjectFactory(ObjectFactory):
if repository_url is None:
repository_url = self.getUniqueURL()
if path is None:
- path = self.getUniqueUnicode('refs/heads/path')
+ path = self.getUniqueUnicode("refs/heads/path")
return getUtility(IGitRefRemoteSet).new(repository_url, path)
- def makeGitRule(self, repository=None, ref_pattern="refs/heads/*",
- creator=None, position=None, **repository_kwargs):
+ def makeGitRule(
+ self,
+ repository=None,
+ ref_pattern="refs/heads/*",
+ creator=None,
+ position=None,
+ **repository_kwargs
+ ):
"""Create a Git repository access rule."""
if repository is None:
repository = self.makeGitRepository(**repository_kwargs)
@@ -1875,9 +2143,16 @@ class LaunchpadObjectFactory(ObjectFactory):
with person_logged_in(creator):
return repository.addRule(ref_pattern, creator, position=position)
- def makeGitRuleGrant(self, rule=None, grantee=None, grantor=None,
- can_create=False, can_push=False,
- can_force_push=False, **rule_kwargs):
+ def makeGitRuleGrant(
+ self,
+ rule=None,
+ grantee=None,
+ grantor=None,
+ can_create=False,
+ can_push=False,
+ can_force_push=False,
+ **rule_kwargs
+ ):
"""Create a Git repository access grant."""
if rule is None:
rule = self.makeGitRule(**rule_kwargs)
@@ -1887,13 +2162,24 @@ class LaunchpadObjectFactory(ObjectFactory):
grantor = rule.repository.owner
with person_logged_in(grantor):
return rule.addGrant(
- grantee, grantor, can_create=can_create, can_push=can_push,
- can_force_push=can_force_push)
+ grantee,
+ grantor,
+ can_create=can_create,
+ can_push=can_push,
+ can_force_push=can_force_push,
+ )
- def makeRevisionStatusReport(self, user=None, title=None,
- git_repository=None, commit_sha1=None,
- result_summary=None, url=None, result=None,
- ci_build=None):
+ def makeRevisionStatusReport(
+ self,
+ user=None,
+ title=None,
+ git_repository=None,
+ commit_sha1=None,
+ result_summary=None,
+ url=None,
+ result=None,
+ ci_build=None,
+ ):
"""Create a new RevisionStatusReport."""
if title is None:
title = self.getUniqueUnicode()
@@ -1912,27 +2198,53 @@ class LaunchpadObjectFactory(ObjectFactory):
if result_summary is None:
result_summary = self.getUniqueUnicode()
return getUtility(IRevisionStatusReportSet).new(
- user, title, git_repository, commit_sha1, url,
- result_summary, result, ci_build=ci_build)
+ user,
+ title,
+ git_repository,
+ commit_sha1,
+ url,
+ result_summary,
+ result,
+ ci_build=ci_build,
+ )
def makeRevisionStatusArtifact(
- self, lfa=None, content=None, report=None,
- artifact_type=None, restricted=False):
+ self,
+ lfa=None,
+ content=None,
+ report=None,
+ artifact_type=None,
+ restricted=False,
+ ):
"""Create a new RevisionStatusArtifact."""
if lfa is None:
lfa = self.makeLibraryFileAlias(
- content=content, restricted=restricted)
+ content=content, restricted=restricted
+ )
if report is None:
report = self.makeRevisionStatusReport()
if artifact_type is None:
artifact_type = RevisionStatusArtifactType.LOG
return getUtility(IRevisionStatusArtifactSet).new(
- lfa, report, artifact_type)
+ lfa, report, artifact_type
+ )
- def makeBug(self, target=None, owner=None, bug_watch_url=None,
- information_type=None, date_closed=None, title=None,
- date_created=None, description=None, comment=None,
- status=None, milestone=None, series=None, tags=None):
+ def makeBug(
+ self,
+ target=None,
+ owner=None,
+ bug_watch_url=None,
+ information_type=None,
+ date_closed=None,
+ title=None,
+ date_created=None,
+ description=None,
+ comment=None,
+ status=None,
+ milestone=None,
+ series=None,
+ tags=None,
+ ):
"""Create and return a new, arbitrary Bug.
The bug returned uses default values where possible. See
@@ -1962,17 +2274,25 @@ class LaunchpadObjectFactory(ObjectFactory):
if IDistributionSourcePackage.providedBy(target):
self.makeSourcePackagePublishingHistory(
distroseries=target.distribution.currentseries,
- sourcepackagename=target.sourcepackagename)
+ sourcepackagename=target.sourcepackagename,
+ )
if owner is None:
owner = self.makePerson()
if title is None:
- title = self.getUniqueString('bug-title')
+ title = self.getUniqueString("bug-title")
if comment is None:
comment = self.getUniqueString()
create_bug_params = CreateBugParams(
- owner, title, comment=comment, information_type=information_type,
- datecreated=date_created, description=description,
- status=status, tags=tags, target=target)
+ owner,
+ title,
+ comment=comment,
+ information_type=information_type,
+ datecreated=date_created,
+ description=description,
+ status=status,
+ tags=tags,
+ target=target,
+ )
bug = getUtility(IBugSet).createBug(create_bug_params)
if bug_watch_url is not None:
# fromText() creates a bug watch associated with the bug.
@@ -1982,11 +2302,13 @@ class LaunchpadObjectFactory(ObjectFactory):
if date_closed is not None:
with person_logged_in(owner):
bugtask.transitionToStatus(
- BugTaskStatus.FIXRELEASED, owner, when=date_closed)
+ BugTaskStatus.FIXRELEASED, owner, when=date_closed
+ )
if milestone is not None:
with person_logged_in(owner):
bugtask.transitionToMilestone(
- milestone, milestone.target.owner)
+ milestone, milestone.target.owner
+ )
if series is not None:
with person_logged_in(owner):
task = bug.addTask(owner, series)
@@ -1994,8 +2316,9 @@ class LaunchpadObjectFactory(ObjectFactory):
removeSecurityProxy(bug).clearBugNotificationRecipientsCache()
return bug
- def makeBugTask(self, bug=None, target=None, owner=None, publish=True,
- status=None):
+ def makeBugTask(
+ self, bug=None, target=None, owner=None, publish=True, status=None
+ ):
"""Create and return a bug task.
If the bug is already targeted to the given target, the existing
@@ -2028,7 +2351,8 @@ class LaunchpadObjectFactory(ObjectFactory):
target = self.makeProductSeries(product=existing_pillar)
elif IDistribution.providedBy(existing_pillar):
target = self.makeDistroSeries(
- distribution=existing_pillar)
+ distribution=existing_pillar
+ )
if target is None:
target = self.makeProduct()
@@ -2045,18 +2369,22 @@ class LaunchpadObjectFactory(ObjectFactory):
if publish:
self.makeSourcePackagePublishingHistory(
distroseries=target.distroseries,
- sourcepackagename=target.sourcepackagename)
+ sourcepackagename=target.sourcepackagename,
+ )
if IDistributionSourcePackage.providedBy(target):
if publish:
self.makeSourcePackagePublishingHistory(
distroseries=target.distribution.currentseries,
- sourcepackagename=target.sourcepackagename)
+ sourcepackagename=target.sourcepackagename,
+ )
if prerequisite_target is not None:
prerequisite = bug and removeSecurityProxy(bug).getBugTask(
- prerequisite_target)
+ prerequisite_target
+ )
if prerequisite is None:
prerequisite = self.makeBugTask(
- bug, prerequisite_target, publish=publish)
+ bug, prerequisite_target, publish=publish
+ )
bug = prerequisite.bug
if bug is None:
@@ -2065,7 +2393,8 @@ class LaunchpadObjectFactory(ObjectFactory):
if owner is None:
owner = self.makePerson()
task = getUtility(IBugTaskSet).createTask(
- removeSecurityProxy(bug), owner, target, status=status)
+ removeSecurityProxy(bug), owner, target, status=status
+ )
removeSecurityProxy(bug).clearBugNotificationRecipientsCache()
return task
@@ -2085,31 +2414,34 @@ class LaunchpadObjectFactory(ObjectFactory):
else:
non_series = target.parent
series = target
- with celebrity_logged_in('admin'):
+ with celebrity_logged_in("admin"):
bug = self.makeBugTask(bug=bug, target=non_series).bug
nomination = bug.addNomination(
- getUtility(ILaunchpadCelebrities).admin, series)
+ getUtility(ILaunchpadCelebrities).admin, series
+ )
return nomination
- def makeBugTracker(self, base_url=None, bugtrackertype=None, title=None,
- name=None):
+ def makeBugTracker(
+ self, base_url=None, bugtrackertype=None, title=None, name=None
+ ):
"""Make a new bug tracker."""
owner = self.makePerson()
if base_url is None:
- base_url = 'http://%s.example.com/' % self.getUniqueString()
+ base_url = "http://%s.example.com/" % self.getUniqueString()
if bugtrackertype is None:
bugtrackertype = BugTrackerType.BUGZILLA
return getUtility(IBugTrackerSet).ensureBugTracker(
- base_url, owner, bugtrackertype, title=title, name=name)
+ base_url, owner, bugtrackertype, title=title, name=name
+ )
def makeBugTrackerWithWatches(self, base_url=None, count=2):
"""Make a new bug tracker with some watches."""
bug_tracker = self.makeBugTracker(base_url=base_url)
bug_watches = [
- self.makeBugWatch(bugtracker=bug_tracker)
- for i in range(count)]
+ self.makeBugWatch(bugtracker=bug_tracker) for i in range(count)
+ ]
return (bug_tracker, bug_watches)
def makeBugTrackerComponentGroup(self, name=None, bug_tracker=None):
@@ -2122,8 +2454,9 @@ class LaunchpadObjectFactory(ObjectFactory):
component_group = bug_tracker.addRemoteComponentGroup(name)
return component_group
- def makeBugTrackerComponent(self, name=None, component_group=None,
- custom=None):
+ def makeBugTrackerComponent(
+ self, name=None, component_group=None, custom=None
+ ):
"""Make a new bug tracker component."""
if name is None:
name = self.getUniqueUnicode()
@@ -2137,8 +2470,14 @@ class LaunchpadObjectFactory(ObjectFactory):
component = component_group.addComponent(name)
return component
- def makeBugWatch(self, remote_bug=None, bugtracker=None, bug=None,
- owner=None, bug_task=None):
+ def makeBugWatch(
+ self,
+ remote_bug=None,
+ bugtracker=None,
+ bug=None,
+ owner=None,
+ bug_task=None,
+ ):
"""Make a new bug watch."""
if remote_bug is None:
remote_bug = self.getUniqueInteger()
@@ -2160,15 +2499,18 @@ class LaunchpadObjectFactory(ObjectFactory):
owner = self.makePerson()
bug_watch = getUtility(IBugWatchSet).createBugWatch(
- bug, owner, bugtracker, str(remote_bug))
+ bug, owner, bugtracker, str(remote_bug)
+ )
if bug_task is not None:
bug_task.bugwatch = bug_watch
- removeSecurityProxy(bug_watch).next_check = (
- datetime.now(pytz.timezone('UTC')))
+ removeSecurityProxy(bug_watch).next_check = datetime.now(
+ pytz.timezone("UTC")
+ )
return bug_watch
- def makeBugComment(self, bug=None, owner=None, subject=None, body=None,
- bug_watch=None):
+ def makeBugComment(
+ self, bug=None, owner=None, subject=None, body=None, bug_watch=None
+ ):
"""Create and return a new bug comment.
:param bug: An `IBug` or a bug ID or name, or None, in which
@@ -2194,13 +2536,26 @@ class LaunchpadObjectFactory(ObjectFactory):
if body is None:
body = self.getUniqueString()
with person_logged_in(owner):
- return bug.newMessage(owner=owner, subject=subject, content=body,
- parent=None, bugwatch=bug_watch,
- remote_comment_id=None)
+ return bug.newMessage(
+ owner=owner,
+ subject=subject,
+ content=body,
+ parent=None,
+ bugwatch=bug_watch,
+ remote_comment_id=None,
+ )
- def makeBugAttachment(self, bug=None, owner=None, data=None,
- comment=None, filename=None, content_type=None,
- description=None, is_patch=_DEFAULT):
+ def makeBugAttachment(
+ self,
+ bug=None,
+ owner=None,
+ data=None,
+ comment=None,
+ filename=None,
+ content_type=None,
+ description=None,
+ is_patch=_DEFAULT,
+ ):
"""Create and return a new bug attachment.
:param bug: An `IBug` or a bug ID or name, or None, in which
@@ -2238,13 +2593,20 @@ class LaunchpadObjectFactory(ObjectFactory):
# passed it.
other_params = {}
if is_patch is not _DEFAULT:
- other_params['is_patch'] = is_patch
+ other_params["is_patch"] = is_patch
return bug.addAttachment(
- owner, data, comment, filename, content_type=content_type,
- description=description, **other_params)
+ owner,
+ data,
+ comment,
+ filename,
+ content_type=content_type,
+ description=description,
+ **other_params,
+ )
- def makeBugSubscriptionFilter(self, target=None, subscriber=None,
- subscribed_by=None):
+ def makeBugSubscriptionFilter(
+ self, target=None, subscriber=None, subscribed_by=None
+ ):
"""Create and return a new bug subscription filter.
:param target: An `IStructuralSubscriptionTarget`. Defaults to a
@@ -2260,11 +2622,20 @@ class LaunchpadObjectFactory(ObjectFactory):
if subscribed_by is None:
subscribed_by = subscriber
return removeSecurityProxy(target).addBugSubscriptionFilter(
- subscriber, subscribed_by)
+ subscriber, subscribed_by
+ )
- def makeSignedMessage(self, msgid=None, body=None, subject=None,
- attachment_contents=None, force_transfer_encoding=False,
- email_address=None, signing_context=None, to_address=None):
+ def makeSignedMessage(
+ self,
+ msgid=None,
+ body=None,
+ subject=None,
+ attachment_contents=None,
+ force_transfer_encoding=False,
+ email_address=None,
+ signing_context=None,
+ to_address=None,
+ ):
"""Return an ISignedMessage.
:param msgid: An rfc2822 message-id.
@@ -2281,31 +2652,35 @@ class LaunchpadObjectFactory(ObjectFactory):
if email_address is None:
person = self.makePerson()
email_address = removeSecurityProxy(person).preferredemail.email
- mail['From'] = email_address
+ mail["From"] = email_address
if to_address is None:
to_address = removeSecurityProxy(
- self.makePerson()).preferredemail.email
- mail['To'] = to_address
+ self.makePerson()
+ ).preferredemail.email
+ mail["To"] = to_address
if subject is None:
- subject = self.getUniqueString('subject')
- mail['Subject'] = subject
+ subject = self.getUniqueString("subject")
+ mail["Subject"] = subject
if msgid is None:
msgid = self.makeUniqueRFC822MsgId()
if body is None:
- body = self.getUniqueString('body')
- charset = 'ascii'
+ body = self.getUniqueString("body")
+ charset = "ascii"
try:
body = body.encode(charset)
except UnicodeEncodeError:
- charset = 'utf-8'
+ charset = "utf-8"
body = body.encode(charset)
- mail['Message-Id'] = msgid
- mail['Date'] = formatdate()
+ mail["Message-Id"] = msgid
+ mail["Date"] = formatdate()
if signing_context is not None:
gpghandler = getUtility(IGPGHandler)
body = gpghandler.signContent(
- body, signing_context.key, signing_context.password,
- signing_context.mode)
+ body,
+ signing_context.key,
+ signing_context.password,
+ signing_context.mode,
+ )
assert body is not None
if attachment_contents is None:
mail.set_payload(body)
@@ -2316,25 +2691,38 @@ class LaunchpadObjectFactory(ObjectFactory):
mail.attach(body_part)
attach_part = EmailMessage()
attach_part.set_payload(attachment_contents)
- attach_part['Content-type'] = 'application/octet-stream'
+ attach_part["Content-type"] = "application/octet-stream"
if force_transfer_encoding:
encode_base64(attach_part)
mail.attach(attach_part)
- mail['Content-type'] = 'multipart/mixed'
- body_part['Content-type'] = 'text/plain'
+ mail["Content-type"] = "multipart/mixed"
+ body_part["Content-type"] = "text/plain"
if force_transfer_encoding:
encode_base64(body_part)
body_part.set_charset(charset)
mail.parsed_bytes = message_as_bytes(mail)
return mail
- def makeSpecification(self, product=None, title=None, distribution=None,
- name=None, summary=None, owner=None,
- status=NewSpecificationDefinitionStatus.NEW,
- implementation_status=None, goal=None, specurl=None,
- assignee=None, drafter=None, approver=None,
- whiteboard=None, milestone=None,
- information_type=None, priority=None):
+ def makeSpecification(
+ self,
+ product=None,
+ title=None,
+ distribution=None,
+ name=None,
+ summary=None,
+ owner=None,
+ status=NewSpecificationDefinitionStatus.NEW,
+ implementation_status=None,
+ goal=None,
+ specurl=None,
+ assignee=None,
+ drafter=None,
+ approver=None,
+ whiteboard=None,
+ milestone=None,
+ information_type=None,
+ priority=None,
+ ):
"""Create and return a new, arbitrary Blueprint.
:param product: The product to make the blueprint on. If one is
@@ -2342,31 +2730,40 @@ class LaunchpadObjectFactory(ObjectFactory):
"""
if distribution and product:
raise AssertionError(
- 'Cannot target a Specification to a distribution and '
- 'a product simultaneously.')
- proprietary = (information_type not in PUBLIC_INFORMATION_TYPES and
- information_type is not None)
- if (product is None and milestone is not None and
- milestone.productseries is not None):
+ "Cannot target a Specification to a distribution and "
+ "a product simultaneously."
+ )
+ proprietary = (
+ information_type not in PUBLIC_INFORMATION_TYPES
+ and information_type is not None
+ )
+ if (
+ product is None
+ and milestone is not None
+ and milestone.productseries is not None
+ ):
product = milestone.productseries.product
if distribution is None and product is None:
if proprietary:
if information_type == InformationType.EMBARGOED:
specification_sharing_policy = (
- SpecificationSharingPolicy.EMBARGOED_OR_PROPRIETARY)
+ SpecificationSharingPolicy.EMBARGOED_OR_PROPRIETARY
+ )
else:
specification_sharing_policy = (
- SpecificationSharingPolicy.PUBLIC_OR_PROPRIETARY)
+ SpecificationSharingPolicy.PUBLIC_OR_PROPRIETARY
+ )
else:
specification_sharing_policy = None
product = self.makeProduct(
- specification_sharing_policy=specification_sharing_policy)
+ specification_sharing_policy=specification_sharing_policy
+ )
if name is None:
- name = self.getUniqueString('name')
+ name = self.getUniqueString("name")
if summary is None:
- summary = self.getUniqueString('summary')
+ summary = self.getUniqueString("summary")
if title is None:
- title = self.getUniqueString('title')
+ title = self.getUniqueString("title")
if owner is None:
owner = self.makePerson()
status_names = NewSpecificationDefinitionStatus.items.mapping.keys()
@@ -2386,15 +2783,18 @@ class LaunchpadObjectFactory(ObjectFactory):
assignee=assignee,
drafter=drafter,
approver=approver,
- target=product or distribution)
+ target=product or distribution,
+ )
naked_spec = removeSecurityProxy(spec)
if priority is not None:
naked_spec.priority = priority
if status.name not in status_names:
# Set the closed status after the status has a sane initial state.
naked_spec.definition_status = status
- if status in (SpecificationDefinitionStatus.OBSOLETE,
- SpecificationDefinitionStatus.SUPERSEDED):
+ if status in (
+ SpecificationDefinitionStatus.OBSOLETE,
+ SpecificationDefinitionStatus.SUPERSEDED,
+ ):
# This is to satisfy a DB constraint of obsolete specs.
naked_spec.completer = owner
naked_spec.date_completed = datetime.now(pytz.UTC)
@@ -2409,17 +2809,24 @@ class LaunchpadObjectFactory(ObjectFactory):
if proprietary:
naked_spec.target._ensurePolicies([information_type])
naked_spec.transitionToInformationType(
- information_type, naked_spec.target.owner)
+ information_type, naked_spec.target.owner
+ )
return spec
makeBlueprint = makeSpecification
- def makeSpecificationWorkItem(self, title=None, specification=None,
- assignee=None, milestone=None, deleted=False,
- status=SpecificationWorkItemStatus.TODO,
- sequence=None):
+ def makeSpecificationWorkItem(
+ self,
+ title=None,
+ specification=None,
+ assignee=None,
+ milestone=None,
+ deleted=False,
+ status=SpecificationWorkItemStatus.TODO,
+ sequence=None,
+ ):
if title is None:
- title = self.getUniqueString('title')
+ title = self.getUniqueString("title")
if specification is None:
product = None
distribution = None
@@ -2427,17 +2834,23 @@ class LaunchpadObjectFactory(ObjectFactory):
product = milestone.product
distribution = milestone.distribution
specification = self.makeSpecification(
- product=product, distribution=distribution)
+ product=product, distribution=distribution
+ )
if sequence is None:
sequence = self.getUniqueInteger()
work_item = removeSecurityProxy(specification).newWorkItem(
- title=title, sequence=sequence, status=status, assignee=assignee,
- milestone=milestone)
+ title=title,
+ sequence=sequence,
+ status=status,
+ assignee=assignee,
+ milestone=milestone,
+ )
work_item.deleted = deleted
return work_item
- def makeQuestion(self, target=None, title=None,
- owner=None, description=None, **kwargs):
+ def makeQuestion(
+ self, target=None, title=None, owner=None, description=None, **kwargs
+ ):
"""Create and return a new, arbitrary Question.
:param target: The IQuestionTarget to make the question on. If one is
@@ -2451,14 +2864,15 @@ class LaunchpadObjectFactory(ObjectFactory):
if target is None:
target = self.makeProduct()
if title is None:
- title = self.getUniqueUnicode('title')
+ title = self.getUniqueUnicode("title")
if owner is None:
owner = target.owner
if description is None:
- description = self.getUniqueUnicode('description')
+ description = self.getUniqueUnicode("description")
with person_logged_in(owner):
question = target.newQuestion(
- owner=owner, title=title, description=description, **kwargs)
+ owner=owner, title=title, description=description, **kwargs
+ )
return question
def makeQuestionSubscription(self, question=None, person=None):
@@ -2481,9 +2895,10 @@ class LaunchpadObjectFactory(ObjectFactory):
if target is None:
target = self.makeProduct()
if title is None:
- title = self.getUniqueString('title')
+ title = self.getUniqueString("title")
return target.newFAQ(
- owner=target.owner, title=title, content='content')
+ owner=target.owner, title=title, content="content"
+ )
def makePackageCodeImport(self, sourcepackage=None, **kwargs):
"""Make a code import targetting a sourcepackage."""
@@ -2497,12 +2912,21 @@ class LaunchpadObjectFactory(ObjectFactory):
product = self.makeProduct()
return self.makeCodeImport(context=product, **kwargs)
- def makeCodeImport(self, svn_branch_url=None, cvs_root=None,
- cvs_module=None, context=None, branch_name=None,
- git_repo_url=None,
- bzr_branch_url=None, registrant=None,
- rcs_type=None, target_rcs_type=None,
- review_status=None, owner=None):
+ def makeCodeImport(
+ self,
+ svn_branch_url=None,
+ cvs_root=None,
+ cvs_module=None,
+ context=None,
+ branch_name=None,
+ git_repo_url=None,
+ bzr_branch_url=None,
+ registrant=None,
+ rcs_type=None,
+ target_rcs_type=None,
+ review_status=None,
+ owner=None,
+ ):
"""Create and return a new, arbitrary code import.
The type of code import will be inferred from the source details
@@ -2512,8 +2936,14 @@ class LaunchpadObjectFactory(ObjectFactory):
"""
if target_rcs_type is None:
target_rcs_type = TargetRevisionControlSystems.BZR
- if (svn_branch_url is cvs_root is cvs_module is git_repo_url is
- bzr_branch_url is None):
+ if (
+ svn_branch_url
+ is cvs_root
+ is cvs_module
+ is git_repo_url
+ is bzr_branch_url
+ is None
+ ):
if target_rcs_type == TargetRevisionControlSystems.BZR:
svn_branch_url = self.getUniqueURL()
else:
@@ -2522,7 +2952,7 @@ class LaunchpadObjectFactory(ObjectFactory):
if context is None:
context = self.makeProduct()
if branch_name is None:
- branch_name = self.getUniqueUnicode('name')
+ branch_name = self.getUniqueUnicode("name")
if registrant is None:
registrant = self.makePerson()
@@ -2530,31 +2960,51 @@ class LaunchpadObjectFactory(ObjectFactory):
if svn_branch_url is not None:
assert rcs_type in (None, RevisionControlSystems.BZR_SVN)
return code_import_set.new(
- registrant, context, branch_name,
+ registrant,
+ context,
+ branch_name,
rcs_type=RevisionControlSystems.BZR_SVN,
target_rcs_type=target_rcs_type,
- url=svn_branch_url, review_status=review_status, owner=owner)
+ url=svn_branch_url,
+ review_status=review_status,
+ owner=owner,
+ )
elif git_repo_url is not None:
assert rcs_type in (None, RevisionControlSystems.GIT)
return code_import_set.new(
- registrant, context, branch_name,
+ registrant,
+ context,
+ branch_name,
rcs_type=RevisionControlSystems.GIT,
target_rcs_type=target_rcs_type,
- url=git_repo_url, review_status=review_status, owner=owner)
+ url=git_repo_url,
+ review_status=review_status,
+ owner=owner,
+ )
elif bzr_branch_url is not None:
return code_import_set.new(
- registrant, context, branch_name,
+ registrant,
+ context,
+ branch_name,
rcs_type=RevisionControlSystems.BZR,
target_rcs_type=target_rcs_type,
- url=bzr_branch_url, review_status=review_status, owner=owner)
+ url=bzr_branch_url,
+ review_status=review_status,
+ owner=owner,
+ )
else:
assert rcs_type in (None, RevisionControlSystems.CVS)
return code_import_set.new(
- registrant, context, branch_name,
+ registrant,
+ context,
+ branch_name,
rcs_type=RevisionControlSystems.CVS,
target_rcs_type=target_rcs_type,
- cvs_root=cvs_root, cvs_module=cvs_module,
- review_status=review_status, owner=owner)
+ cvs_root=cvs_root,
+ cvs_module=cvs_module,
+ review_status=review_status,
+ owner=owner,
+ )
def makeChangelog(self, spn=None, versions=[]):
"""Create and return a LFA of a valid Debian-style changelog.
@@ -2565,16 +3015,19 @@ class LaunchpadObjectFactory(ObjectFactory):
"""
if spn is None:
spn = self.getUniqueString()
- changelog = ''
+ changelog = ""
for version in versions:
- entry = dedent('''\
+ entry = dedent(
+ """\
%s (%s) unstable; urgency=low
* %s.
-- Føo Bær <foo@xxxxxxxxxxx> Tue, 01 Jan 1970 01:50:41 +0000
- ''' % (spn, version, version))
+ """
+ % (spn, version, version)
+ )
changelog += entry
return self.makeLibraryFileAlias(content=changelog.encode("utf-8"))
@@ -2594,8 +3047,9 @@ class LaunchpadObjectFactory(ObjectFactory):
if code_import is None:
code_import = self.makeCodeImport()
code_import.updateFromData(
- {'review_status': CodeImportReviewStatus.REVIEWED},
- code_import.registrant)
+ {"review_status": CodeImportReviewStatus.REVIEWED},
+ code_import.registrant,
+ )
return code_import.import_job
def makeCodeImportMachine(self, set_online=False, hostname=None):
@@ -2603,7 +3057,7 @@ class LaunchpadObjectFactory(ObjectFactory):
The machine will be in the OFFLINE state."""
if hostname is None:
- hostname = self.getUniqueUnicode('machine-')
+ hostname = self.getUniqueUnicode("machine-")
if set_online:
state = CodeImportMachineState.ONLINE
else:
@@ -2611,10 +3065,17 @@ class LaunchpadObjectFactory(ObjectFactory):
machine = getUtility(ICodeImportMachineSet).new(hostname, state)
return machine
- def makeCodeImportResult(self, code_import=None, result_status=None,
- date_started=None, date_finished=None,
- log_excerpt=None, log_alias=None, machine=None,
- requesting_user=None):
+ def makeCodeImportResult(
+ self,
+ code_import=None,
+ result_status=None,
+ date_started=None,
+ date_finished=None,
+ log_excerpt=None,
+ log_alias=None,
+ machine=None,
+ requesting_user=None,
+ ):
"""Create and return a new CodeImportResult."""
if code_import is None:
code_import = self.makeCodeImport()
@@ -2636,32 +3097,55 @@ class LaunchpadObjectFactory(ObjectFactory):
if log_alias is None:
log_alias = self.makeLibraryFileAlias()
return getUtility(ICodeImportResultSet).new(
- code_import, machine, requesting_user, log_excerpt, log_alias,
- result_status, date_started, date_finished)
+ code_import,
+ machine,
+ requesting_user,
+ log_excerpt,
+ log_alias,
+ result_status,
+ date_started,
+ date_finished,
+ )
- def makeCodeReviewComment(self, sender=None, subject=None, body=None,
- vote=None, vote_tag=None, parent=None,
- merge_proposal=None, date_created=DEFAULT,
- git=False):
+ def makeCodeReviewComment(
+ self,
+ sender=None,
+ subject=None,
+ body=None,
+ vote=None,
+ vote_tag=None,
+ parent=None,
+ merge_proposal=None,
+ date_created=DEFAULT,
+ git=False,
+ ):
if sender is None:
sender = self.makePerson()
if subject is None:
- subject = self.getUniqueString('subject')
+ subject = self.getUniqueString("subject")
if body is None:
- body = self.getUniqueString('content')
+ body = self.getUniqueString("content")
if merge_proposal is None:
if parent:
merge_proposal = parent.branch_merge_proposal
elif git:
merge_proposal = self.makeBranchMergeProposalForGit(
- registrant=sender)
+ registrant=sender
+ )
else:
merge_proposal = self.makeBranchMergeProposal(
- registrant=sender)
+ registrant=sender
+ )
with person_logged_in(sender):
return merge_proposal.createComment(
- sender, subject, body, vote, vote_tag, parent,
- _date_created=date_created)
+ sender,
+ subject,
+ body,
+ vote,
+ vote_tag,
+ parent,
+ _date_created=date_created,
+ )
def makeCodeReviewVoteReference(self, git=False):
if git:
@@ -2671,8 +3155,14 @@ class LaunchpadObjectFactory(ObjectFactory):
candidate = self.makePerson()
return bmp.nominateReviewer(candidate, bmp.registrant)
- def makeMessage(self, subject=None, content=None, parent=None,
- owner=None, datecreated=None):
+ def makeMessage(
+ self,
+ subject=None,
+ content=None,
+ parent=None,
+ owner=None,
+ datecreated=None,
+ ):
if subject is None:
subject = self.getUniqueString()
if content is None:
@@ -2682,27 +3172,40 @@ class LaunchpadObjectFactory(ObjectFactory):
if datecreated is None:
datecreated = datetime.now(UTC)
rfc822msgid = self.makeUniqueRFC822MsgId()
- message = Message(rfc822msgid=rfc822msgid, subject=subject,
- owner=owner, parent=parent, datecreated=datecreated)
+ message = Message(
+ rfc822msgid=rfc822msgid,
+ subject=subject,
+ owner=owner,
+ parent=parent,
+ datecreated=datecreated,
+ )
MessageChunk(message=message, sequence=1, content=content)
return message
- def makeLanguage(self, language_code=None, name=None, pluralforms=None,
- plural_expression=None):
+ def makeLanguage(
+ self,
+ language_code=None,
+ name=None,
+ pluralforms=None,
+ plural_expression=None,
+ ):
"""Makes a language given the language_code and name."""
if language_code is None:
- language_code = self.getUniqueString('lang')
+ language_code = self.getUniqueString("lang")
if name is None:
name = "Language %s" % language_code
if plural_expression is None and pluralforms is not None:
# If the number of plural forms is known, the language
# should also have a plural expression and vice versa.
- plural_expression = 'n %% %d' % pluralforms
+ plural_expression = "n %% %d" % pluralforms
language_set = getUtility(ILanguageSet)
return language_set.createLanguage(
- language_code, name, pluralforms=pluralforms,
- pluralexpression=plural_expression)
+ language_code,
+ name,
+ pluralforms=pluralforms,
+ pluralexpression=plural_expression,
+ )
def makeLanguagePack(self, distroseries=None, languagepack_type=None):
"""Create a language pack."""
@@ -2711,14 +3214,21 @@ class LaunchpadObjectFactory(ObjectFactory):
if languagepack_type is None:
languagepack_type = LanguagePackType.FULL
return getUtility(ILanguagePackSet).addLanguagePack(
- distroseries, self.makeLibraryFileAlias(), languagepack_type)
+ distroseries, self.makeLibraryFileAlias(), languagepack_type
+ )
- def makeLibraryFileAlias(self, filename=None, content=None,
- content_type='text/plain', restricted=False,
- expires=None, db_only=False):
+ def makeLibraryFileAlias(
+ self,
+ filename=None,
+ content=None,
+ content_type="text/plain",
+ restricted=False,
+ expires=None,
+ db_only=False,
+ ):
"""Make a library file, and return the alias."""
if filename is None:
- filename = self.getUniqueString('filename')
+ filename = self.getUniqueString("filename")
if content is None:
content = self.getUniqueBytes()
else:
@@ -2731,25 +3241,46 @@ class LaunchpadObjectFactory(ObjectFactory):
filesize=len(content),
sha256=hashlib.sha256(content).hexdigest(),
sha1=hashlib.sha1(content).hexdigest(),
- md5=hashlib.md5(content).hexdigest())
+ md5=hashlib.md5(content).hexdigest(),
+ )
lfa = LibraryFileAlias(
- content=lfc, filename=filename, mimetype=content_type)
+ content=lfc, filename=filename, mimetype=content_type
+ )
else:
lfa = getUtility(ILibraryFileAliasSet).create(
- filename, len(content), BytesIO(content), content_type,
- expires=expires, restricted=restricted)
+ filename,
+ len(content),
+ BytesIO(content),
+ content_type,
+ expires=expires,
+ restricted=restricted,
+ )
return lfa
- def makeDistribution(self, name=None, displayname=None, owner=None,
- registrant=None, members=None, title=None,
- aliases=None, bug_supervisor=None, driver=None,
- publish_root_dir=None, publish_base_url=None,
- publish_copy_base_url=None, no_pubconf=False,
- icon=None, summary=None, vcs=None,
- oci_project_admin=None, bug_sharing_policy=None,
- branch_sharing_policy=None,
- specification_sharing_policy=None,
- information_type=None):
+ def makeDistribution(
+ self,
+ name=None,
+ displayname=None,
+ owner=None,
+ registrant=None,
+ members=None,
+ title=None,
+ aliases=None,
+ bug_supervisor=None,
+ driver=None,
+ publish_root_dir=None,
+ publish_base_url=None,
+ publish_copy_base_url=None,
+ no_pubconf=False,
+ icon=None,
+ summary=None,
+ vcs=None,
+ oci_project_admin=None,
+ bug_sharing_policy=None,
+ branch_sharing_policy=None,
+ specification_sharing_policy=None,
+ information_type=None,
+ ):
"""Make a new distribution."""
if name is None:
name = self.getUniqueString(prefix="distribution")
@@ -2768,9 +3299,19 @@ class LaunchpadObjectFactory(ObjectFactory):
if members is None:
members = self.makeTeam(owner)
distro = getUtility(IDistributionSet).new(
- name, displayname, title, description, summary, domainname,
- members, owner, registrant, icon=icon, vcs=vcs,
- information_type=information_type)
+ name,
+ displayname,
+ title,
+ description,
+ summary,
+ domainname,
+ members,
+ owner,
+ registrant,
+ icon=icon,
+ vcs=vcs,
+ information_type=information_type,
+ )
naked_distro = removeSecurityProxy(distro)
if aliases is not None:
naked_distro.setAliases(aliases)
@@ -2785,13 +3326,21 @@ class LaunchpadObjectFactory(ObjectFactory):
# complimentary commercial subscription. However, Distribution
# doesn't have a licenses field, so deal with the commercial
# subscription directly here instead.
- if ((bug_sharing_policy is not None and
- bug_sharing_policy != BugSharingPolicy.PUBLIC) or
- (branch_sharing_policy is not None and
- branch_sharing_policy != BranchSharingPolicy.PUBLIC) or
- (specification_sharing_policy is not None and
- specification_sharing_policy !=
- SpecificationSharingPolicy.PUBLIC)):
+ if (
+ (
+ bug_sharing_policy is not None
+ and bug_sharing_policy != BugSharingPolicy.PUBLIC
+ )
+ or (
+ branch_sharing_policy is not None
+ and branch_sharing_policy != BranchSharingPolicy.PUBLIC
+ )
+ or (
+ specification_sharing_policy is not None
+ and specification_sharing_policy
+ != SpecificationSharingPolicy.PUBLIC
+ )
+ ):
naked_distro._ensure_complimentary_subscription()
if branch_sharing_policy:
naked_distro.setBranchSharingPolicy(branch_sharing_policy)
@@ -2799,17 +3348,27 @@ class LaunchpadObjectFactory(ObjectFactory):
naked_distro.setBugSharingPolicy(bug_sharing_policy)
if specification_sharing_policy:
naked_distro.setSpecificationSharingPolicy(
- specification_sharing_policy)
+ specification_sharing_policy
+ )
if not no_pubconf:
self.makePublisherConfig(
- distro, publish_root_dir, publish_base_url,
- publish_copy_base_url)
+ distro,
+ publish_root_dir,
+ publish_base_url,
+ publish_copy_base_url,
+ )
return distro
- def makeDistroSeries(self, distribution=None, version=None,
- status=SeriesStatus.DEVELOPMENT,
- previous_series=None, name=None, displayname=None,
- registrant=None):
+ def makeDistroSeries(
+ self,
+ distribution=None,
+ version=None,
+ status=SeriesStatus.DEVELOPMENT,
+ previous_series=None,
+ name=None,
+ displayname=None,
+ registrant=None,
+ ):
"""Make a new `DistroSeries`."""
if distribution is None:
distribution = self.makeDistribution()
@@ -2829,95 +3388,120 @@ class LaunchpadObjectFactory(ObjectFactory):
version=version,
name=name,
display_name=displayname,
- title=self.getUniqueString(), summary=self.getUniqueString(),
+ title=self.getUniqueString(),
+ summary=self.getUniqueString(),
description=self.getUniqueString(),
- previous_series=previous_series, registrant=registrant)
+ previous_series=previous_series,
+ registrant=registrant,
+ )
series.status = status
return ProxyFactory(series)
- def makeUbuntuDistroSeries(self, version=None,
- status=SeriesStatus.DEVELOPMENT,
- previous_series=None, name=None,
- displayname=None):
+ def makeUbuntuDistroSeries(
+ self,
+ version=None,
+ status=SeriesStatus.DEVELOPMENT,
+ previous_series=None,
+ name=None,
+ displayname=None,
+ ):
"""Short cut to use the celebrity 'ubuntu' as the distribution."""
ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
return self.makeDistroSeries(
- ubuntu, version, status, previous_series, name, displayname)
+ ubuntu, version, status, previous_series, name, displayname
+ )
def makeDistroSeriesDifference(
- self, derived_series=None, source_package_name_str=None,
+ self,
+ derived_series=None,
+ source_package_name_str=None,
versions=None,
difference_type=DistroSeriesDifferenceType.DIFFERENT_VERSIONS,
status=DistroSeriesDifferenceStatus.NEEDS_ATTENTION,
- changelogs=None, set_base_version=False, parent_series=None):
+ changelogs=None,
+ set_base_version=False,
+ parent_series=None,
+ ):
"""Create a new distro series source package difference."""
if derived_series is None:
- dsp = self.makeDistroSeriesParent(
- parent_series=parent_series)
+ dsp = self.makeDistroSeriesParent(parent_series=parent_series)
derived_series = dsp.derived_series
parent_series = dsp.parent_series
else:
if parent_series is None:
dsp = getUtility(IDistroSeriesParentSet).getByDerivedSeries(
- derived_series)
+ derived_series
+ )
if dsp.is_empty():
new_dsp = self.makeDistroSeriesParent(
derived_series=derived_series,
- parent_series=parent_series)
+ parent_series=parent_series,
+ )
parent_series = new_dsp.parent_series
else:
parent_series = dsp[0].parent_series
if source_package_name_str is None:
- source_package_name_str = self.getUniqueString('src-name')
+ source_package_name_str = self.getUniqueString("src-name")
source_package_name = self.getOrMakeSourcePackageName(
- source_package_name_str)
+ source_package_name_str
+ )
if versions is None:
versions = {}
if changelogs is None:
changelogs = {}
- base_version = versions.get('base')
+ base_version = versions.get("base")
if base_version is not None:
for series in [derived_series, parent_series]:
spr = self.makeSourcePackageRelease(
- sourcepackagename=source_package_name,
- version=base_version)
+ sourcepackagename=source_package_name, version=base_version
+ )
self.makeSourcePackagePublishingHistory(
- distroseries=series, sourcepackagerelease=spr,
- status=PackagePublishingStatus.SUPERSEDED)
+ distroseries=series,
+ sourcepackagerelease=spr,
+ status=PackagePublishingStatus.SUPERSEDED,
+ )
if difference_type is not (
- DistroSeriesDifferenceType.MISSING_FROM_DERIVED_SERIES):
+ DistroSeriesDifferenceType.MISSING_FROM_DERIVED_SERIES
+ ):
spr = self.makeSourcePackageRelease(
sourcepackagename=source_package_name,
- version=versions.get('derived'),
- changelog=changelogs.get('derived'))
+ version=versions.get("derived"),
+ changelog=changelogs.get("derived"),
+ )
self.makeSourcePackagePublishingHistory(
- distroseries=derived_series, sourcepackagerelease=spr,
- status=PackagePublishingStatus.PUBLISHED)
+ distroseries=derived_series,
+ sourcepackagerelease=spr,
+ status=PackagePublishingStatus.PUBLISHED,
+ )
if difference_type is not (
- DistroSeriesDifferenceType.UNIQUE_TO_DERIVED_SERIES):
+ DistroSeriesDifferenceType.UNIQUE_TO_DERIVED_SERIES
+ ):
spr = self.makeSourcePackageRelease(
sourcepackagename=source_package_name,
- version=versions.get('parent'),
- changelog=changelogs.get('parent'))
+ version=versions.get("parent"),
+ changelog=changelogs.get("parent"),
+ )
self.makeSourcePackagePublishingHistory(
distroseries=parent_series,
sourcepackagerelease=spr,
- status=PackagePublishingStatus.PUBLISHED)
+ status=PackagePublishingStatus.PUBLISHED,
+ )
diff = getUtility(IDistroSeriesDifferenceSource).new(
- derived_series, source_package_name, parent_series)
+ derived_series, source_package_name, parent_series
+ )
removeSecurityProxy(diff).status = status
if set_base_version:
- version = versions.get('base', "%s.0" % self.getUniqueInteger())
+ version = versions.get("base", "%s.0" % self.getUniqueInteger())
removeSecurityProxy(diff).base_version = version
# We clear the cache on the diff, returning the object as if it
@@ -2926,33 +3510,53 @@ class LaunchpadObjectFactory(ObjectFactory):
return diff
def makeDistroSeriesDifferenceComment(
- self, distro_series_difference=None, owner=None, comment=None):
+ self, distro_series_difference=None, owner=None, comment=None
+ ):
"""Create a new distro series difference comment."""
if distro_series_difference is None:
distro_series_difference = self.makeDistroSeriesDifference()
if owner is None:
owner = self.makePerson()
if comment is None:
- comment = self.getUniqueString('dsdcomment')
+ comment = self.getUniqueString("dsdcomment")
return getUtility(IDistroSeriesDifferenceCommentSource).new(
- distro_series_difference, owner, comment)
+ distro_series_difference, owner, comment
+ )
- def makeDistroSeriesParent(self, derived_series=None, parent_series=None,
- initialized=False, is_overlay=False,
- inherit_overrides=False, pocket=None,
- component=None):
+ def makeDistroSeriesParent(
+ self,
+ derived_series=None,
+ parent_series=None,
+ initialized=False,
+ is_overlay=False,
+ inherit_overrides=False,
+ pocket=None,
+ component=None,
+ ):
if parent_series is None:
parent_series = self.makeDistroSeries()
if derived_series is None:
derived_series = self.makeDistroSeries()
return getUtility(IDistroSeriesParentSet).new(
- derived_series, parent_series, initialized, is_overlay,
- inherit_overrides, pocket, component)
+ derived_series,
+ parent_series,
+ initialized,
+ is_overlay,
+ inherit_overrides,
+ pocket,
+ component,
+ )
- def makeDistroArchSeries(self, distroseries=None,
- architecturetag=None, processor=None,
- official=True, owner=None, enabled=True):
+ def makeDistroArchSeries(
+ self,
+ distroseries=None,
+ architecturetag=None,
+ processor=None,
+ official=True,
+ owner=None,
+ enabled=True,
+ ):
"""Create a new distroarchseries"""
if distroseries is None:
@@ -2965,35 +3569,45 @@ class LaunchpadObjectFactory(ObjectFactory):
# wrong to just make a fresh architecture tag without also making a
# processor to go with it.
if architecturetag is None:
- architecturetag = self.getUniqueString('arch')
+ architecturetag = self.getUniqueString("arch")
return distroseries.newArch(
- architecturetag, processor, official, owner, enabled)
+ architecturetag, processor, official, owner, enabled
+ )
- def makeBuildableDistroArchSeries(self, architecturetag=None,
- processor=None,
- supports_virtualized=True,
- supports_nonvirtualized=True, **kwargs):
+ def makeBuildableDistroArchSeries(
+ self,
+ architecturetag=None,
+ processor=None,
+ supports_virtualized=True,
+ supports_nonvirtualized=True,
+ **kwargs
+ ):
if architecturetag is None:
architecturetag = self.getUniqueUnicode("arch")
if processor is None:
try:
processor = getUtility(IProcessorSet).getByName(
- architecturetag)
+ architecturetag
+ )
except ProcessorNotFound:
processor = self.makeProcessor(
name=architecturetag,
supports_virtualized=supports_virtualized,
- supports_nonvirtualized=supports_nonvirtualized)
+ supports_nonvirtualized=supports_nonvirtualized,
+ )
das = self.makeDistroArchSeries(
- architecturetag=architecturetag, processor=processor, **kwargs)
+ architecturetag=architecturetag, processor=processor, **kwargs
+ )
# Add both a chroot and a LXD image to test that
# getAllowedArchitectures doesn't get confused by multiple
# PocketChroot rows for a single DistroArchSeries.
fake_chroot = self.makeLibraryFileAlias(
- filename="fake_chroot.tar.gz", db_only=True)
+ filename="fake_chroot.tar.gz", db_only=True
+ )
das.addOrUpdateChroot(fake_chroot)
fake_lxd = self.makeLibraryFileAlias(
- filename="fake_lxd.tar.gz", db_only=True)
+ filename="fake_lxd.tar.gz", db_only=True
+ )
das.addOrUpdateChroot(fake_lxd, image_type=BuildBaseImageType.LXD)
return das
@@ -3018,17 +3632,27 @@ class LaunchpadObjectFactory(ObjectFactory):
component = self.makeComponent(component)
selection = ComponentSelection(
- distroseries=distroseries, component=component)
+ distroseries=distroseries, component=component
+ )
del get_property_cache(distroseries).components
return selection
- def makeArchive(self, distribution=None, owner=None, name=None,
- purpose=None, enabled=True, private=False,
- virtualized=True, description=None, displayname=None,
- suppress_subscription_notifications=False,
- processors=None,
- publishing_method=ArchivePublishingMethod.LOCAL,
- repository_format=ArchiveRepositoryFormat.DEBIAN):
+ def makeArchive(
+ self,
+ distribution=None,
+ owner=None,
+ name=None,
+ purpose=None,
+ enabled=True,
+ private=False,
+ virtualized=True,
+ description=None,
+ displayname=None,
+ suppress_subscription_notifications=False,
+ processors=None,
+ publishing_method=ArchivePublishingMethod.LOCAL,
+ repository_format=ArchiveRepositoryFormat.DEBIAN,
+ ):
"""Create and return a new arbitrary archive.
:param distribution: Supply IDistribution, defaults to a new one
@@ -3076,12 +3700,18 @@ class LaunchpadObjectFactory(ObjectFactory):
admins = getUtility(ILaunchpadCelebrities).admin
with person_logged_in(admins.teamowner):
archive = getUtility(IArchiveSet).new(
- owner=owner, purpose=purpose,
- distribution=distribution, name=name, displayname=displayname,
- enabled=enabled, require_virtualized=virtualized,
- description=description, processors=processors,
+ owner=owner,
+ purpose=purpose,
+ distribution=distribution,
+ name=name,
+ displayname=displayname,
+ enabled=enabled,
+ require_virtualized=virtualized,
+ description=description,
+ processors=processors,
publishing_method=publishing_method,
- repository_format=repository_format)
+ repository_format=repository_format,
+ )
if private:
naked_archive = removeSecurityProxy(archive)
@@ -3106,11 +3736,17 @@ class LaunchpadObjectFactory(ObjectFactory):
person = self.makePerson()
permission_set = getUtility(IArchivePermissionSet)
- permission_set.newQueueAdmin(archive, person, 'main')
+ permission_set.newQueueAdmin(archive, person, "main")
return person
- def makeArchiveFile(self, archive=None, container=None, path=None,
- library_file=None, scheduled_deletion_date=None):
+ def makeArchiveFile(
+ self,
+ archive=None,
+ container=None,
+ path=None,
+ library_file=None,
+ scheduled_deletion_date=None,
+ ):
if archive is None:
archive = self.makeArchive()
if container is None:
@@ -3120,16 +3756,30 @@ class LaunchpadObjectFactory(ObjectFactory):
if library_file is None:
library_file = self.makeLibraryFileAlias()
archive_file = getUtility(IArchiveFileSet).new(
- archive=archive, container=container, path=path,
- library_file=library_file)
+ archive=archive,
+ container=container,
+ path=path,
+ library_file=library_file,
+ )
if scheduled_deletion_date is not None:
- removeSecurityProxy(archive_file).scheduled_deletion_date = (
- scheduled_deletion_date)
+ removeSecurityProxy(
+ archive_file
+ ).scheduled_deletion_date = scheduled_deletion_date
return archive_file
- def makeBuilder(self, processors=None, url=None, name=None, title=None,
- owner=None, active=True, virtualized=True, vm_host=None,
- vm_reset_protocol=None, manual=False):
+ def makeBuilder(
+ self,
+ processors=None,
+ url=None,
+ name=None,
+ title=None,
+ owner=None,
+ active=True,
+ virtualized=True,
+ vm_host=None,
+ vm_reset_protocol=None,
+ manual=False,
+ ):
"""Make a new builder for i386 virtualized builds by default.
Note: the builder returned will not be able to actually build -
@@ -3137,13 +3787,13 @@ class LaunchpadObjectFactory(ObjectFactory):
test environment.
"""
if processors is None:
- processors = [getUtility(IProcessorSet).getByName('386')]
+ processors = [getUtility(IProcessorSet).getByName("386")]
if url is None:
- url = 'http://%s:8221/' % self.getUniqueUnicode()
+ url = "http://%s:8221/" % self.getUniqueUnicode()
if name is None:
- name = self.getUniqueUnicode('builder-name')
+ name = self.getUniqueUnicode("builder-name")
if title is None:
- title = self.getUniqueUnicode('builder-title')
+ title = self.getUniqueUnicode("builder-title")
if owner is None:
owner = self.makePerson()
if virtualized and vm_reset_protocol is None:
@@ -3151,13 +3801,21 @@ class LaunchpadObjectFactory(ObjectFactory):
with admin_logged_in():
return getUtility(IBuilderSet).new(
- processors, url, name, title, owner, active,
- virtualized, vm_host, manual=manual,
- vm_reset_protocol=vm_reset_protocol)
+ processors,
+ url,
+ name,
+ title,
+ owner,
+ active,
+ virtualized,
+ vm_host,
+ manual=manual,
+ vm_reset_protocol=vm_reset_protocol,
+ )
def makeRecipeText(self, *branches):
if len(branches) == 0:
- branches = (self.makeAnyBranch(), )
+ branches = (self.makeAnyBranch(),)
base_branch = branches[0]
other_branches = branches[1:]
if IBranch.providedBy(base_branch):
@@ -3168,19 +3826,27 @@ class LaunchpadObjectFactory(ObjectFactory):
# which is equivalent to the repository's default branch. This
# makes that mode easier to test.
text = "%s\n%s\n" % (
- MINIMAL_RECIPE_TEXT_GIT.splitlines()[0], base_branch.identity)
+ MINIMAL_RECIPE_TEXT_GIT.splitlines()[0],
+ base_branch.identity,
+ )
elif IGitRef.providedBy(base_branch):
text = MINIMAL_RECIPE_TEXT_GIT % (
- base_branch.repository.identity, base_branch.name)
+ base_branch.repository.identity,
+ base_branch.name,
+ )
else:
raise AssertionError(
- "Unsupported base_branch: %r" % (base_branch,))
+ "Unsupported base_branch: %r" % (base_branch,)
+ )
for i, branch in enumerate(other_branches):
if IBranch.providedBy(branch) or IGitRepository.providedBy(branch):
- text += 'merge dummy-%s %s\n' % (i, branch.identity)
+ text += "merge dummy-%s %s\n" % (i, branch.identity)
elif IGitRef.providedBy(branch):
- text += 'merge dummy-%s %s %s\n' % (
- i, branch.repository.identity, branch.name)
+ text += "merge dummy-%s %s %s\n" % (
+ i,
+ branch.repository.identity,
+ branch.name,
+ )
else:
raise AssertionError("Unsupported branch: %r" % (branch,))
return text
@@ -3192,6 +3858,7 @@ class LaunchpadObjectFactory(ObjectFactory):
arbitrary branch.
"""
from breezy.plugins.builder.recipe import RecipeParser
+
parser = RecipeParser(self.makeRecipeText(*branches))
return parser.parse()
@@ -3201,15 +3868,23 @@ class LaunchpadObjectFactory(ObjectFactory):
Ew. This uses sampledata currently, which is the ONLY reason this
method exists: it gives us a migration path away from sampledata.
"""
- ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
+ ubuntu = getUtility(IDistributionSet).getByName("ubuntu")
return ubuntu.getSeries(name)
- def makeSourcePackageRecipe(self, registrant=None, owner=None,
- distroseries=None, name=None,
- description=None, branches=(),
- build_daily=False, daily_build_archive=None,
- is_stale=None, recipe=None,
- date_created=DEFAULT):
+ def makeSourcePackageRecipe(
+ self,
+ registrant=None,
+ owner=None,
+ distroseries=None,
+ name=None,
+ description=None,
+ branches=(),
+ build_daily=False,
+ daily_build_archive=None,
+ is_stale=None,
+ recipe=None,
+ date_created=DEFAULT,
+ ):
"""Make a `SourcePackageRecipe`."""
if registrant is None:
registrant = self.makePerson()
@@ -3219,30 +3894,46 @@ class LaunchpadObjectFactory(ObjectFactory):
distroseries = self.makeSourcePackageRecipeDistroseries()
if name is None:
- name = self.getUniqueUnicode('spr-name')
+ name = self.getUniqueUnicode("spr-name")
if description is None:
- description = self.getUniqueUnicode('spr-description')
+ description = self.getUniqueUnicode("spr-description")
if daily_build_archive is None:
daily_build_archive = self.makeArchive(
- distribution=distroseries.distribution, owner=owner)
+ distribution=distroseries.distribution, owner=owner
+ )
if recipe is None:
recipe = self.makeRecipeText(*branches)
else:
assert branches == ()
source_package_recipe = getUtility(ISourcePackageRecipeSource).new(
- registrant, owner, name, recipe, description, [distroseries],
- daily_build_archive, build_daily, date_created)
+ registrant,
+ owner,
+ name,
+ recipe,
+ description,
+ [distroseries],
+ daily_build_archive,
+ build_daily,
+ date_created,
+ )
if is_stale is not None:
removeSecurityProxy(source_package_recipe).is_stale = is_stale
IStore(source_package_recipe).flush()
return source_package_recipe
- def makeSourcePackageRecipeBuild(self, sourcepackage=None, recipe=None,
- requester=None, archive=None,
- sourcename=None, distroseries=None,
- pocket=None, date_created=None,
- status=BuildStatus.NEEDSBUILD,
- duration=None):
+ def makeSourcePackageRecipeBuild(
+ self,
+ sourcepackage=None,
+ recipe=None,
+ requester=None,
+ archive=None,
+ sourcename=None,
+ distroseries=None,
+ pocket=None,
+ date_created=None,
+ status=BuildStatus.NEEDSBUILD,
+ duration=None,
+ ):
"""Make a new SourcePackageRecipeBuild."""
if recipe is None:
recipe = self.makeSourcePackageRecipe(name=sourcename)
@@ -3250,7 +3941,8 @@ class LaunchpadObjectFactory(ObjectFactory):
archive = self.makeArchive()
if distroseries is None:
distroseries = self.makeDistroSeries(
- distribution=archive.distribution)
+ distribution=archive.distribution
+ )
arch = self.makeDistroArchSeries(distroseries=distroseries)
removeSecurityProxy(distroseries).nominatedarchindep = arch
if requester is None:
@@ -3261,12 +3953,15 @@ class LaunchpadObjectFactory(ObjectFactory):
archive=archive,
requester=requester,
pocket=pocket,
- date_created=date_created)
+ date_created=date_created,
+ )
if duration is not None:
removeSecurityProxy(spr_build).updateStatus(
- BuildStatus.BUILDING, date_started=spr_build.date_created)
+ BuildStatus.BUILDING, date_started=spr_build.date_created
+ )
removeSecurityProxy(spr_build).updateStatus(
- status, date_finished=spr_build.date_started + duration)
+ status, date_finished=spr_build.date_started + duration
+ )
else:
removeSecurityProxy(spr_build).updateStatus(status)
IStore(spr_build).flush()
@@ -3284,18 +3979,29 @@ class LaunchpadObjectFactory(ObjectFactory):
jobset = getUtility(ITranslationTemplatesBuildSource)
return jobset.create(branch)
- def makePOTemplate(self, productseries=None, distroseries=None,
- sourcepackagename=None, owner=None, name=None,
- translation_domain=None, path=None,
- copy_pofiles=True, side=None, sourcepackage=None,
- iscurrent=True):
+ def makePOTemplate(
+ self,
+ productseries=None,
+ distroseries=None,
+ sourcepackagename=None,
+ owner=None,
+ name=None,
+ translation_domain=None,
+ path=None,
+ copy_pofiles=True,
+ side=None,
+ sourcepackage=None,
+ iscurrent=True,
+ ):
"""Make a new translation template."""
if sourcepackage is not None:
- assert distroseries is None, (
- 'Cannot specify sourcepackage and distroseries')
+ assert (
+ distroseries is None
+ ), "Cannot specify sourcepackage and distroseries"
distroseries = sourcepackage.distroseries
- assert sourcepackagename is None, (
- 'Cannot specify sourcepackage and sourcepackagename')
+ assert (
+ sourcepackagename is None
+ ), "Cannot specify sourcepackage and sourcepackagename"
sourcepackagename = sourcepackage.sourcepackagename
if productseries is None and distroseries is None:
if side != TranslationSide.UBUNTU:
@@ -3305,7 +4011,8 @@ class LaunchpadObjectFactory(ObjectFactory):
# to us creating a template for it.
naked_series = removeSecurityProxy(productseries)
naked_series.product.translations_usage = (
- ServiceUsage.LAUNCHPAD)
+ ServiceUsage.LAUNCHPAD
+ )
else:
distroseries = self.makeUbuntuDistroSeries()
if distroseries is not None and sourcepackagename is None:
@@ -3313,7 +4020,8 @@ class LaunchpadObjectFactory(ObjectFactory):
templateset = getUtility(IPOTemplateSet)
subset = templateset.getSubset(
- distroseries, sourcepackagename, productseries)
+ distroseries, sourcepackagename, productseries
+ )
if name is None:
name = self.getUniqueString()
@@ -3327,7 +4035,7 @@ class LaunchpadObjectFactory(ObjectFactory):
owner = productseries.owner
if path is None:
- path = 'messages.pot'
+ path = "messages.pot"
pot = subset.new(name, translation_domain, path, owner, copy_pofiles)
removeSecurityProxy(pot).iscurrent = iscurrent
@@ -3345,11 +4053,19 @@ class LaunchpadObjectFactory(ObjectFactory):
self.makePOFile(language_code, template, template.owner)
return template
- def makePOFile(self, language_code=None, potemplate=None, owner=None,
- create_sharing=False, language=None, side=None):
+ def makePOFile(
+ self,
+ language_code=None,
+ potemplate=None,
+ owner=None,
+ create_sharing=False,
+ language=None,
+ side=None,
+ ):
"""Make a new translation file."""
- assert language_code is None or language is None, (
- "Please specify only one of language_code and language.")
+ assert (
+ language_code is None or language is None
+ ), "Please specify only one of language_code and language."
if language_code is None:
if language is None:
language = self.makeLanguage()
@@ -3357,14 +4073,23 @@ class LaunchpadObjectFactory(ObjectFactory):
if potemplate is None:
potemplate = self.makePOTemplate(owner=owner, side=side)
else:
- assert side is None, 'Cannot specify both side and potemplate.'
- return potemplate.newPOFile(language_code,
- create_sharing=create_sharing)
-
- def makePOTMsgSet(self, potemplate=None, singular=None, plural=None,
- context=None, sequence=None, commenttext=None,
- filereferences=None, sourcecomment=None,
- flagscomment=None):
+ assert side is None, "Cannot specify both side and potemplate."
+ return potemplate.newPOFile(
+ language_code, create_sharing=create_sharing
+ )
+
+ def makePOTMsgSet(
+ self,
+ potemplate=None,
+ singular=None,
+ plural=None,
+ context=None,
+ sequence=None,
+ commenttext=None,
+ filereferences=None,
+ sourcecomment=None,
+ flagscomment=None,
+ ):
"""Make a new `POTMsgSet` in the given template."""
if potemplate is None:
potemplate = self.makePOTemplate()
@@ -3373,7 +4098,8 @@ class LaunchpadObjectFactory(ObjectFactory):
if sequence is None:
sequence = self.getUniqueInteger()
potmsgset = potemplate.createMessageSetFromText(
- singular, plural, context, sequence)
+ singular, plural, context, sequence
+ )
if commenttext is not None:
potmsgset.commenttext = commenttext
if filereferences is not None:
@@ -3385,8 +4111,9 @@ class LaunchpadObjectFactory(ObjectFactory):
removeSecurityProxy(potmsgset).sync()
return potmsgset
- def makePOFileAndPOTMsgSet(self, language_code=None, msgid=None,
- with_plural=False, side=None):
+ def makePOFileAndPOTMsgSet(
+ self, language_code=None, msgid=None, with_plural=False, side=None
+ ):
"""Make a `POFile` with a `POTMsgSet`."""
pofile = self.makePOFile(language_code, side=side)
@@ -3398,7 +4125,8 @@ class LaunchpadObjectFactory(ObjectFactory):
plural = None
potmsgset = self.makePOTMsgSet(
- pofile.potemplate, singular=msgid, plural=plural)
+ pofile.potemplate, singular=msgid, plural=plural
+ )
return pofile, potmsgset
@@ -3414,38 +4142,56 @@ class LaunchpadObjectFactory(ObjectFactory):
return {0: self.getUniqueUnicode()}
if isinstance(translations, dict):
return translations
- assert isinstance(translations, (list, tuple)), (
- "Expecting either a dict or a sequence.")
+ assert isinstance(
+ translations, (list, tuple)
+ ), "Expecting either a dict or a sequence."
return dict(enumerate(translations))
- def makeSuggestion(self, pofile=None, potmsgset=None, translator=None,
- translations=None, date_created=None):
+ def makeSuggestion(
+ self,
+ pofile=None,
+ potmsgset=None,
+ translator=None,
+ translations=None,
+ date_created=None,
+ ):
"""Make a new suggested `TranslationMessage` in the given PO file."""
if pofile is None:
- pofile = self.makePOFile('sr')
+ pofile = self.makePOFile("sr")
if potmsgset is None:
potmsgset = self.makePOTMsgSet(pofile.potemplate)
if translator is None:
translator = self.makePerson()
translations = self.makeTranslationsDict(translations)
translation_message = potmsgset.submitSuggestion(
- pofile, translator, translations)
- assert translation_message is not None, (
- "Cannot make suggestion on translation credits POTMsgSet.")
+ pofile, translator, translations
+ )
+ assert (
+ translation_message is not None
+ ), "Cannot make suggestion on translation credits POTMsgSet."
if date_created is not None:
naked_translation_message = removeSecurityProxy(
- translation_message)
+ translation_message
+ )
naked_translation_message.date_created = date_created
naked_translation_message.sync()
return translation_message
- def makeCurrentTranslationMessage(self, pofile=None, potmsgset=None,
- translator=None, reviewer=None,
- translations=None, diverged=False,
- current_other=False,
- date_created=None, date_reviewed=None,
- language=None, side=None,
- potemplate=None):
+ def makeCurrentTranslationMessage(
+ self,
+ pofile=None,
+ potmsgset=None,
+ translator=None,
+ reviewer=None,
+ translations=None,
+ diverged=False,
+ current_other=False,
+ date_created=None,
+ date_reviewed=None,
+ language=None,
+ side=None,
+ potemplate=None,
+ ):
"""Create a `TranslationMessage` and make it current.
By default the message will only be current on the side (Ubuntu
@@ -3476,35 +4222,40 @@ class LaunchpadObjectFactory(ObjectFactory):
:param potemplate: If provided, the POTemplate to use when creating
the POFile.
"""
- assert not (diverged and current_other), (
- "A diverged message can't be current on the other side.")
- assert None in (language, pofile), (
- 'Cannot specify both language and pofile.')
- assert None in (side, pofile), (
- 'Cannot specify both side and pofile.')
+ assert not (
+ diverged and current_other
+ ), "A diverged message can't be current on the other side."
+ assert None in (
+ language,
+ pofile,
+ ), "Cannot specify both language and pofile."
+ assert None in (side, pofile), "Cannot specify both side and pofile."
link_potmsgset_with_potemplate = (
- (pofile is None and potemplate is None) or potmsgset is None)
+ pofile is None and potemplate is None
+ ) or potmsgset is None
if pofile is None:
pofile = self.makePOFile(
- language=language, side=side, potemplate=potemplate)
+ language=language, side=side, potemplate=potemplate
+ )
else:
- assert potemplate is None, (
- 'Cannot specify both pofile and potemplate')
+ assert (
+ potemplate is None
+ ), "Cannot specify both pofile and potemplate"
potemplate = pofile.potemplate
if potmsgset is None:
potmsgset = self.makePOTMsgSet(potemplate)
if link_potmsgset_with_potemplate:
# If we have a new pofile or a new potmsgset, we must link
# the potmsgset to the pofile's potemplate.
- potmsgset.setSequence(
- pofile.potemplate, self.getUniqueInteger())
+ potmsgset.setSequence(pofile.potemplate, self.getUniqueInteger())
else:
# Otherwise it is the duty of the callsite to ensure
# consistency.
store = IStore(TranslationTemplateItem)
tti_for_message_in_template = store.find(
TranslationTemplateItem.potmsgset == potmsgset,
- TranslationTemplateItem.potemplate == pofile.potemplate).any()
+ TranslationTemplateItem.potemplate == pofile.potemplate,
+ ).any()
assert tti_for_message_in_template is not None
if translator is None:
translator = self.makePerson()
@@ -3513,17 +4264,26 @@ class LaunchpadObjectFactory(ObjectFactory):
translations = sanitize_translations_from_webui(
potmsgset.singular_text,
self.makeTranslationsDict(translations),
- pofile.language.pluralforms)
+ pofile.language.pluralforms,
+ )
if diverged:
message = self.makeDivergedTranslationMessage(
- pofile, potmsgset, translator, reviewer,
- translations, date_created)
+ pofile,
+ potmsgset,
+ translator,
+ reviewer,
+ translations,
+ date_created,
+ )
else:
message = potmsgset.setCurrentTranslation(
- pofile, translator, translations,
+ pofile,
+ translator,
+ translations,
RosettaTranslationOrigin.ROSETTAWEB,
- share_with_other_side=current_other)
+ share_with_other_side=current_other,
+ )
if date_created is not None:
removeSecurityProxy(message).date_created = date_created
@@ -3531,34 +4291,51 @@ class LaunchpadObjectFactory(ObjectFactory):
return message
- def makeDivergedTranslationMessage(self, pofile=None, potmsgset=None,
- translator=None, reviewer=None,
- translations=None, date_created=None):
+ def makeDivergedTranslationMessage(
+ self,
+ pofile=None,
+ potmsgset=None,
+ translator=None,
+ reviewer=None,
+ translations=None,
+ date_created=None,
+ ):
"""Create a diverged, current `TranslationMessage`."""
if pofile is None:
- pofile = self.makePOFile('lt')
+ pofile = self.makePOFile("lt")
if reviewer is None:
reviewer = self.makePerson()
message = self.makeSuggestion(
- pofile=pofile, potmsgset=potmsgset, translator=translator,
- translations=translations, date_created=date_created)
+ pofile=pofile,
+ potmsgset=potmsgset,
+ translator=translator,
+ translations=translations,
+ date_created=date_created,
+ )
return message.approveAsDiverged(pofile, reviewer)
- def makeTranslationImportQueueEntry(self, path=None, productseries=None,
- distroseries=None,
- sourcepackagename=None,
- potemplate=None, content=None,
- uploader=None, pofile=None,
- format=None, status=None,
- by_maintainer=False):
+ def makeTranslationImportQueueEntry(
+ self,
+ path=None,
+ productseries=None,
+ distroseries=None,
+ sourcepackagename=None,
+ potemplate=None,
+ content=None,
+ uploader=None,
+ pofile=None,
+ format=None,
+ status=None,
+ by_maintainer=False,
+ ):
"""Create a `TranslationImportQueueEntry`."""
if path is None:
- path = self.getUniqueUnicode() + '.pot'
+ path = self.getUniqueUnicode() + ".pot"
for_distro = not (distroseries is None and sourcepackagename is None)
for_project = productseries is not None
- has_template = (potemplate is not None)
+ has_template = potemplate is not None
if has_template and not for_distro and not for_project:
# Copy target from template.
distroseries = potemplate.distroseries
@@ -3589,12 +4366,20 @@ class LaunchpadObjectFactory(ObjectFactory):
content = six.ensure_binary(content)
entry = getUtility(ITranslationImportQueue).addOrUpdateEntry(
- path=path, content=content, by_maintainer=by_maintainer,
- importer=uploader, productseries=productseries,
- distroseries=distroseries, sourcepackagename=sourcepackagename,
- potemplate=potemplate, pofile=pofile, format=format)
+ path=path,
+ content=content,
+ by_maintainer=by_maintainer,
+ importer=uploader,
+ productseries=productseries,
+ distroseries=distroseries,
+ sourcepackagename=sourcepackagename,
+ potemplate=potemplate,
+ pofile=pofile,
+ format=format,
+ )
entry.setStatus(
- status, getUtility(ILaunchpadCelebrities).rosetta_experts)
+ status, getUtility(ILaunchpadCelebrities).rosetta_experts
+ )
return entry
def makeMailingList(self, team, owner):
@@ -3605,9 +4390,12 @@ class LaunchpadObjectFactory(ObjectFactory):
return team_list
def makeTeamAndMailingList(
- self, team_name, owner_name,
+ self,
+ team_name,
+ owner_name,
visibility=None,
- membership_policy=TeamMembershipPolicy.OPEN):
+ membership_policy=TeamMembershipPolicy.OPEN,
+ ):
"""Make a new active mailing list for the named team.
:param team_name: The new team's name.
@@ -3624,18 +4412,23 @@ class LaunchpadObjectFactory(ObjectFactory):
"""
owner = getUtility(IPersonSet).getByName(owner_name)
display_name = SPACE.join(
- word.capitalize() for word in team_name.split('-'))
+ word.capitalize() for word in team_name.split("-")
+ )
team = getUtility(IPersonSet).getByName(team_name)
if team is None:
team = self.makeTeam(
- owner, displayname=display_name, name=team_name,
+ owner,
+ displayname=display_name,
+ name=team_name,
visibility=visibility,
- membership_policy=membership_policy)
+ membership_policy=membership_policy,
+ )
team_list = self.makeMailingList(team, owner)
return team, team_list
- def makeTeamWithMailingListSubscribers(self, team_name, super_team=None,
- auto_subscribe=True):
+ def makeTeamWithMailingListSubscribers(
+ self, team_name, super_team=None, auto_subscribe=True
+ ):
"""Create a team, mailing list, and subscribers.
:param team_name: The name of the team to create.
@@ -3646,12 +4439,13 @@ class LaunchpadObjectFactory(ObjectFactory):
"""
team = self.makeTeam(name=team_name)
member = self.makePerson()
- with celebrity_logged_in('admin'):
+ with celebrity_logged_in("admin"):
if super_team is None:
mailing_list = self.makeMailingList(team, team.teamowner)
else:
super_team.addMember(
- team, reviewer=team.teamowner, force_team_add=True)
+ team, reviewer=team.teamowner, force_team_add=True
+ )
mailing_list = super_team.mailing_list
team.addMember(member, reviewer=team.teamowner)
if auto_subscribe:
@@ -3665,15 +4459,26 @@ class LaunchpadObjectFactory(ObjectFactory):
log_file.seek(0)
library_alias = getUtility(ILibraryFileAliasSet).create(
- name='foo', size=len(log_file.getvalue()),
- file=log_file, contentType='text/plain')
+ name="foo",
+ size=len(log_file.getvalue()),
+ file=log_file,
+ contentType="text/plain",
+ )
proberecord = mirror.newProbeRecord(library_alias)
return proberecord
- def makeMirror(self, distribution, displayname=None, country=None,
- http_url=None, https_url=None, ftp_url=None, rsync_url=None,
- official_candidate=False):
+ def makeMirror(
+ self,
+ distribution,
+ displayname=None,
+ country=None,
+ http_url=None,
+ https_url=None,
+ ftp_url=None,
+ rsync_url=None,
+ official_candidate=False,
+ ):
"""Create a mirror for the distribution."""
if displayname is None:
displayname = self.getUniqueString("mirror")
@@ -3682,7 +4487,7 @@ class LaunchpadObjectFactory(ObjectFactory):
http_url = self.getUniqueURL()
# If no country is given use Argentina.
if country is None:
- country = getUtility(ICountrySet)['AR']
+ country = getUtility(ICountrySet)["AR"]
mirror = distribution.newMirror(
owner=distribution.owner,
@@ -3695,7 +4500,8 @@ class LaunchpadObjectFactory(ObjectFactory):
https_base_url=https_url,
ftp_base_url=ftp_url,
rsync_base_url=rsync_url,
- official_candidate=official_candidate)
+ official_candidate=official_candidate,
+ )
return mirror
def makeUniqueRFC822MsgId(self):
@@ -3704,9 +4510,9 @@ class LaunchpadObjectFactory(ObjectFactory):
The created message id is guaranteed not to exist in the
`Message` table already.
"""
- msg_id = make_msgid('launchpad')
+ msg_id = make_msgid("launchpad")
while not Message.selectBy(rfc822msgid=msg_id).is_empty():
- msg_id = make_msgid('launchpad')
+ msg_id = make_msgid("launchpad")
return msg_id
def makeSourcePackageName(self, name=None):
@@ -3725,8 +4531,9 @@ class LaunchpadObjectFactory(ObjectFactory):
return self.makeSourcePackageName()
return getUtility(ISourcePackageNameSet).getOrCreateByName(name)
- def makeSourcePackage(self, sourcepackagename=None, distroseries=None,
- publish=False):
+ def makeSourcePackage(
+ self, sourcepackagename=None, distroseries=None, publish=False
+ ):
"""Make an `ISourcePackage`.
:param publish: if true, create a corresponding
@@ -3735,34 +4542,43 @@ class LaunchpadObjectFactory(ObjectFactory):
# Make sure we have a real sourcepackagename object.
if sourcepackagename is None or isinstance(sourcepackagename, str):
sourcepackagename = self.getOrMakeSourcePackageName(
- sourcepackagename)
+ sourcepackagename
+ )
if distroseries is None:
distroseries = self.makeDistroSeries()
if publish:
self.makeSourcePackagePublishingHistory(
- distroseries=distroseries,
- sourcepackagename=sourcepackagename)
- with dbuser('statistician'):
+ distroseries=distroseries, sourcepackagename=sourcepackagename
+ )
+ with dbuser("statistician"):
DistributionSourcePackageCache(
distribution=distroseries.distribution,
sourcepackagename=sourcepackagename,
archive=distroseries.main_archive,
- name=sourcepackagename.name)
+ name=sourcepackagename.name,
+ )
return distroseries.getSourcePackage(sourcepackagename)
def getAnySourcePackageUrgency(self):
return SourcePackageUrgency.MEDIUM
- def makePackageUpload(self, distroseries=None, archive=None,
- pocket=None, changes_filename=None,
- changes_file_content=None,
- signing_key=None, status=None,
- package_copy_job=None):
+ def makePackageUpload(
+ self,
+ distroseries=None,
+ archive=None,
+ pocket=None,
+ changes_filename=None,
+ changes_file_content=None,
+ signing_key=None,
+ status=None,
+ package_copy_job=None,
+ ):
if archive is None:
archive = self.makeArchive()
if distroseries is None:
distroseries = self.makeDistroSeries(
- distribution=archive.distribution)
+ distribution=archive.distribution
+ )
if changes_filename is None:
changes_filename = self.getUniqueString("changesfilename")
if changes_file_content is None:
@@ -3770,53 +4586,82 @@ class LaunchpadObjectFactory(ObjectFactory):
if pocket is None:
pocket = PackagePublishingPocket.RELEASE
package_upload = distroseries.createQueueEntry(
- pocket, archive, changes_filename, changes_file_content,
- signing_key=signing_key, package_copy_job=package_copy_job)
+ pocket,
+ archive,
+ changes_filename,
+ changes_file_content,
+ signing_key=signing_key,
+ package_copy_job=package_copy_job,
+ )
if status is not None:
if status is not PackageUploadStatus.NEW:
naked_package_upload = removeSecurityProxy(package_upload)
status_changers = {
- PackageUploadStatus.UNAPPROVED:
- naked_package_upload.setUnapproved,
- PackageUploadStatus.REJECTED:
- naked_package_upload.setRejected,
+ PackageUploadStatus.UNAPPROVED: (
+ naked_package_upload.setUnapproved
+ ),
+ PackageUploadStatus.REJECTED: (
+ naked_package_upload.setRejected
+ ),
PackageUploadStatus.DONE: naked_package_upload.setDone,
- PackageUploadStatus.ACCEPTED:
- naked_package_upload.setAccepted,
- }
+ PackageUploadStatus.ACCEPTED: (
+ naked_package_upload.setAccepted
+ ),
+ }
status_changers[status]()
return package_upload
- def makeSourcePackageUpload(self, distroseries=None,
- sourcepackagename=None, component=None):
+ def makeSourcePackageUpload(
+ self, distroseries=None, sourcepackagename=None, component=None
+ ):
"""Make a `PackageUpload` with a `PackageUploadSource` attached."""
if distroseries is None:
distroseries = self.makeDistroSeries()
upload = self.makePackageUpload(
- distroseries=distroseries, archive=distroseries.main_archive)
- upload.addSource(self.makeSourcePackageRelease(
- sourcepackagename=sourcepackagename, component=component))
+ distroseries=distroseries, archive=distroseries.main_archive
+ )
+ upload.addSource(
+ self.makeSourcePackageRelease(
+ sourcepackagename=sourcepackagename, component=component
+ )
+ )
return upload
- def makeBuildPackageUpload(self, distroseries=None, pocket=None,
- binarypackagename=None,
- source_package_release=None, component=None):
+ def makeBuildPackageUpload(
+ self,
+ distroseries=None,
+ pocket=None,
+ binarypackagename=None,
+ source_package_release=None,
+ component=None,
+ ):
"""Make a `PackageUpload` with a `PackageUploadBuild` attached."""
if distroseries is None:
distroseries = self.makeDistroSeries()
upload = self.makePackageUpload(
- distroseries=distroseries, archive=distroseries.main_archive,
- pocket=pocket)
+ distroseries=distroseries,
+ archive=distroseries.main_archive,
+ pocket=pocket,
+ )
build = self.makeBinaryPackageBuild(
- source_package_release=source_package_release, pocket=pocket)
+ source_package_release=source_package_release, pocket=pocket
+ )
self.makeBinaryPackageRelease(
- binarypackagename=binarypackagename, build=build,
- component=component)
+ binarypackagename=binarypackagename,
+ build=build,
+ component=component,
+ )
upload.addBuild(build)
return upload
- def makeCustomPackageUpload(self, distroseries=None, archive=None,
- pocket=None, custom_type=None, filename=None):
+ def makeCustomPackageUpload(
+ self,
+ distroseries=None,
+ archive=None,
+ pocket=None,
+ custom_type=None,
+ filename=None,
+ ):
"""Make a `PackageUpload` with a `PackageUploadCustom` attached."""
if distroseries is None:
distroseries = self.makeDistroSeries()
@@ -3825,20 +4670,27 @@ class LaunchpadObjectFactory(ObjectFactory):
if custom_type is None:
custom_type = PackageUploadCustomFormat.DEBIAN_INSTALLER
upload = self.makePackageUpload(
- distroseries=distroseries, archive=archive, pocket=pocket)
+ distroseries=distroseries, archive=archive, pocket=pocket
+ )
file_alias = self.makeLibraryFileAlias(filename=filename)
upload.addCustom(file_alias, custom_type)
return upload
- def makeCopyJobPackageUpload(self, distroseries=None,
- sourcepackagename=None, source_archive=None,
- target_pocket=None, requester=None,
- include_binaries=False):
+ def makeCopyJobPackageUpload(
+ self,
+ distroseries=None,
+ sourcepackagename=None,
+ source_archive=None,
+ target_pocket=None,
+ requester=None,
+ include_binaries=False,
+ ):
"""Make a `PackageUpload` with a `PackageCopyJob` attached."""
if distroseries is None:
distroseries = self.makeDistroSeries()
spph = self.makeSourcePackagePublishingHistory(
- archive=source_archive, sourcepackagename=sourcepackagename)
+ archive=source_archive, sourcepackagename=sourcepackagename
+ )
spr = spph.sourcepackagerelease
job = self.makePlainPackageCopyJob(
package_name=spr.sourcepackagename.name,
@@ -3846,8 +4698,10 @@ class LaunchpadObjectFactory(ObjectFactory):
source_archive=spph.archive,
target_pocket=target_pocket,
target_archive=distroseries.main_archive,
- target_distroseries=distroseries, requester=requester,
- include_binaries=include_binaries)
+ target_distroseries=distroseries,
+ requester=requester,
+ include_binaries=include_binaries,
+ )
job.addSourceOverride(SourceOverride(spr.component, spr.section))
try:
job.run()
@@ -3857,28 +4711,37 @@ class LaunchpadObjectFactory(ObjectFactory):
upload_set = getUtility(IPackageUploadSet)
return upload_set.getByPackageCopyJobIDs([job.id]).one()
- def makeSourcePackageRelease(self, archive=None, sourcepackagename=None,
- distroseries=None, maintainer=None,
- creator=None, component=None,
- section_name=None, urgency=None,
- version=None, builddepends=None,
- builddependsindep=None,
- build_conflicts=None,
- build_conflicts_indep=None,
- architecturehintlist='all',
- dsc_maintainer_rfc822=None,
- dsc_standards_version='3.6.2',
- dsc_format='1.0', dsc_binaries='foo-bin',
- date_uploaded=UTC_NOW,
- source_package_recipe_build=None,
- ci_build=None,
- dscsigningkey=None,
- user_defined_fields=None,
- changelog_entry=None,
- homepage=None,
- changelog=None,
- copyright=None,
- format=None):
+ def makeSourcePackageRelease(
+ self,
+ archive=None,
+ sourcepackagename=None,
+ distroseries=None,
+ maintainer=None,
+ creator=None,
+ component=None,
+ section_name=None,
+ urgency=None,
+ version=None,
+ builddepends=None,
+ builddependsindep=None,
+ build_conflicts=None,
+ build_conflicts_indep=None,
+ architecturehintlist="all",
+ dsc_maintainer_rfc822=None,
+ dsc_standards_version="3.6.2",
+ dsc_format="1.0",
+ dsc_binaries="foo-bin",
+ date_uploaded=UTC_NOW,
+ source_package_recipe_build=None,
+ ci_build=None,
+ dscsigningkey=None,
+ user_defined_fields=None,
+ changelog_entry=None,
+ homepage=None,
+ changelog=None,
+ copyright=None,
+ format=None,
+ ):
"""Make a `SourcePackageRelease`."""
if distroseries is None:
if source_package_recipe_build is not None:
@@ -3890,17 +4753,17 @@ class LaunchpadObjectFactory(ObjectFactory):
distribution = None
else:
distribution = archive.distribution
- distroseries = self.makeDistroSeries(
- distribution=distribution)
+ distroseries = self.makeDistroSeries(distribution=distribution)
if archive is None:
archive = distroseries.main_archive
if sourcepackagename is None or isinstance(sourcepackagename, str):
sourcepackagename = self.getOrMakeSourcePackageName(
- sourcepackagename)
+ sourcepackagename
+ )
- if (component is None or isinstance(component, str)):
+ if component is None or isinstance(component, str):
component = self.makeComponent(component)
if urgency is None:
@@ -3914,15 +4777,16 @@ class LaunchpadObjectFactory(ObjectFactory):
maintainer = self.makePerson()
if dsc_maintainer_rfc822 is None:
- dsc_maintainer_rfc822 = '%s <%s>' % (
+ dsc_maintainer_rfc822 = "%s <%s>" % (
maintainer.displayname,
- removeSecurityProxy(maintainer).preferredemail.email)
+ removeSecurityProxy(maintainer).preferredemail.email,
+ )
if creator is None:
creator = self.makePerson()
if version is None:
- version = str(self.getUniqueInteger()) + 'version'
+ version = str(self.getUniqueInteger()) + "version"
if format is None:
format = SourcePackageType.DPKG
@@ -3958,10 +4822,12 @@ class LaunchpadObjectFactory(ObjectFactory):
source_package_recipe_build=source_package_recipe_build,
ci_build=ci_build,
user_defined_fields=user_defined_fields,
- homepage=homepage)
+ homepage=homepage,
+ )
- def makeSourcePackageReleaseFile(self, sourcepackagerelease=None,
- library_file=None, filetype=None):
+ def makeSourcePackageReleaseFile(
+ self, sourcepackagerelease=None, library_file=None, filetype=None
+ ):
if sourcepackagerelease is None:
sourcepackagerelease = self.makeSourcePackageRelease()
if library_file is None:
@@ -3969,12 +4835,22 @@ class LaunchpadObjectFactory(ObjectFactory):
if filetype is None:
filetype = SourcePackageFileType.DSC
return ProxyFactory(
- sourcepackagerelease.addFile(library_file, filetype=filetype))
+ sourcepackagerelease.addFile(library_file, filetype=filetype)
+ )
- def makeBinaryPackageBuild(self, source_package_release=None,
- distroarchseries=None, archive=None, builder=None,
- status=None, pocket=None, date_created=None, processor=None,
- sourcepackagename=None, arch_indep=None):
+ def makeBinaryPackageBuild(
+ self,
+ source_package_release=None,
+ distroarchseries=None,
+ archive=None,
+ builder=None,
+ status=None,
+ pocket=None,
+ date_created=None,
+ processor=None,
+ sourcepackagename=None,
+ arch_indep=None,
+ ):
"""Create a BinaryPackageBuild.
If archive is not supplied, the source_package_release is used
@@ -3998,16 +4874,21 @@ class LaunchpadObjectFactory(ObjectFactory):
distroseries = source_package_release.upload_distroseries
elif archive is not None:
distroseries = self.makeDistroSeries(
- distribution=archive.distribution)
+ distribution=archive.distribution
+ )
else:
distroseries = self.makeDistroSeries()
distroarchseries = self.makeDistroArchSeries(
- distroseries=distroseries, processor=processor)
+ distroseries=distroseries, processor=processor
+ )
else:
- if (processor is not None
- and processor != distroarchseries.processor):
+ if (
+ processor is not None
+ and processor != distroarchseries.processor
+ ):
raise AssertionError(
- "DistroArchSeries and Processor must match.")
+ "DistroArchSeries and Processor must match."
+ )
if arch_indep is None:
arch_indep = distroarchseries.isNominatedArchIndep
if archive is None:
@@ -4021,15 +4902,19 @@ class LaunchpadObjectFactory(ObjectFactory):
pocket = PackagePublishingPocket.items[pocket.upper()]
if source_package_release is None:
- multiverse = self.makeComponent(name='multiverse')
+ multiverse = self.makeComponent(name="multiverse")
source_package_release = self.makeSourcePackageRelease(
- archive, component=multiverse,
+ archive,
+ component=multiverse,
distroseries=distroarchseries.distroseries,
- sourcepackagename=sourcepackagename)
+ sourcepackagename=sourcepackagename,
+ )
self.makeSourcePackagePublishingHistory(
distroseries=distroarchseries.distroseries,
- archive=archive, sourcepackagerelease=source_package_release,
- pocket=pocket)
+ archive=archive,
+ sourcepackagerelease=source_package_release,
+ pocket=pocket,
+ )
if status is None:
status = BuildStatus.NEEDSBUILD
admins = getUtility(ILaunchpadCelebrities).admin
@@ -4041,25 +4926,28 @@ class LaunchpadObjectFactory(ObjectFactory):
archive=archive,
pocket=pocket,
builder=builder,
- arch_indep=arch_indep)
+ arch_indep=arch_indep,
+ )
IStore(binary_package_build).flush()
return binary_package_build
- def makeSourcePackagePublishingHistory(self,
- distroseries=None,
- archive=None,
- sourcepackagerelease=None,
- pocket=None,
- status=None,
- dateremoved=None,
- date_uploaded=UTC_NOW,
- scheduleddeletiondate=None,
- ancestor=None,
- creator=None,
- packageupload=None,
- spr_creator=None,
- channel=None,
- **kwargs):
+ def makeSourcePackagePublishingHistory(
+ self,
+ distroseries=None,
+ archive=None,
+ sourcepackagerelease=None,
+ pocket=None,
+ status=None,
+ dateremoved=None,
+ date_uploaded=UTC_NOW,
+ scheduleddeletiondate=None,
+ ancestor=None,
+ creator=None,
+ packageupload=None,
+ spr_creator=None,
+ channel=None,
+ **kwargs
+ ):
"""Make a `SourcePackagePublishingHistory`.
:param sourcepackagerelease: The source package release to publish
@@ -4092,8 +4980,7 @@ class LaunchpadObjectFactory(ObjectFactory):
distribution = None
else:
distribution = archive.distribution
- distroseries = self.makeDistroSeries(
- distribution=distribution)
+ distroseries = self.makeDistroSeries(distribution=distribution)
if archive is None:
archive = distroseries.main_archive
@@ -4109,17 +4996,27 @@ class LaunchpadObjectFactory(ObjectFactory):
if sourcepackagerelease is None:
sourcepackagerelease = self.makeSourcePackageRelease(
- archive=archive, distroseries=distroseries,
- date_uploaded=date_uploaded, creator=spr_creator, **kwargs)
+ archive=archive,
+ distroseries=distroseries,
+ date_uploaded=date_uploaded,
+ creator=spr_creator,
+ **kwargs,
+ )
admins = getUtility(ILaunchpadCelebrities).admin
with person_logged_in(admins.teamowner):
spph = getUtility(IPublishingSet).newSourcePublication(
- archive, sourcepackagerelease, distroseries, pocket,
+ archive,
+ sourcepackagerelease,
+ distroseries,
+ pocket,
component=sourcepackagerelease.component,
section=sourcepackagerelease.section,
- ancestor=ancestor, creator=creator,
- packageupload=packageupload, channel=channel)
+ ancestor=ancestor,
+ creator=creator,
+ packageupload=packageupload,
+ channel=channel,
+ )
naked_spph = removeSecurityProxy(spph)
naked_spph.status = status
@@ -4130,22 +5027,30 @@ class LaunchpadObjectFactory(ObjectFactory):
naked_spph.datepublished = UTC_NOW
return spph
- def makeBinaryPackagePublishingHistory(self, binarypackagerelease=None,
- binarypackagename=None,
- distroarchseries=None,
- component=None, section_name=None,
- priority=None, status=None,
- scheduleddeletiondate=None,
- dateremoved=None,
- datecreated=None,
- pocket=None, archive=None,
- source_package_release=None,
- binpackageformat=None,
- sourcepackagename=None,
- version=None,
- architecturespecific=False,
- with_debug=False, with_file=False,
- creator=None, channel=None):
+ def makeBinaryPackagePublishingHistory(
+ self,
+ binarypackagerelease=None,
+ binarypackagename=None,
+ distroarchseries=None,
+ component=None,
+ section_name=None,
+ priority=None,
+ status=None,
+ scheduleddeletiondate=None,
+ dateremoved=None,
+ datecreated=None,
+ pocket=None,
+ archive=None,
+ source_package_release=None,
+ binpackageformat=None,
+ sourcepackagename=None,
+ version=None,
+ architecturespecific=False,
+ with_debug=False,
+ with_file=False,
+ creator=None,
+ channel=None,
+ ):
"""Make a `BinaryPackagePublishingHistory`."""
if distroarchseries is None:
if archive is None:
@@ -4154,16 +5059,19 @@ class LaunchpadObjectFactory(ObjectFactory):
distribution = archive.distribution
distroseries = self.makeDistroSeries(distribution=distribution)
distroarchseries = self.makeDistroArchSeries(
- distroseries=distroseries)
+ distroseries=distroseries
+ )
if archive is None:
archive = self.makeArchive(
distribution=distroarchseries.distroseries.distribution,
- purpose=ArchivePurpose.PRIMARY)
+ purpose=ArchivePurpose.PRIMARY,
+ )
# XXX wgrant 2013-05-23: We need to set build_debug_symbols
# until the guard in publishBinaries is gone.
need_debug = (
- with_debug or binpackageformat == BinaryPackageFormat.DDEB)
+ with_debug or binpackageformat == BinaryPackageFormat.DDEB
+ )
if archive.purpose == ArchivePurpose.PRIMARY and need_debug:
with admin_logged_in():
archive.build_debug_symbols = True
@@ -4185,40 +5093,58 @@ class LaunchpadObjectFactory(ObjectFactory):
# Create a new BinaryPackageBuild and BinaryPackageRelease
# in the same archive and suite.
binarypackagebuild = self.makeBinaryPackageBuild(
- archive=archive, distroarchseries=distroarchseries,
- pocket=pocket, source_package_release=source_package_release,
- sourcepackagename=sourcepackagename)
+ archive=archive,
+ distroarchseries=distroarchseries,
+ pocket=pocket,
+ source_package_release=source_package_release,
+ sourcepackagename=sourcepackagename,
+ )
binarypackagerelease = self.makeBinaryPackageRelease(
- binarypackagename=binarypackagename, version=version,
+ binarypackagename=binarypackagename,
+ version=version,
build=binarypackagebuild,
- component=component, binpackageformat=binpackageformat,
- section_name=section_name, priority=priority,
- architecturespecific=architecturespecific)
+ component=component,
+ binpackageformat=binpackageformat,
+ section_name=section_name,
+ priority=priority,
+ architecturespecific=architecturespecific,
+ )
if with_file:
ext = {
- BinaryPackageFormat.DEB: 'deb',
- BinaryPackageFormat.UDEB: 'udeb',
- BinaryPackageFormat.DDEB: 'ddeb',
- }[binarypackagerelease.binpackageformat]
+ BinaryPackageFormat.DEB: "deb",
+ BinaryPackageFormat.UDEB: "udeb",
+ BinaryPackageFormat.DDEB: "ddeb",
+ }[binarypackagerelease.binpackageformat]
lfa = self.makeLibraryFileAlias(
- filename='%s_%s_%s.%s' % (
+ filename="%s_%s_%s.%s"
+ % (
binarypackagerelease.binarypackagename.name,
binarypackagerelease.version,
binarypackagebuild.distro_arch_series.architecturetag,
- ext))
+ ext,
+ )
+ )
self.makeBinaryPackageFile(
- binarypackagerelease=binarypackagerelease,
- library_file=lfa)
+ binarypackagerelease=binarypackagerelease, library_file=lfa
+ )
if datecreated is None:
datecreated = self.getUniqueDate()
bpphs = getUtility(IPublishingSet).publishBinaries(
- archive, distroarchseries.distroseries, pocket,
- {binarypackagerelease: (
- binarypackagerelease.component, binarypackagerelease.section,
- priority, None)},
- channel=channel)
+ archive,
+ distroarchseries.distroseries,
+ pocket,
+ {
+ binarypackagerelease: (
+ binarypackagerelease.component,
+ binarypackagerelease.section,
+ priority,
+ None,
+ )
+ },
+ channel=channel,
+ )
for bpph in bpphs:
naked_bpph = removeSecurityProxy(bpph)
naked_bpph.status = status
@@ -4231,21 +5157,29 @@ class LaunchpadObjectFactory(ObjectFactory):
if with_debug:
debug_bpph = self.makeBinaryPackagePublishingHistory(
binarypackagename=(
- binarypackagerelease.binarypackagename.name + '-dbgsym'),
- version=version, distroarchseries=distroarchseries,
- component=component, section_name=binarypackagerelease.section,
- priority=priority, status=status,
+ binarypackagerelease.binarypackagename.name + "-dbgsym"
+ ),
+ version=version,
+ distroarchseries=distroarchseries,
+ component=component,
+ section_name=binarypackagerelease.section,
+ priority=priority,
+ status=status,
scheduleddeletiondate=scheduleddeletiondate,
- dateremoved=dateremoved, datecreated=datecreated,
- pocket=pocket, archive=archive,
+ dateremoved=dateremoved,
+ datecreated=datecreated,
+ pocket=pocket,
+ archive=archive,
source_package_release=source_package_release,
binpackageformat=BinaryPackageFormat.DDEB,
sourcepackagename=sourcepackagename,
architecturespecific=architecturespecific,
with_file=with_file,
- creator=creator)
- removeSecurityProxy(bpph.binarypackagerelease).debug_package = (
- debug_bpph.binarypackagerelease)
+ creator=creator,
+ )
+ removeSecurityProxy(
+ bpph.binarypackagerelease
+ ).debug_package = debug_bpph.binarypackagerelease
return bpphs[0], debug_bpph
return bpphs[0]
@@ -4261,7 +5195,9 @@ class LaunchpadObjectFactory(ObjectFactory):
return self.makeSourcePackagePublishingHistory(
distroseries=bpph.distroarchseries.distroseries,
sourcepackagerelease=bpr.build.source_package_release,
- pocket=bpph.pocket, archive=bpph.archive)
+ pocket=bpph.pocket,
+ archive=bpph.archive,
+ )
def makeBinaryPackageName(self, name=None):
"""Make an `IBinaryPackageName`."""
@@ -4279,38 +5215,60 @@ class LaunchpadObjectFactory(ObjectFactory):
return self.makeBinaryPackageName()
return getUtility(IBinaryPackageNameSet).getOrCreateByName(name)
- def makeBinaryPackageFile(self, binarypackagerelease=None,
- library_file=None, filetype=None):
+ def makeBinaryPackageFile(
+ self, binarypackagerelease=None, library_file=None, filetype=None
+ ):
if binarypackagerelease is None:
binarypackagerelease = self.makeBinaryPackageRelease()
if library_file is None:
library_file = self.makeLibraryFileAlias()
if filetype is None:
filetype = BinaryPackageFileType.DEB
- return ProxyFactory(BinaryPackageFile(
- binarypackagerelease=binarypackagerelease,
- libraryfile=library_file, filetype=filetype))
-
- def makeBinaryPackageRelease(self, binarypackagename=None,
- version=None, build=None, ci_build=None,
- binpackageformat=None, component=None,
- section_name=None, priority=None,
- architecturespecific=False,
- summary=None, description=None,
- shlibdeps=None, depends=None,
- recommends=None, suggests=None,
- conflicts=None, replaces=None,
- provides=None, pre_depends=None,
- enhances=None, breaks=None,
- essential=False, installed_size=None,
- date_created=None, debug_package=None,
- homepage=None, user_defined_fields=None):
+ return ProxyFactory(
+ BinaryPackageFile(
+ binarypackagerelease=binarypackagerelease,
+ libraryfile=library_file,
+ filetype=filetype,
+ )
+ )
+
+ def makeBinaryPackageRelease(
+ self,
+ binarypackagename=None,
+ version=None,
+ build=None,
+ ci_build=None,
+ binpackageformat=None,
+ component=None,
+ section_name=None,
+ priority=None,
+ architecturespecific=False,
+ summary=None,
+ description=None,
+ shlibdeps=None,
+ depends=None,
+ recommends=None,
+ suggests=None,
+ conflicts=None,
+ replaces=None,
+ provides=None,
+ pre_depends=None,
+ enhances=None,
+ breaks=None,
+ essential=False,
+ installed_size=None,
+ date_created=None,
+ debug_package=None,
+ homepage=None,
+ user_defined_fields=None,
+ ):
"""Make a `BinaryPackageRelease`."""
if build is None and ci_build is None:
build = self.makeBinaryPackageBuild()
if binarypackagename is None or isinstance(binarypackagename, str):
binarypackagename = self.getOrMakeBinaryPackageName(
- binarypackagename)
+ binarypackagename
+ )
if version is None and build is not None:
version = build.source_package_release.version
if binpackageformat is None:
@@ -4345,88 +5303,111 @@ class LaunchpadObjectFactory(ObjectFactory):
"installedsize": installed_size,
"homepage": homepage,
"user_defined_fields": user_defined_fields,
- }
+ }
if build is not None:
- kwargs.update({
- "component": component,
- "section": section,
- "priority": priority,
- "shlibdeps": shlibdeps,
- "depends": depends,
- "recommends": recommends,
- "suggests": suggests,
- "conflicts": conflicts,
- "replaces": replaces,
- "provides": provides,
- "pre_depends": pre_depends,
- "enhances": enhances,
- "breaks": breaks,
- "essential": essential,
- "debug_package": debug_package,
- })
+ kwargs.update(
+ {
+ "component": component,
+ "section": section,
+ "priority": priority,
+ "shlibdeps": shlibdeps,
+ "depends": depends,
+ "recommends": recommends,
+ "suggests": suggests,
+ "conflicts": conflicts,
+ "replaces": replaces,
+ "provides": provides,
+ "pre_depends": pre_depends,
+ "enhances": enhances,
+ "breaks": breaks,
+ "essential": essential,
+ "debug_package": debug_package,
+ }
+ )
bpr = (build or ci_build).createBinaryPackageRelease(**kwargs)
if date_created is not None:
removeSecurityProxy(bpr).datecreated = date_created
return bpr
- def makeSigningKey(self, key_type=None, fingerprint=None,
- public_key=None, description=None):
- """Makes a SigningKey (integration with lp-signing)
- """
+ def makeSigningKey(
+ self,
+ key_type=None,
+ fingerprint=None,
+ public_key=None,
+ description=None,
+ ):
+ """Makes a SigningKey (integration with lp-signing)"""
if key_type is None:
key_type = SigningKeyType.UEFI
if fingerprint is None:
- fingerprint = self.getUniqueUnicode('fingerprint')
+ fingerprint = self.getUniqueUnicode("fingerprint")
if public_key is None:
- public_key = self.getUniqueHexString(64).encode('ASCII')
+ public_key = self.getUniqueHexString(64).encode("ASCII")
store = IMasterStore(SigningKey)
signing_key = SigningKey(
- key_type=key_type, fingerprint=fingerprint, public_key=public_key,
- description=description)
+ key_type=key_type,
+ fingerprint=fingerprint,
+ public_key=public_key,
+ description=description,
+ )
store.add(signing_key)
return signing_key
- def makeArchiveSigningKey(self, archive=None, distro_series=None,
- signing_key=None):
+ def makeArchiveSigningKey(
+ self, archive=None, distro_series=None, signing_key=None
+ ):
if archive is None:
archive = self.makeArchive()
if signing_key is None:
signing_key = self.makeSigningKey()
return getUtility(IArchiveSigningKeySet).create(
- archive, distro_series, signing_key)
+ archive, distro_series, signing_key
+ )
def makeSection(self, name=None):
"""Make a `Section`."""
if name is None:
- name = self.getUniqueString('section')
+ name = self.getUniqueString("section")
return getUtility(ISectionSet).ensure(name)
- def makePackageset(self, name=None, description=None, owner=None,
- packages=(), distroseries=None, related_set=None):
+ def makePackageset(
+ self,
+ name=None,
+ description=None,
+ owner=None,
+ packages=(),
+ distroseries=None,
+ related_set=None,
+ ):
"""Make an `IPackageset`."""
if name is None:
- name = self.getUniqueString('package-set-name')
+ name = self.getUniqueString("package-set-name")
if description is None:
- description = self.getUniqueString('package-set-description')
+ description = self.getUniqueString("package-set-description")
if owner is None:
- person = self.getUniqueString('package-set-owner')
+ person = self.getUniqueString("package-set-owner")
owner = self.makePerson(name=person)
if distroseries is None:
- distroseries = getUtility(IDistributionSet)[
- 'ubuntu'].currentseries
+ distroseries = getUtility(IDistributionSet)["ubuntu"].currentseries
techboard = getUtility(ILaunchpadCelebrities).ubuntu_techboard
ps_set = getUtility(IPackagesetSet)
package_set = run_with_login(
techboard.teamowner,
lambda: ps_set.new(
- name, description, owner, distroseries, related_set))
+ name, description, owner, distroseries, related_set
+ ),
+ )
run_with_login(owner, lambda: package_set.add(packages))
return package_set
- def makeDistroArchSeriesFilter(self, distroarchseries=None,
- packageset=None,
- sense=DistroArchSeriesFilterSense.INCLUDE,
- creator=None, date_created=DEFAULT):
+ def makeDistroArchSeriesFilter(
+ self,
+ distroarchseries=None,
+ packageset=None,
+ sense=DistroArchSeriesFilterSense.INCLUDE,
+ creator=None,
+ date_created=DEFAULT,
+ ):
"""Make a new `DistroArchSeriesFilter`."""
if distroarchseries is None:
if packageset is not None:
@@ -4434,21 +5415,28 @@ class LaunchpadObjectFactory(ObjectFactory):
else:
distroseries = None
distroarchseries = self.makeDistroArchSeries(
- distroseries=distroseries)
+ distroseries=distroseries
+ )
if packageset is None:
packageset = self.makePackageset(
- distroseries=distroarchseries.distroseries)
+ distroseries=distroarchseries.distroseries
+ )
if creator is None:
creator = self.makePerson()
return DistroArchSeriesFilter(
- distroarchseries=distroarchseries, packageset=packageset,
- sense=sense, creator=creator, date_created=date_created)
+ distroarchseries=distroarchseries,
+ packageset=packageset,
+ sense=sense,
+ creator=creator,
+ date_created=date_created,
+ )
def getAnyPocket(self):
return PackagePublishingPocket.BACKPORTS
- def makeSuiteSourcePackage(self, distroseries=None,
- sourcepackagename=None, pocket=None):
+ def makeSuiteSourcePackage(
+ self, distroseries=None, sourcepackagename=None, pocket=None
+ ):
if distroseries is None:
distroseries = self.makeDistroSeries()
if pocket is None:
@@ -4456,16 +5444,20 @@ class LaunchpadObjectFactory(ObjectFactory):
# Make sure we have a real sourcepackagename object.
if sourcepackagename is None or isinstance(sourcepackagename, str):
sourcepackagename = self.getOrMakeSourcePackageName(
- sourcepackagename)
+ sourcepackagename
+ )
return ProxyFactory(
- SuiteSourcePackage(distroseries, pocket, sourcepackagename))
+ SuiteSourcePackage(distroseries, pocket, sourcepackagename)
+ )
- def makeDistributionSourcePackage(self, sourcepackagename=None,
- distribution=None, with_db=False):
+ def makeDistributionSourcePackage(
+ self, sourcepackagename=None, distribution=None, with_db=False
+ ):
# Make sure we have a real sourcepackagename object.
if sourcepackagename is None or isinstance(sourcepackagename, str):
sourcepackagename = self.getOrMakeSourcePackageName(
- sourcepackagename)
+ sourcepackagename
+ )
if distribution is None:
distribution = self.makeDistribution()
package = distribution.getSourcePackage(sourcepackagename)
@@ -4477,31 +5469,47 @@ class LaunchpadObjectFactory(ObjectFactory):
naked_package._new(distribution, sourcepackagename, False)
return package
- def makeDSPCache(self, distroseries=None, sourcepackagename=None,
- official=True, binary_names=None, archive=None):
+ def makeDSPCache(
+ self,
+ distroseries=None,
+ sourcepackagename=None,
+ official=True,
+ binary_names=None,
+ archive=None,
+ ):
if distroseries is None:
distroseries = self.makeDistroSeries()
dsp = self.makeDistributionSourcePackage(
distribution=distroseries.distribution,
- sourcepackagename=sourcepackagename, with_db=official)
+ sourcepackagename=sourcepackagename,
+ with_db=official,
+ )
if archive is None:
archive = dsp.distribution.main_archive
if official:
self.makeSourcePackagePublishingHistory(
distroseries=distroseries,
sourcepackagename=dsp.sourcepackagename,
- archive=archive)
- with dbuser('statistician'):
+ archive=archive,
+ )
+ with dbuser("statistician"):
DistributionSourcePackageCache(
distribution=dsp.distribution,
sourcepackagename=dsp.sourcepackagename,
archive=archive,
name=dsp.sourcepackagename.name,
- binpkgnames=binary_names)
+ binpkgnames=binary_names,
+ )
return dsp
- def makeEmailMessage(self, body=None, sender=None, to=None,
- attachments=None, encode_attachments=False):
+ def makeEmailMessage(
+ self,
+ body=None,
+ sender=None,
+ to=None,
+ attachments=None,
+ encode_attachments=False,
+ ):
"""Make an email message with possible attachments.
:param attachments: Should be an interable of tuples containing
@@ -4510,16 +5518,16 @@ class LaunchpadObjectFactory(ObjectFactory):
if sender is None:
sender = self.makePerson()
if body is None:
- body = self.getUniqueString('body')
+ body = self.getUniqueString("body")
if to is None:
to = self.getUniqueEmailAddress()
msg = MIMEMultipart()
- msg['Message-Id'] = make_msgid('launchpad')
- msg['Date'] = formatdate()
- msg['To'] = to
- msg['From'] = removeSecurityProxy(sender).preferredemail.email
- msg['Subject'] = 'Sample'
+ msg["Message-Id"] = make_msgid("launchpad")
+ msg["Date"] = formatdate()
+ msg["To"] = to
+ msg["From"] = removeSecurityProxy(sender).preferredemail.email
+ msg["Subject"] = "Sample"
if attachments is None:
msg.set_payload(body)
@@ -4528,9 +5536,10 @@ class LaunchpadObjectFactory(ObjectFactory):
for filename, content_type, payload in attachments:
attachment = EmailMessage()
attachment.set_payload(payload)
- attachment['Content-Type'] = content_type
- attachment['Content-Disposition'] = (
- 'attachment; filename="%s"' % filename)
+ attachment["Content-Type"] = content_type
+ attachment["Content-Disposition"] = (
+ 'attachment; filename="%s"' % filename
+ )
if encode_attachments:
encode_base64(attachment)
msg.attach(attachment)
@@ -4550,36 +5559,46 @@ class LaunchpadObjectFactory(ObjectFactory):
parameters = [MP(keydata.RSAData[param]) for param in ("e", "n")]
elif key_type == "ssh-dss":
parameters = [
- MP(keydata.DSAData[param]) for param in ("p", "q", "g", "y")]
+ MP(keydata.DSAData[param]) for param in ("p", "q", "g", "y")
+ ]
elif key_type.startswith("ecdsa-sha2-"):
- curve = key_type[len("ecdsa-sha2-"):]
+ curve = key_type[len("ecdsa-sha2-") :]
key_size, curve_data = {
"nistp256": (256, keydata.ECDatanistp256),
"nistp384": (384, keydata.ECDatanistp384),
"nistp521": (521, keydata.ECDatanistp521),
- }.get(curve, (None, None))
+ }.get(curve, (None, None))
if curve_data is not None:
key_byte_length = (key_size + 7) // 8
parameters = [
NS(curve_data["curve"][-8:]),
- NS(b"\x04" +
- int_to_bytes(curve_data["x"], key_byte_length) +
- int_to_bytes(curve_data["y"], key_byte_length)),
- ]
+ NS(
+ b"\x04"
+ + int_to_bytes(curve_data["x"], key_byte_length)
+ + int_to_bytes(curve_data["y"], key_byte_length)
+ ),
+ ]
elif key_type == "ssh-ed25519":
parameters = [NS(keydata.Ed25519Data["a"])]
if parameters is None:
raise AssertionError(
- "key_type must be a member of SSH_TEXT_TO_KEY_TYPE, not %r" %
- key_type)
+ "key_type must be a member of SSH_TEXT_TO_KEY_TYPE, not %r"
+ % key_type
+ )
key_text = base64.b64encode(
- NS(key_type) + b"".join(parameters)).decode("ASCII")
+ NS(key_type) + b"".join(parameters)
+ ).decode("ASCII")
if comment is None:
comment = self.getUniqueString()
return "%s %s %s" % (key_type, key_text, comment)
- def makeSSHKey(self, person=None, key_type="ssh-rsa",
- send_notification=True, comment=None):
+ def makeSSHKey(
+ self,
+ person=None,
+ key_type="ssh-rsa",
+ send_notification=True,
+ comment=None,
+ ):
"""Create a new SSHKey.
:param person: If specified, the person to attach the key to. If
@@ -4594,14 +5613,16 @@ class LaunchpadObjectFactory(ObjectFactory):
person = self.makePerson()
public_key = self.makeSSHKeyText(key_type=key_type, comment=comment)
return getUtility(ISSHKeySet).new(
- person, public_key, send_notification=send_notification)
+ person, public_key, send_notification=send_notification
+ )
def makeBlob(self, blob=None, expires=None, blob_file=None):
"""Create a new TemporaryFileStorage BLOB."""
if blob_file is not None:
blob_path = os.path.join(
- config.root, 'lib/lp/bugs/tests/testfiles', blob_file)
- with open(blob_path, 'rb') as blob_file:
+ config.root, "lib/lp/bugs/tests/testfiles", blob_file
+ )
+ with open(blob_path, "rb") as blob_file:
blob = blob_file.read()
if blob is None:
blob = self.getUniqueBytes()
@@ -4619,7 +5640,8 @@ class LaunchpadObjectFactory(ObjectFactory):
job = getUtility(IProcessApportBlobJobSource).create(blob)
job.job.start()
removeSecurityProxy(job).metadata = {
- 'processed_data': FileBugData(**metadata).asDict()}
+ "processed_data": FileBugData(**metadata).asDict()
+ }
job.job.complete()
return blob
@@ -4627,15 +5649,26 @@ class LaunchpadObjectFactory(ObjectFactory):
if person is None:
person = self.makePerson()
from lp.testing.layers import BaseLayer
+
launchpad = launchpadlib_for(
- "test", person, service_root=BaseLayer.appserver_root_url("api"),
- version=version)
+ "test",
+ person,
+ service_root=BaseLayer.appserver_root_url("api"),
+ version=version,
+ )
login_person(person)
return launchpad
- def makePackageDiff(self, from_source=None, to_source=None,
- requester=None, status=None, date_fulfilled=None,
- diff_content=None, diff_filename=None):
+ def makePackageDiff(
+ self,
+ from_source=None,
+ to_source=None,
+ requester=None,
+ status=None,
+ date_fulfilled=None,
+ diff_content=None,
+ diff_filename=None,
+ ):
"""Create a new `PackageDiff`."""
if from_source is None:
from_source = self.makeSourcePackageRelease()
@@ -4650,12 +5683,18 @@ class LaunchpadObjectFactory(ObjectFactory):
if diff_content is None:
diff_content = self.getUniqueBytes("packagediff")
lfa = self.makeLibraryFileAlias(
- filename=diff_filename, content=diff_content)
+ filename=diff_filename, content=diff_content
+ )
package_diff = ProxyFactory(
PackageDiff(
- requester=requester, from_source=from_source,
- to_source=to_source, date_fulfilled=date_fulfilled,
- status=status, diff_content=lfa))
+ requester=requester,
+ from_source=from_source,
+ to_source=to_source,
+ date_fulfilled=date_fulfilled,
+ status=status,
+ diff_content=lfa,
+ )
+ )
IStore(package_diff).flush()
return package_diff
@@ -4664,12 +5703,16 @@ class LaunchpadObjectFactory(ObjectFactory):
if key is None:
key = self.getUniqueUnicode("oauthconsumerkey")
if secret is None:
- secret = ''
+ secret = ""
return getUtility(IOAuthConsumerSet).new(key, secret)
- def makeOAuthRequestToken(self, consumer=None, date_created=None,
- reviewed_by=None,
- access_level=OAuthPermission.READ_PUBLIC):
+ def makeOAuthRequestToken(
+ self,
+ consumer=None,
+ date_created=None,
+ reviewed_by=None,
+ access_level=OAuthPermission.READ_PUBLIC,
+ ):
"""Create a (possibly reviewed) OAuth request token."""
if consumer is None:
consumer = self.makeOAuthConsumer()
@@ -4686,17 +5729,29 @@ class LaunchpadObjectFactory(ObjectFactory):
unwrapped_token.date_created = date_created
return token
- def makeOAuthAccessToken(self, consumer=None, owner=None,
- access_level=OAuthPermission.READ_PUBLIC):
+ def makeOAuthAccessToken(
+ self,
+ consumer=None,
+ owner=None,
+ access_level=OAuthPermission.READ_PUBLIC,
+ ):
"""Create an OAuth access token."""
if owner is None:
owner = self.makePerson()
request_token = self.makeOAuthRequestToken(
- consumer, reviewed_by=owner, access_level=access_level)
+ consumer, reviewed_by=owner, access_level=access_level
+ )
return request_token.createAccessToken()
- def makeAccessToken(self, secret=None, owner=None, description=None,
- target=None, scopes=None, date_expires=None):
+ def makeAccessToken(
+ self,
+ secret=None,
+ owner=None,
+ description=None,
+ target=None,
+ scopes=None,
+ date_expires=None,
+ ):
"""Create a personal access token.
:return: A tuple of the secret for the new token and the token
@@ -4713,30 +5768,40 @@ class LaunchpadObjectFactory(ObjectFactory):
if scopes is None:
scopes = []
token = getUtility(IAccessTokenSet).new(
- secret, owner, description, target, scopes,
- date_expires=date_expires)
+ secret,
+ owner,
+ description,
+ target,
+ scopes,
+ date_expires=date_expires,
+ )
IStore(token).flush()
return secret, token
- def makeCVE(self, sequence, description=None,
- cvestate=CveStatus.CANDIDATE,
- date_made_public=None, discoverer=None,
- cvss=None):
+ def makeCVE(
+ self,
+ sequence,
+ description=None,
+ cvestate=CveStatus.CANDIDATE,
+ date_made_public=None,
+ discoverer=None,
+ cvss=None,
+ ):
"""Create a new CVE record."""
if description is None:
description = self.getUniqueUnicode()
return getUtility(ICveSet).new(
- sequence,
- description,
- cvestate,
- date_made_public,
- discoverer,
- cvss
+ sequence, description, cvestate, date_made_public, discoverer, cvss
)
- def makePublisherConfig(self, distribution=None, root_dir=None,
- base_url=None, copy_base_url=None):
+ def makePublisherConfig(
+ self,
+ distribution=None,
+ root_dir=None,
+ base_url=None,
+ copy_base_url=None,
+ ):
"""Create a new `PublisherConfig` record."""
if distribution is None:
distribution = self.makeDistribution()
@@ -4747,16 +5812,24 @@ class LaunchpadObjectFactory(ObjectFactory):
if copy_base_url is None:
copy_base_url = self.getUniqueUnicode()
return getUtility(IPublisherConfigSet).new(
- distribution, root_dir, base_url, copy_base_url)
+ distribution, root_dir, base_url, copy_base_url
+ )
def makePlainPackageCopyJob(
- self, package_name=None, package_version=None, source_archive=None,
- target_archive=None, target_distroseries=None, target_pocket=None,
- requester=None, include_binaries=False):
+ self,
+ package_name=None,
+ package_version=None,
+ source_archive=None,
+ target_archive=None,
+ target_distroseries=None,
+ target_pocket=None,
+ requester=None,
+ include_binaries=False,
+ ):
"""Create a new `PlainPackageCopyJob`."""
if package_name is None and package_version is None:
package_name = self.makeSourcePackageName().name
- package_version = str(self.getUniqueInteger()) + 'version'
+ package_version = str(self.getUniqueInteger()) + "version"
if source_archive is None:
source_archive = self.makeArchive()
if target_archive is None:
@@ -4768,14 +5841,22 @@ class LaunchpadObjectFactory(ObjectFactory):
if requester is None:
requester = self.makePerson()
return getUtility(IPlainPackageCopyJobSource).create(
- package_name, source_archive, target_archive,
- target_distroseries, target_pocket,
- package_version=package_version, requester=requester,
- include_binaries=include_binaries)
-
- def makeAccessPolicy(self, pillar=None,
- type=InformationType.PROPRIETARY,
- check_existing=False):
+ package_name,
+ source_archive,
+ target_archive,
+ target_distroseries,
+ target_pocket,
+ package_version=package_version,
+ requester=requester,
+ include_binaries=include_binaries,
+ )
+
+ def makeAccessPolicy(
+ self,
+ pillar=None,
+ type=InformationType.PROPRIETARY,
+ check_existing=False,
+ ):
if pillar is None:
pillar = self.makeProduct()
policy_source = getUtility(IAccessPolicySource)
@@ -4798,11 +5879,13 @@ class LaunchpadObjectFactory(ObjectFactory):
if policy is None:
policy = self.makeAccessPolicy()
[link] = getUtility(IAccessPolicyArtifactSource).create(
- [(artifact, policy)])
+ [(artifact, policy)]
+ )
return link
- def makeAccessArtifactGrant(self, artifact=None, grantee=None,
- grantor=None, concrete_artifact=None):
+ def makeAccessArtifactGrant(
+ self, artifact=None, grantee=None, grantor=None, concrete_artifact=None
+ ):
if artifact is None:
artifact = self.makeAccessArtifact(concrete_artifact)
if grantee is None:
@@ -4810,7 +5893,8 @@ class LaunchpadObjectFactory(ObjectFactory):
if grantor is None:
grantor = self.makePerson()
[grant] = getUtility(IAccessArtifactGrantSource).grant(
- [(artifact, grantee, grantor)])
+ [(artifact, grantee, grantor)]
+ )
return grant
def makeAccessPolicyGrant(self, policy=None, grantee=None, grantor=None):
@@ -4821,7 +5905,8 @@ class LaunchpadObjectFactory(ObjectFactory):
if grantor is None:
grantor = self.makePerson()
[grant] = getUtility(IAccessPolicyGrantSource).grant(
- [(policy, grantee, grantor)])
+ [(policy, grantee, grantor)]
+ )
return grant
def makeFakeFileUpload(self, filename=None, content=None):
@@ -4836,13 +5921,14 @@ class LaunchpadObjectFactory(ObjectFactory):
fileupload = BytesIO(content)
fileupload.filename = filename
fileupload.headers = {
- 'Content-Type': 'text/plain; charset=utf-8',
- 'Content-Disposition': 'attachment; filename="%s"' % filename
- }
+ "Content-Type": "text/plain; charset=utf-8",
+ "Content-Disposition": 'attachment; filename="%s"' % filename,
+ }
return fileupload
- def makeCommercialSubscription(self, pillar, expired=False,
- voucher_id='new'):
+ def makeCommercialSubscription(
+ self, pillar, expired=False, voucher_id="new"
+ ):
"""Create a commercial subscription for the given pillar."""
if IProduct.providedBy(pillar):
find_kwargs = {"product": pillar}
@@ -4850,10 +5936,15 @@ class LaunchpadObjectFactory(ObjectFactory):
find_kwargs = {"distribution": pillar}
else:
raise AssertionError("Unknown pillar: %r" % pillar)
- if IStore(CommercialSubscription).find(
- CommercialSubscription, **find_kwargs).one() is not None:
+ if (
+ IStore(CommercialSubscription)
+ .find(CommercialSubscription, **find_kwargs)
+ .one()
+ is not None
+ ):
raise AssertionError(
- "The pillar under test already has a CommercialSubscription.")
+ "The pillar under test already has a CommercialSubscription."
+ )
if expired:
expiry = datetime.now(pytz.UTC) - timedelta(days=1)
else:
@@ -4865,7 +5956,8 @@ class LaunchpadObjectFactory(ObjectFactory):
registrant=pillar.owner,
purchaser=pillar.owner,
sales_system_id=voucher_id,
- whiteboard='')
+ whiteboard="",
+ )
del get_property_cache(pillar).commercial_subscription
return commercial_subscription
@@ -4873,11 +5965,20 @@ class LaunchpadObjectFactory(ObjectFactory):
"""Give 'person' a commercial subscription."""
product = self.makeProduct(owner=person)
self.makeCommercialSubscription(
- product, voucher_id=self.getUniqueUnicode())
+ product, voucher_id=self.getUniqueUnicode()
+ )
- def makeLiveFS(self, registrant=None, owner=None, distroseries=None,
- name=None, metadata=None, require_virtualized=True,
- keep_binary_files_days=1, date_created=DEFAULT):
+ def makeLiveFS(
+ self,
+ registrant=None,
+ owner=None,
+ distroseries=None,
+ name=None,
+ metadata=None,
+ require_virtualized=True,
+ keep_binary_files_days=1,
+ date_created=DEFAULT,
+ ):
"""Make a new LiveFS."""
if registrant is None:
registrant = self.makePerson()
@@ -4890,18 +5991,35 @@ class LaunchpadObjectFactory(ObjectFactory):
if metadata is None:
metadata = {}
livefs = getUtility(ILiveFSSet).new(
- registrant, owner, distroseries, name, metadata,
+ registrant,
+ owner,
+ distroseries,
+ name,
+ metadata,
require_virtualized=require_virtualized,
keep_binary_files_days=keep_binary_files_days,
- date_created=date_created)
+ date_created=date_created,
+ )
IStore(livefs).flush()
return livefs
- def makeLiveFSBuild(self, requester=None, registrant=None, livefs=None,
- archive=None, distroarchseries=None, pocket=None,
- unique_key=None, metadata_override=None, version=None,
- date_created=DEFAULT, status=BuildStatus.NEEDSBUILD,
- builder=None, duration=None, **kwargs):
+ def makeLiveFSBuild(
+ self,
+ requester=None,
+ registrant=None,
+ livefs=None,
+ archive=None,
+ distroarchseries=None,
+ pocket=None,
+ unique_key=None,
+ metadata_override=None,
+ version=None,
+ date_created=DEFAULT,
+ status=BuildStatus.NEEDSBUILD,
+ builder=None,
+ duration=None,
+ **kwargs
+ ):
"""Make a new LiveFSBuild."""
if requester is None:
requester = self.makePerson()
@@ -4913,34 +6031,49 @@ class LaunchpadObjectFactory(ObjectFactory):
distroseries = distroarchseries.distroseries
elif archive is not None:
distroseries = self.makeDistroSeries(
- distribution=archive.distribution)
+ distribution=archive.distribution
+ )
else:
distroseries = None
if registrant is None:
registrant = requester
livefs = self.makeLiveFS(
- registrant=registrant, distroseries=distroseries, **kwargs)
+ registrant=registrant, distroseries=distroseries, **kwargs
+ )
if archive is None:
archive = livefs.distro_series.main_archive
if distroarchseries is None:
distroarchseries = self.makeDistroArchSeries(
- distroseries=livefs.distro_series)
+ distroseries=livefs.distro_series
+ )
if pocket is None:
pocket = PackagePublishingPocket.RELEASE
livefsbuild = getUtility(ILiveFSBuildSet).new(
- requester, livefs, archive, distroarchseries, pocket,
- unique_key=unique_key, metadata_override=metadata_override,
- version=version, date_created=date_created)
+ requester,
+ livefs,
+ archive,
+ distroarchseries,
+ pocket,
+ unique_key=unique_key,
+ metadata_override=metadata_override,
+ version=version,
+ date_created=date_created,
+ )
if duration is not None:
removeSecurityProxy(livefsbuild).updateStatus(
- BuildStatus.BUILDING, builder=builder,
- date_started=livefsbuild.date_created)
+ BuildStatus.BUILDING,
+ builder=builder,
+ date_started=livefsbuild.date_created,
+ )
removeSecurityProxy(livefsbuild).updateStatus(
- status, builder=builder,
- date_finished=livefsbuild.date_started + duration)
+ status,
+ builder=builder,
+ date_finished=livefsbuild.date_started + duration,
+ )
else:
removeSecurityProxy(livefsbuild).updateStatus(
- status, builder=builder)
+ status, builder=builder
+ )
IStore(livefsbuild).flush()
return livefsbuild
@@ -4950,47 +6083,84 @@ class LaunchpadObjectFactory(ObjectFactory):
if libraryfile is None:
libraryfile = self.makeLibraryFileAlias()
return ProxyFactory(
- LiveFSFile(livefsbuild=livefsbuild, libraryfile=libraryfile))
+ LiveFSFile(livefsbuild=livefsbuild, libraryfile=libraryfile)
+ )
- def makeWebhook(self, target=None, delivery_url=None, secret=None,
- active=True, event_types=None):
+ def makeWebhook(
+ self,
+ target=None,
+ delivery_url=None,
+ secret=None,
+ active=True,
+ event_types=None,
+ ):
if target is None:
target = self.makeGitRepository()
if delivery_url is None:
delivery_url = self.getUniqueURL()
return getUtility(IWebhookSet).new(
- target, self.makePerson(), delivery_url, event_types or [],
- active, secret)
-
- def makeSnap(self, registrant=None, owner=None, distroseries=_DEFAULT,
- name=None, branch=None, git_ref=None, auto_build=False,
- auto_build_archive=None, auto_build_pocket=None,
- auto_build_channels=None, is_stale=None,
- require_virtualized=True, processors=None,
- date_created=DEFAULT, private=None, information_type=None,
- allow_internet=True, build_source_tarball=False,
- store_upload=False, store_series=None, store_name=None,
- store_secrets=None, store_channels=None, project=_DEFAULT):
+ target,
+ self.makePerson(),
+ delivery_url,
+ event_types or [],
+ active,
+ secret,
+ )
+
+ def makeSnap(
+ self,
+ registrant=None,
+ owner=None,
+ distroseries=_DEFAULT,
+ name=None,
+ branch=None,
+ git_ref=None,
+ auto_build=False,
+ auto_build_archive=None,
+ auto_build_pocket=None,
+ auto_build_channels=None,
+ is_stale=None,
+ require_virtualized=True,
+ processors=None,
+ date_created=DEFAULT,
+ private=None,
+ information_type=None,
+ allow_internet=True,
+ build_source_tarball=False,
+ store_upload=False,
+ store_series=None,
+ store_name=None,
+ store_secrets=None,
+ store_channels=None,
+ project=_DEFAULT,
+ ):
"""Make a new Snap."""
assert information_type is None or private is None
if information_type is None:
# Defaults to public information type, unless "private" flag was
# passed.
- information_type = (InformationType.PUBLIC if not private
- else InformationType.PROPRIETARY)
+ information_type = (
+ InformationType.PUBLIC
+ if not private
+ else InformationType.PROPRIETARY
+ )
if private is None:
private = information_type not in PUBLIC_INFORMATION_TYPES
if registrant is None:
registrant = self.makePerson()
if owner is None:
is_private_snap = (
- private or information_type not in PUBLIC_INFORMATION_TYPES)
+ private or information_type not in PUBLIC_INFORMATION_TYPES
+ )
# Private snaps cannot be owned by non-moderated teams.
membership_policy = (
- TeamMembershipPolicy.OPEN if not is_private_snap
- else TeamMembershipPolicy.MODERATED)
+ TeamMembershipPolicy.OPEN
+ if not is_private_snap
+ else TeamMembershipPolicy.MODERATED
+ )
owner = self.makeTeam(
- registrant, membership_policy=membership_policy)
+ registrant, membership_policy=membership_policy
+ )
if distroseries is _DEFAULT:
distroseries = self.makeDistroSeries()
if name is None:
@@ -5000,42 +6170,63 @@ class LaunchpadObjectFactory(ObjectFactory):
if auto_build:
if auto_build_archive is None:
auto_build_archive = self.makeArchive(
- distribution=distroseries.distribution, owner=owner)
+ distribution=distroseries.distribution, owner=owner
+ )
if auto_build_pocket is None:
auto_build_pocket = PackagePublishingPocket.UPDATES
if private and project is _DEFAULT:
# If we are creating a private snap and didn't explicitly set a
# pillar for it, we must create a pillar.
branch_sharing = (
- BranchSharingPolicy.PUBLIC_OR_PROPRIETARY if not private
- else BranchSharingPolicy.PROPRIETARY)
+ BranchSharingPolicy.PUBLIC_OR_PROPRIETARY
+ if not private
+ else BranchSharingPolicy.PROPRIETARY
+ )
project = self.makeProduct(
- owner=registrant, registrant=registrant,
+ owner=registrant,
+ registrant=registrant,
information_type=information_type,
- branch_sharing_policy=branch_sharing)
+ branch_sharing_policy=branch_sharing,
+ )
if project is _DEFAULT:
project = None
snap = getUtility(ISnapSet).new(
- registrant, owner, distroseries, name,
- require_virtualized=require_virtualized, processors=processors,
- date_created=date_created, branch=branch, git_ref=git_ref,
- auto_build=auto_build, auto_build_archive=auto_build_archive,
+ registrant,
+ owner,
+ distroseries,
+ name,
+ require_virtualized=require_virtualized,
+ processors=processors,
+ date_created=date_created,
+ branch=branch,
+ git_ref=git_ref,
+ auto_build=auto_build,
+ auto_build_archive=auto_build_archive,
auto_build_pocket=auto_build_pocket,
auto_build_channels=auto_build_channels,
information_type=information_type,
allow_internet=allow_internet,
build_source_tarball=build_source_tarball,
- store_upload=store_upload, store_series=store_series,
- store_name=store_name, store_secrets=store_secrets,
- store_channels=store_channels, project=project)
+ store_upload=store_upload,
+ store_series=store_series,
+ store_name=store_name,
+ store_secrets=store_secrets,
+ store_channels=store_channels,
+ project=project,
+ )
if is_stale is not None:
removeSecurityProxy(snap).is_stale = is_stale
IStore(snap).flush()
return snap
- def makeSnapBuildRequest(self, snap=None, requester=None, archive=None,
- pocket=PackagePublishingPocket.UPDATES,
- channels=None):
+ def makeSnapBuildRequest(
+ self,
+ snap=None,
+ requester=None,
+ archive=None,
+ pocket=PackagePublishingPocket.UPDATES,
+ channels=None,
+ ):
"""Make a new SnapBuildRequest."""
if snap is None:
snap = self.makeSnap()
@@ -5044,14 +6235,27 @@ class LaunchpadObjectFactory(ObjectFactory):
if archive is None:
archive = snap.distro_series.main_archive
return snap.requestBuilds(
- requester, archive, pocket, channels=channels)
-
- def makeSnapBuild(self, requester=None, registrant=None, snap=None,
- archive=None, distroarchseries=None, pocket=None,
- snap_base=None, channels=None, date_created=DEFAULT,
- build_request=None, status=BuildStatus.NEEDSBUILD,
- builder=None, duration=None, target_architectures=None,
- **kwargs):
+ requester, archive, pocket, channels=channels
+ )
+
+ def makeSnapBuild(
+ self,
+ requester=None,
+ registrant=None,
+ snap=None,
+ archive=None,
+ distroarchseries=None,
+ pocket=None,
+ snap_base=None,
+ channels=None,
+ date_created=DEFAULT,
+ build_request=None,
+ status=BuildStatus.NEEDSBUILD,
+ builder=None,
+ duration=None,
+ target_architectures=None,
+ **kwargs
+ ):
"""Make a new SnapBuild."""
if requester is None:
requester = self.makePerson()
@@ -5063,35 +6267,50 @@ class LaunchpadObjectFactory(ObjectFactory):
distroseries = distroarchseries.distroseries
elif archive is not None:
distroseries = self.makeDistroSeries(
- distribution=archive.distribution)
+ distribution=archive.distribution
+ )
else:
distroseries = _DEFAULT
if registrant is None:
registrant = requester
snap = self.makeSnap(
- registrant=registrant, distroseries=distroseries, **kwargs)
+ registrant=registrant, distroseries=distroseries, **kwargs
+ )
if archive is None:
archive = snap.distro_series.main_archive
if distroarchseries is None:
distroarchseries = self.makeDistroArchSeries(
- distroseries=snap.distro_series)
+ distroseries=snap.distro_series
+ )
if pocket is None:
pocket = PackagePublishingPocket.UPDATES
snapbuild = getUtility(ISnapBuildSet).new(
- requester, snap, archive, distroarchseries, pocket,
- snap_base=snap_base, channels=channels, date_created=date_created,
+ requester,
+ snap,
+ archive,
+ distroarchseries,
+ pocket,
+ snap_base=snap_base,
+ channels=channels,
+ date_created=date_created,
build_request=build_request,
- target_architectures=target_architectures)
+ target_architectures=target_architectures,
+ )
if duration is not None:
removeSecurityProxy(snapbuild).updateStatus(
- BuildStatus.BUILDING, builder=builder,
- date_started=snapbuild.date_created)
+ BuildStatus.BUILDING,
+ builder=builder,
+ date_started=snapbuild.date_created,
+ )
removeSecurityProxy(snapbuild).updateStatus(
- status, builder=builder,
- date_finished=snapbuild.date_started + duration)
+ status,
+ builder=builder,
+ date_finished=snapbuild.date_started + duration,
+ )
else:
removeSecurityProxy(snapbuild).updateStatus(
- status, builder=builder)
+ status, builder=builder
+ )
IStore(snapbuild).flush()
return snapbuild
@@ -5101,13 +6320,20 @@ class LaunchpadObjectFactory(ObjectFactory):
if libraryfile is None:
libraryfile = self.makeLibraryFileAlias()
return ProxyFactory(
- SnapFile(snapbuild=snapbuild, libraryfile=libraryfile))
+ SnapFile(snapbuild=snapbuild, libraryfile=libraryfile)
+ )
- def makeSnappySeries(self, registrant=None, name=None, display_name=None,
- status=SeriesStatus.DEVELOPMENT,
- preferred_distro_series=None, date_created=DEFAULT,
- usable_distro_series=None,
- can_infer_distro_series=False):
+ def makeSnappySeries(
+ self,
+ registrant=None,
+ name=None,
+ display_name=None,
+ status=SeriesStatus.DEVELOPMENT,
+ preferred_distro_series=None,
+ date_created=DEFAULT,
+ usable_distro_series=None,
+ can_infer_distro_series=False,
+ ):
"""Make a new SnappySeries."""
if registrant is None:
registrant = self.makePerson()
@@ -5115,11 +6341,16 @@ class LaunchpadObjectFactory(ObjectFactory):
name = self.getUniqueString("snappy-series-name")
if display_name is None:
display_name = SPACE.join(
- word.capitalize() for word in name.split('-'))
+ word.capitalize() for word in name.split("-")
+ )
snappy_series = getUtility(ISnappySeriesSet).new(
- registrant, name, display_name, status,
+ registrant,
+ name,
+ display_name,
+ status,
preferred_distro_series=preferred_distro_series,
- date_created=date_created)
+ date_created=date_created,
+ )
if usable_distro_series is not None:
snappy_series.usable_distro_series = usable_distro_series
elif preferred_distro_series is not None:
@@ -5129,9 +6360,16 @@ class LaunchpadObjectFactory(ObjectFactory):
IStore(snappy_series).flush()
return snappy_series
- def makeSnapBase(self, registrant=None, name=None, display_name=None,
- distro_series=None, build_channels=None, processors=None,
- date_created=DEFAULT):
+ def makeSnapBase(
+ self,
+ registrant=None,
+ name=None,
+ display_name=None,
+ distro_series=None,
+ build_channels=None,
+ processors=None,
+ date_created=DEFAULT,
+ ):
"""Make a new SnapBase."""
if registrant is None:
registrant = self.makePerson()
@@ -5139,25 +6377,38 @@ class LaunchpadObjectFactory(ObjectFactory):
name = self.getUniqueString("snap-base-name")
if display_name is None:
display_name = SPACE.join(
- word.capitalize() for word in name.split('-'))
+ word.capitalize() for word in name.split("-")
+ )
if distro_series is None:
distro_series = self.makeDistroSeries()
if build_channels is None:
build_channels = {"snapcraft": "stable"}
return getUtility(ISnapBaseSet).new(
- registrant, name, display_name, distro_series, build_channels,
- processors=processors, date_created=date_created)
+ registrant,
+ name,
+ display_name,
+ distro_series,
+ build_channels,
+ processors=processors,
+ date_created=date_created,
+ )
def makeOCIProjectName(self, name=None):
if name is None:
name = self.getUniqueString("oci-project-name")
return getUtility(IOCIProjectNameSet).getOrCreateByName(name)
- def makeOCIProject(self, registrant=None, pillar=None,
- ociprojectname=None, date_created=DEFAULT,
- description=None, bug_reporting_guidelines=None,
- bug_reported_acknowledgement=None,
- bugfiling_duplicate_search=False):
+ def makeOCIProject(
+ self,
+ registrant=None,
+ pillar=None,
+ ociprojectname=None,
+ date_created=DEFAULT,
+ description=None,
+ bug_reporting_guidelines=None,
+ bug_reported_acknowledgement=None,
+ bugfiling_duplicate_search=False,
+ ):
"""Make a new OCIProject."""
if registrant is None:
registrant = self.makePerson()
@@ -5166,14 +6417,24 @@ class LaunchpadObjectFactory(ObjectFactory):
if ociprojectname is None or isinstance(ociprojectname, str):
ociprojectname = self.makeOCIProjectName(ociprojectname)
return getUtility(IOCIProjectSet).new(
- registrant, pillar, ociprojectname, date_created=date_created,
+ registrant,
+ pillar,
+ ociprojectname,
+ date_created=date_created,
description=description,
bug_reporting_guidelines=bug_reporting_guidelines,
bug_reported_acknowledgement=bug_reported_acknowledgement,
- bugfiling_duplicate_search=bugfiling_duplicate_search)
+ bugfiling_duplicate_search=bugfiling_duplicate_search,
+ )
- def makeOCIProjectSeries(self, name=None, summary=None, registrant=None,
- oci_project=None, **kwargs):
+ def makeOCIProjectSeries(
+ self,
+ name=None,
+ summary=None,
+ registrant=None,
+ oci_project=None,
+ **kwargs
+ ):
"""Make a new OCIProjectSeries attached to an OCIProject."""
if name is None:
name = self.getUniqueString("oci-project-series-name")
@@ -5185,12 +6446,23 @@ class LaunchpadObjectFactory(ObjectFactory):
oci_project = self.makeOCIProject(**kwargs)
return oci_project.newSeries(name, summary, registrant)
- def makeOCIRecipe(self, name=None, registrant=None, owner=None,
- oci_project=None, git_ref=None, description=None,
- official=False, require_virtualized=True,
- build_file=None, date_created=DEFAULT,
- allow_internet=True, build_args=None, build_path=None,
- information_type=InformationType.PUBLIC):
+ def makeOCIRecipe(
+ self,
+ name=None,
+ registrant=None,
+ owner=None,
+ oci_project=None,
+ git_ref=None,
+ description=None,
+ official=False,
+ require_virtualized=True,
+ build_file=None,
+ date_created=DEFAULT,
+ allow_internet=True,
+ build_args=None,
+ build_path=None,
+ information_type=InformationType.PUBLIC,
+ ):
"""Make a new OCIRecipe."""
if name is None:
name = self.getUniqueString("oci-recipe-name")
@@ -5204,7 +6476,7 @@ class LaunchpadObjectFactory(ObjectFactory):
oci_project = self.makeOCIProject()
if git_ref is None:
component = self.getUniqueUnicode()
- paths = ['refs/heads/{}-20.04'.format(component)]
+ paths = ["refs/heads/{}-20.04".format(component)]
[git_ref] = self.makeGitRefs(paths=paths)
if build_file is None:
build_file = self.getUniqueUnicode("build_file_for")
@@ -5224,7 +6496,8 @@ class LaunchpadObjectFactory(ObjectFactory):
date_created=date_created,
allow_internet=allow_internet,
build_args=build_args,
- information_type=information_type)
+ information_type=information_type,
+ )
def makeOCIRecipeArch(self, recipe=None, processor=None):
"""Make a new OCIRecipeArch."""
@@ -5234,10 +6507,19 @@ class LaunchpadObjectFactory(ObjectFactory):
processor = self.makeProcessor()
return OCIRecipeArch(recipe, processor)
- def makeOCIRecipeBuild(self, requester=None, registrant=None, recipe=None,
- distro_arch_series=None, date_created=DEFAULT,
- status=BuildStatus.NEEDSBUILD, builder=None,
- duration=None, build_request=None, **kwargs):
+ def makeOCIRecipeBuild(
+ self,
+ requester=None,
+ registrant=None,
+ recipe=None,
+ distro_arch_series=None,
+ date_created=DEFAULT,
+ status=BuildStatus.NEEDSBUILD,
+ builder=None,
+ duration=None,
+ build_request=None,
+ **kwargs
+ ):
"""Make a new OCIRecipeBuild."""
if requester is None:
requester = self.makePerson()
@@ -5247,55 +6529,78 @@ class LaunchpadObjectFactory(ObjectFactory):
else:
distribution = None
distroseries = self.makeDistroSeries(
- distribution=distribution, status=SeriesStatus.CURRENT)
+ distribution=distribution, status=SeriesStatus.CURRENT
+ )
processor = getUtility(IProcessorSet).getByName("386")
distro_arch_series = self.makeDistroArchSeries(
- distroseries=distroseries, architecturetag="i386",
- processor=processor)
+ distroseries=distroseries,
+ architecturetag="i386",
+ processor=processor,
+ )
if recipe is None:
oci_project = self.makeOCIProject(
- pillar=distro_arch_series.distroseries.distribution)
+ pillar=distro_arch_series.distroseries.distribution
+ )
if registrant is None:
registrant = requester
recipe = self.makeOCIRecipe(
- registrant=registrant, oci_project=oci_project, **kwargs)
+ registrant=registrant, oci_project=oci_project, **kwargs
+ )
oci_build = getUtility(IOCIRecipeBuildSet).new(
- requester, recipe, distro_arch_series, date_created, build_request)
+ requester, recipe, distro_arch_series, date_created, build_request
+ )
if duration is not None:
removeSecurityProxy(oci_build).updateStatus(
- BuildStatus.BUILDING, builder=builder,
- date_started=oci_build.date_created)
+ BuildStatus.BUILDING,
+ builder=builder,
+ date_started=oci_build.date_created,
+ )
removeSecurityProxy(oci_build).updateStatus(
- status, builder=builder,
- date_finished=oci_build.date_started + duration)
+ status,
+ builder=builder,
+ date_finished=oci_build.date_started + duration,
+ )
else:
removeSecurityProxy(oci_build).updateStatus(
- status, builder=builder)
+ status, builder=builder
+ )
IStore(oci_build).flush()
return oci_build
- def makeOCIFile(self, build=None, library_file=None,
- layer_file_digest=None, content=None, filename=None):
+ def makeOCIFile(
+ self,
+ build=None,
+ library_file=None,
+ layer_file_digest=None,
+ content=None,
+ filename=None,
+ ):
"""Make a new OCIFile."""
if build is None:
build = self.makeOCIRecipeBuild()
if library_file is None:
library_file = self.makeLibraryFileAlias(
- content=content, filename=filename)
- return OCIFile(build=build, library_file=library_file,
- layer_file_digest=layer_file_digest)
+ content=content, filename=filename
+ )
+ return OCIFile(
+ build=build,
+ library_file=library_file,
+ layer_file_digest=layer_file_digest,
+ )
def makeOCIRecipeBuildJob(self, build=None):
store = IStore(OCIRecipeBuildJob)
if build is None:
build = self.makeOCIRecipeBuild()
job = OCIRecipeBuildJob(
- build, OCIRecipeBuildJobType.REGISTRY_UPLOAD, {})
+ build, OCIRecipeBuildJobType.REGISTRY_UPLOAD, {}
+ )
store.add(job)
return job
- def makeOCIRegistryCredentials(self, registrant=None, owner=None, url=None,
- credentials=None):
+ def makeOCIRegistryCredentials(
+ self, registrant=None, owner=None, url=None, credentials=None
+ ):
"""Make a new OCIRegistryCredentials."""
if registrant is None:
registrant = self.makePerson()
@@ -5305,14 +6610,19 @@ class LaunchpadObjectFactory(ObjectFactory):
url = self.getUniqueURL()
if credentials is None:
credentials = {
- 'username': self.getUniqueUnicode(),
- 'password': self.getUniqueUnicode()}
+ "username": self.getUniqueUnicode(),
+ "password": self.getUniqueUnicode(),
+ }
return getUtility(IOCIRegistryCredentialsSet).new(
- registrant=registrant, owner=owner, url=url,
- credentials=credentials)
+ registrant=registrant,
+ owner=owner,
+ url=url,
+ credentials=credentials,
+ )
- def makeOCIPushRule(self, recipe=None, registry_credentials=None,
- image_name=None):
+ def makeOCIPushRule(
+ self, recipe=None, registry_credentials=None, image_name=None
+ ):
"""Make a new OCIPushRule."""
if recipe is None:
recipe = self.makeOCIRecipe()
@@ -5323,16 +6633,29 @@ class LaunchpadObjectFactory(ObjectFactory):
return getUtility(IOCIPushRuleSet).new(
recipe=recipe,
registry_credentials=registry_credentials,
- image_name=image_name)
-
- def makeCharmRecipe(self, registrant=None, owner=None, project=None,
- name=None, description=None, git_ref=None,
- build_path=None, require_virtualized=True,
- information_type=InformationType.PUBLIC,
- auto_build=False, auto_build_channels=None,
- is_stale=None, store_upload=False, store_name=None,
- store_secrets=None, store_channels=None,
- date_created=DEFAULT):
+ image_name=image_name,
+ )
+
+ def makeCharmRecipe(
+ self,
+ registrant=None,
+ owner=None,
+ project=None,
+ name=None,
+ description=None,
+ git_ref=None,
+ build_path=None,
+ require_virtualized=True,
+ information_type=InformationType.PUBLIC,
+ auto_build=False,
+ auto_build_channels=None,
+ is_stale=None,
+ store_upload=False,
+ store_name=None,
+ store_secrets=None,
+ store_channels=None,
+ date_created=DEFAULT,
+ ):
"""Make a new charm recipe."""
if registrant is None:
registrant = self.makePerson()
@@ -5340,37 +6663,55 @@ class LaunchpadObjectFactory(ObjectFactory):
if owner is None:
# Private charm recipes cannot be owned by non-moderated teams.
membership_policy = (
- TeamMembershipPolicy.OPEN if private
- else TeamMembershipPolicy.MODERATED)
+ TeamMembershipPolicy.OPEN
+ if private
+ else TeamMembershipPolicy.MODERATED
+ )
owner = self.makeTeam(
- registrant, membership_policy=membership_policy)
+ registrant, membership_policy=membership_policy
+ )
if project is None:
branch_sharing_policy = (
- BranchSharingPolicy.PUBLIC if not private
- else BranchSharingPolicy.PROPRIETARY)
+ BranchSharingPolicy.PUBLIC
+ if not private
+ else BranchSharingPolicy.PROPRIETARY
+ )
project = self.makeProduct(
- owner=registrant, registrant=registrant,
+ owner=registrant,
+ registrant=registrant,
information_type=information_type,
- branch_sharing_policy=branch_sharing_policy)
+ branch_sharing_policy=branch_sharing_policy,
+ )
if name is None:
name = self.getUniqueUnicode("charm-name")
if git_ref is None:
git_ref = self.makeGitRefs()[0]
recipe = getUtility(ICharmRecipeSet).new(
- registrant=registrant, owner=owner, project=project, name=name,
- description=description, git_ref=git_ref, build_path=build_path,
+ registrant=registrant,
+ owner=owner,
+ project=project,
+ name=name,
+ description=description,
+ git_ref=git_ref,
+ build_path=build_path,
require_virtualized=require_virtualized,
- information_type=information_type, auto_build=auto_build,
- auto_build_channels=auto_build_channels, store_upload=store_upload,
- store_name=store_name, store_secrets=store_secrets,
- store_channels=store_channels, date_created=date_created)
+ information_type=information_type,
+ auto_build=auto_build,
+ auto_build_channels=auto_build_channels,
+ store_upload=store_upload,
+ store_name=store_name,
+ store_secrets=store_secrets,
+ store_channels=store_channels,
+ date_created=date_created,
+ )
if is_stale is not None:
removeSecurityProxy(recipe).is_stale = is_stale
IStore(recipe).flush()
return recipe
- def makeCharmRecipeBuildRequest(self, recipe=None, requester=None,
- channels=None, architectures=None):
+ def makeCharmRecipeBuildRequest(
+ self, recipe=None, requester=None, channels=None, architectures=None
+ ):
"""Make a new CharmRecipeBuildRequest."""
if recipe is None:
recipe = self.makeCharmRecipe()
@@ -5380,14 +6721,24 @@ class LaunchpadObjectFactory(ObjectFactory):
else:
requester = recipe.owner
return recipe.requestBuilds(
- requester, channels=channels, architectures=architectures)
-
- def makeCharmRecipeBuild(self, registrant=None, recipe=None,
- build_request=None, requester=None,
- distro_arch_series=None, channels=None,
- store_upload_metadata=None, date_created=DEFAULT,
- status=BuildStatus.NEEDSBUILD, builder=None,
- duration=None, **kwargs):
+ requester, channels=channels, architectures=architectures
+ )
+
+ def makeCharmRecipeBuild(
+ self,
+ registrant=None,
+ recipe=None,
+ build_request=None,
+ requester=None,
+ distro_arch_series=None,
+ channels=None,
+ store_upload_metadata=None,
+ date_created=DEFAULT,
+ status=BuildStatus.NEEDSBUILD,
+ builder=None,
+ duration=None,
+ **kwargs
+ ):
if recipe is None:
if registrant is None:
if build_request is not None:
@@ -5399,18 +6750,27 @@ class LaunchpadObjectFactory(ObjectFactory):
distro_arch_series = self.makeDistroArchSeries()
if build_request is None:
build_request = self.makeCharmRecipeBuildRequest(
- recipe=recipe, requester=requester, channels=channels)
+ recipe=recipe, requester=requester, channels=channels
+ )
build = getUtility(ICharmRecipeBuildSet).new(
- build_request, recipe, distro_arch_series, channels=channels,
+ build_request,
+ recipe,
+ distro_arch_series,
+ channels=channels,
store_upload_metadata=store_upload_metadata,
- date_created=date_created)
+ date_created=date_created,
+ )
if duration is not None:
removeSecurityProxy(build).updateStatus(
- BuildStatus.BUILDING, builder=builder,
- date_started=build.date_created)
+ BuildStatus.BUILDING,
+ builder=builder,
+ date_started=build.date_created,
+ )
removeSecurityProxy(build).updateStatus(
- status, builder=builder,
- date_finished=build.date_started + duration)
+ status,
+ builder=builder,
+ date_finished=build.date_started + duration,
+ )
else:
removeSecurityProxy(build).updateStatus(status, builder=builder)
IStore(build).flush()
@@ -5423,9 +6783,14 @@ class LaunchpadObjectFactory(ObjectFactory):
library_file = self.makeLibraryFileAlias()
return ProxyFactory(CharmFile(build=build, library_file=library_file))
- def makeCharmBase(self, registrant=None, distro_series=None,
- build_snap_channels=None, processors=None,
- date_created=DEFAULT):
+ def makeCharmBase(
+ self,
+ registrant=None,
+ distro_series=None,
+ build_snap_channels=None,
+ processors=None,
+ date_created=DEFAULT,
+ ):
"""Make a new CharmBase."""
if registrant is None:
registrant = self.makePerson()
@@ -5434,13 +6799,24 @@ class LaunchpadObjectFactory(ObjectFactory):
if build_snap_channels is None:
build_snap_channels = {"charmcraft": "stable"}
return getUtility(ICharmBaseSet).new(
- registrant, distro_series, build_snap_channels,
- processors=processors, date_created=date_created)
+ registrant,
+ distro_series,
+ build_snap_channels,
+ processors=processors,
+ date_created=date_created,
+ )
- def makeCIBuild(self, git_repository=None, commit_sha1=None,
- distro_arch_series=None, stages=None, date_created=DEFAULT,
- status=BuildStatus.NEEDSBUILD, builder=None,
- duration=None):
+ def makeCIBuild(
+ self,
+ git_repository=None,
+ commit_sha1=None,
+ distro_arch_series=None,
+ stages=None,
+ date_created=DEFAULT,
+ status=BuildStatus.NEEDSBUILD,
+ builder=None,
+ duration=None,
+ ):
"""Make a new `CIBuild`."""
if git_repository is None:
git_repository = self.makeGitRepository()
@@ -5451,25 +6827,42 @@ class LaunchpadObjectFactory(ObjectFactory):
if stages is None:
stages = [[("test", 0)]]
build = getUtility(ICIBuildSet).new(
- git_repository, commit_sha1, distro_arch_series, stages,
- date_created=date_created)
+ git_repository,
+ commit_sha1,
+ distro_arch_series,
+ stages,
+ date_created=date_created,
+ )
if duration is not None:
removeSecurityProxy(build).updateStatus(
- BuildStatus.BUILDING, builder=builder,
- date_started=build.date_created)
+ BuildStatus.BUILDING,
+ builder=builder,
+ date_started=build.date_created,
+ )
removeSecurityProxy(build).updateStatus(
- status, builder=builder,
- date_finished=build.date_started + duration)
+ status,
+ builder=builder,
+ date_finished=build.date_started + duration,
+ )
else:
removeSecurityProxy(build).updateStatus(status, builder=builder)
IStore(build).flush()
return build
- def makeVulnerability(self, distribution=None, status=None,
- importance=None, creator=None,
- information_type=InformationType.PUBLIC, cve=None,
- description=None, notes=None, mitigation=None,
- importance_explanation=None, date_made_public=None):
+ def makeVulnerability(
+ self,
+ distribution=None,
+ status=None,
+ importance=None,
+ creator=None,
+ information_type=InformationType.PUBLIC,
+ cve=None,
+ description=None,
+ notes=None,
+ mitigation=None,
+ importance_explanation=None,
+ date_made_public=None,
+ ):
"""Make a new `Vulnerability`."""
if distribution is None:
distribution = self.makeDistribution()
@@ -5481,19 +6874,30 @@ class LaunchpadObjectFactory(ObjectFactory):
creator = self.makePerson()
if importance_explanation is None:
importance_explanation = self.getUniqueString(
- "vulnerability-importance-explanation")
- return getUtility(
- IVulnerabilitySet).new(
- distribution=distribution, cve=cve, status=status,
- importance=importance, creator=creator,
- information_type=information_type, description=description,
- notes=notes, mitigation=mitigation,
+ "vulnerability-importance-explanation"
+ )
+ return getUtility(IVulnerabilitySet).new(
+ distribution=distribution,
+ cve=cve,
+ status=status,
+ importance=importance,
+ creator=creator,
+ information_type=information_type,
+ description=description,
+ notes=notes,
+ mitigation=mitigation,
importance_explanation=importance_explanation,
- date_made_public=date_made_public)
+ date_made_public=date_made_public,
+ )
- def makeVulnerabilityActivity(self, vulnerability=None, changer=None,
- what_changed=None, old_value=None,
- new_value=None):
+ def makeVulnerabilityActivity(
+ self,
+ vulnerability=None,
+ changer=None,
+ what_changed=None,
+ old_value=None,
+ new_value=None,
+ ):
"""Make a new `VulnerabilityActivity`."""
if vulnerability is None:
vulnerability = self.makeVulnerability()
@@ -5505,25 +6909,28 @@ class LaunchpadObjectFactory(ObjectFactory):
old_value = self.getUniqueString("old-value")
if new_value is None:
new_value = self.getUniqueString("new-value")
- return getUtility(
- IVulnerabilityActivitySet).new(vulnerability=vulnerability,
- changer=changer,
- what_changed=what_changed,
- old_value=old_value,
- new_value=new_value)
+ return getUtility(IVulnerabilityActivitySet).new(
+ vulnerability=vulnerability,
+ changer=changer,
+ what_changed=what_changed,
+ old_value=old_value,
+ new_value=new_value,
+ )
# Some factory methods return simple Python types. We don't add
# security wrappers for them, as well as for objects created by
# other Python libraries.
-unwrapped_types = frozenset({
- BaseRecipeBranch,
- DSCFile,
- Message,
- datetime,
- int,
- str,
- })
+unwrapped_types = frozenset(
+ {
+ BaseRecipeBranch,
+ DSCFile,
+ Message,
+ datetime,
+ int,
+ str,
+ }
+)
def is_security_proxied_or_harmless(obj):
@@ -5535,14 +6942,15 @@ def is_security_proxied_or_harmless(obj):
if type(obj) in unwrapped_types:
return True
if isinstance(obj, (Sequence, set, frozenset)):
- return all(
- is_security_proxied_or_harmless(element)
- for element in obj)
+ return all(is_security_proxied_or_harmless(element) for element in obj)
if isinstance(obj, Mapping):
return all(
- (is_security_proxied_or_harmless(key) and
- is_security_proxied_or_harmless(obj[key]))
- for key in obj)
+ (
+ is_security_proxied_or_harmless(key)
+ and is_security_proxied_or_harmless(obj[key])
+ )
+ for key in obj
+ )
return False
@@ -5552,7 +6960,8 @@ class UnproxiedFactoryMethodWarning(UserWarning):
def __init__(self, method_name):
super().__init__(
"PLEASE FIX: LaunchpadObjectFactory.%s returns an "
- "unproxied object." % (method_name, ))
+ "unproxied object." % (method_name,)
+ )
class ShouldThisBeUsingRemoveSecurityProxy(UserWarning):
@@ -5561,7 +6970,8 @@ class ShouldThisBeUsingRemoveSecurityProxy(UserWarning):
def __init__(self, obj):
message = (
"removeSecurityProxy(%r) called. Is this correct? "
- "Either call it directly or fix the test." % obj)
+ "Either call it directly or fix the test." % obj
+ )
super().__init__(message)
@@ -5575,6 +6985,6 @@ def remove_security_proxy_and_shout_at_engineer(obj):
This function should only be used in legacy tests which fail because
they expect unproxied objects.
"""
- if os.environ.get('LP_PROXY_WARNINGS') == '1':
+ if os.environ.get("LP_PROXY_WARNINGS") == "1":
warnings.warn(ShouldThisBeUsingRemoveSecurityProxy(obj), stacklevel=2)
return removeSecurityProxy(obj)
diff --git a/lib/lp/testing/fakemethod.py b/lib/lp/testing/fakemethod.py
index d3a7df7..7fcd87b 100644
--- a/lib/lp/testing/fakemethod.py
+++ b/lib/lp/testing/fakemethod.py
@@ -2,8 +2,8 @@
# GNU Affero General Public License version 3 (see the file LICENSE).
__all__ = [
- 'FakeMethod',
- ]
+ "FakeMethod",
+]
class FakeMethod:
diff --git a/lib/lp/testing/faketransaction.py b/lib/lp/testing/faketransaction.py
index 3c3d786..b5b7623 100644
--- a/lib/lp/testing/faketransaction.py
+++ b/lib/lp/testing/faketransaction.py
@@ -3,7 +3,7 @@
"""Fake transaction manager."""
-__all__ = ['FakeTransaction']
+__all__ = ["FakeTransaction"]
class FakeTransaction:
@@ -14,6 +14,7 @@ class FakeTransaction:
Set `log_calls` to True to enable printing of commits and aborts.
"""
+
commit_count = 0
def __init__(self, log_calls=False):
diff --git a/lib/lp/testing/fixture.py b/lib/lp/testing/fixture.py
index 9effd7f..f112eb1 100644
--- a/lib/lp/testing/fixture.py
+++ b/lib/lp/testing/fixture.py
@@ -4,46 +4,39 @@
"""Launchpad test fixtures that have no better home."""
__all__ = [
- 'CapturedOutput',
- 'CaptureOops',
- 'DemoMode',
- 'DisableTriggerFixture',
- 'PGBouncerFixture',
- 'PGNotReadyError',
- 'run_capturing_output',
- 'ZopeAdapterFixture',
- 'ZopeEventHandlerFixture',
- 'ZopeUtilityFixture',
- 'ZopeViewReplacementFixture',
- ]
+ "CapturedOutput",
+ "CaptureOops",
+ "DemoMode",
+ "DisableTriggerFixture",
+ "PGBouncerFixture",
+ "PGNotReadyError",
+ "run_capturing_output",
+ "ZopeAdapterFixture",
+ "ZopeEventHandlerFixture",
+ "ZopeUtilityFixture",
+ "ZopeViewReplacementFixture",
+]
-from configparser import ConfigParser
import io
import os.path
import socket
import time
+from configparser import ConfigParser
import amqp
-from fixtures import (
- EnvironmentVariableFixture,
- Fixture,
- MonkeyPatch,
- )
-from lazr.restful.utils import get_current_browser_request
import oops
import oops_amqp
import pgbouncer.fixture
-from zope.component import (
- adapter,
- getGlobalSiteManager,
- )
+from fixtures import EnvironmentVariableFixture, Fixture, MonkeyPatch
+from lazr.restful.utils import get_current_browser_request
+from zope.component import adapter, getGlobalSiteManager
from zope.interface import Interface
from zope.publisher.interfaces.browser import IDefaultBrowserLayer
from zope.security.checker import (
defineChecker,
getCheckerForInstancesOf,
undefineChecker,
- )
+)
from lp.services import webapp
from lp.services.config import config
@@ -72,29 +65,32 @@ class PGBouncerFixture(pgbouncer.fixture.PGBouncerFixture):
# Known databases
from lp.testing.layers import DatabaseLayer
+
dbnames = [
DatabaseLayer._db_fixture.dbname,
DatabaseLayer._db_template_fixture.dbname,
- 'session_ftest',
- 'launchpad_empty',
- ]
+ "session_ftest",
+ "launchpad_empty",
+ ]
for dbname in dbnames:
- self.databases[dbname] = 'dbname=%s port=5432 host=localhost' % (
- dbname,)
+ self.databases[dbname] = "dbname=%s port=5432 host=localhost" % (
+ dbname,
+ )
# Known users, pulled from security.cfg
security_cfg_path = os.path.join(
- config.root, 'database', 'schema', 'security.cfg')
+ config.root, "database", "schema", "security.cfg"
+ )
security_cfg_config = ConfigParser({})
security_cfg_config.read([security_cfg_path])
for section_name in security_cfg_config.sections():
- self.users[section_name] = 'trusted'
- self.users[section_name + '_ro'] = 'trusted'
- self.users[os.environ['USER']] = 'trusted'
- self.users['pgbouncer'] = 'trusted'
+ self.users[section_name] = "trusted"
+ self.users[section_name + "_ro"] = "trusted"
+ self.users[os.environ["USER"]] = "trusted"
+ self.users["pgbouncer"] = "trusted"
# Administrative access is useful for debugging.
- self.admin_users = ['launchpad', 'pgbouncer', os.environ['USER']]
+ self.admin_users = ["launchpad", "pgbouncer", os.environ["USER"]]
def setUp(self):
super().setUp()
@@ -106,9 +102,9 @@ class PGBouncerFixture(pgbouncer.fixture.PGBouncerFixture):
# Abuse the PGPORT environment variable to get things connecting
# via pgbouncer. Otherwise, we would need to temporarily
# overwrite the database connection strings in the config.
- self.useFixture(EnvironmentVariableFixture('PGPORT', str(self.port)))
+ self.useFixture(EnvironmentVariableFixture("PGPORT", str(self.port)))
# Force TCP, as pgbouncer doesn't listen on a UNIX socket.
- self.useFixture(EnvironmentVariableFixture('PGHOST', 'localhost'))
+ self.useFixture(EnvironmentVariableFixture("PGHOST", "localhost"))
# Reset database connections so they go through pgbouncer.
self._maybe_reconnect_stores()
@@ -120,16 +116,13 @@ class PGBouncerFixture(pgbouncer.fixture.PGBouncerFixture):
as we are using a test layer that doesn't provide database
connections.
"""
- from lp.testing.layers import (
- is_ca_available,
- reconnect_stores,
- )
+ from lp.testing.layers import is_ca_available, reconnect_stores
+
if is_ca_available():
reconnect_stores()
def start(self, retries=20, sleep=0.5):
- """Start PGBouncer, waiting for it to accept connections if neccesary.
- """
+ """Start PGBouncer, waiting for it to accept connections."""
super().start()
for i in range(retries):
try:
@@ -147,8 +140,15 @@ class PGBouncerFixture(pgbouncer.fixture.PGBouncerFixture):
class ZopeAdapterFixture(Fixture):
"""A fixture to register and unregister an adapter."""
- def __init__(self, factory, required=None, provided=None, name="",
- info="", event=True):
+ def __init__(
+ self,
+ factory,
+ required=None,
+ provided=None,
+ name="",
+ info="",
+ event=True,
+ ):
# We use some private functions from here since we need them to work
# out how to query for existing adapters. We could copy and paste
# the code instead, but it doesn't seem worth it.
@@ -166,15 +166,26 @@ class ZopeAdapterFixture(Fixture):
def _setUp(self):
site_manager = getGlobalSiteManager()
original = site_manager.adapters.lookup(
- self._required, self._provided, self._name)
+ self._required, self._provided, self._name
+ )
site_manager.registerAdapter(
- self._factory, required=self._required, provided=self._provided,
- name=self._name, info=self._info, event=self._event)
+ self._factory,
+ required=self._required,
+ provided=self._provided,
+ name=self._name,
+ info=self._info,
+ event=self._event,
+ )
# Equivalent to unregisterAdapter if original is None.
self.addCleanup(
site_manager.registerAdapter,
- original, required=self._required, provided=self._provided,
- name=self._name, info=self._info, event=self._event)
+ original,
+ required=self._required,
+ provided=self._provided,
+ name=self._name,
+ info=self._info,
+ event=self._event,
+ )
class ZopeEventHandlerFixture(Fixture):
@@ -189,7 +200,8 @@ class ZopeEventHandlerFixture(Fixture):
gsm = getGlobalSiteManager()
gsm.registerHandler(self._handler, required=self._required)
self.addCleanup(
- gsm.unregisterHandler, self._handler, required=self._required)
+ gsm.unregisterHandler, self._handler, required=self._required
+ )
class ZopeViewReplacementFixture(Fixture):
@@ -198,9 +210,13 @@ class ZopeViewReplacementFixture(Fixture):
This will not work with the AppServerLayer.
"""
- def __init__(self, name, context_interface,
- request_interface=IDefaultBrowserLayer,
- replacement=None):
+ def __init__(
+ self,
+ name,
+ context_interface,
+ request_interface=IDefaultBrowserLayer,
+ replacement=None,
+ ):
super().__init__()
self.name = name
self.context_interface = context_interface
@@ -209,33 +225,39 @@ class ZopeViewReplacementFixture(Fixture):
# It can be convenient--bordering on necessary--to use this original
# class as a base for the replacement.
self.original = self.gsm.adapters.registered(
- (context_interface, request_interface), Interface, name)
+ (context_interface, request_interface), Interface, name
+ )
self.checker = getCheckerForInstancesOf(self.original)
if self.original is None:
# The adapter registry does not provide good methods to introspect
# it. If it did, we might try harder here.
raise ValueError(
- 'No existing view to replace. Wrong request interface? '
- 'Try a layer.')
+ "No existing view to replace. Wrong request interface? "
+ "Try a layer."
+ )
self.replacement = replacement
def _setUp(self):
if self.replacement is None:
- raise ValueError('replacement is not set')
+ raise ValueError("replacement is not set")
self.gsm.adapters.register(
- (self.context_interface, self.request_interface), Interface,
- self.name, self.replacement)
+ (self.context_interface, self.request_interface),
+ Interface,
+ self.name,
+ self.replacement,
+ )
# The same checker should be sufficient. If it ever isn't, we
# can add more flexibility then.
defineChecker(self.replacement, self.checker)
- self.addCleanup(
- undefineChecker, self.replacement)
+ self.addCleanup(undefineChecker, self.replacement)
self.addCleanup(
self.gsm.adapters.register,
(self.context_interface, self.request_interface),
Interface,
- self.name, self.original)
+ self.name,
+ self.original,
+ )
class ZopeUtilityFixture(Fixture):
@@ -260,10 +282,11 @@ class ZopeUtilityFixture(Fixture):
gsm.registerUtility(self.component, self.intf, self.name)
if original is not None:
self.addCleanup(
- gsm.registerUtility, original, self.intf, self.name)
+ gsm.registerUtility, original, self.intf, self.name
+ )
self.addCleanup(
- gsm.unregisterUtility,
- self.component, self.intf, self.name)
+ gsm.unregisterUtility, self.component, self.intf, self.name
+ )
class CapturedOutput(Fixture):
@@ -275,8 +298,8 @@ class CapturedOutput(Fixture):
self.stderr = io.StringIO()
def _setUp(self):
- self.useFixture(MonkeyPatch('sys.stdout', self.stdout))
- self.useFixture(MonkeyPatch('sys.stderr', self.stderr))
+ self.useFixture(MonkeyPatch("sys.stdout", self.stdout))
+ self.useFixture(MonkeyPatch("sys.stderr", self.stderr))
def run_capturing_output(function, *args, **kwargs):
@@ -328,27 +351,34 @@ class CaptureOops(Fixture):
that it will be automatically nuked and must be recreated.
"""
self.queue_name, _, _ = self.channel.queue_declare(
- durable=True, auto_delete=False)
+ durable=True, auto_delete=False
+ )
self.addCleanup(self.channel.queue_delete, self.queue_name)
# In production the exchange already exists and is durable, but
# here we make it just-in-time, and tell it to go when the test
# fixture goes.
- self.channel.exchange_declare(config.error_reports.error_exchange,
- "fanout", durable=True, auto_delete=False)
+ self.channel.exchange_declare(
+ config.error_reports.error_exchange,
+ "fanout",
+ durable=True,
+ auto_delete=False,
+ )
self.addCleanup(
- self.channel.exchange_delete, config.error_reports.error_exchange)
+ self.channel.exchange_delete, config.error_reports.error_exchange
+ )
self.channel.queue_bind(
- self.queue_name, config.error_reports.error_exchange)
+ self.queue_name, config.error_reports.error_exchange
+ )
def _add_oops(self, report):
"""Add an oops if it isn't already recorded.
This is called from both amqp and in-appserver situations.
"""
- if report['id'] not in self.oops_ids:
+ if report["id"] not in self.oops_ids:
self.oopses.append(report)
- self.oops_ids.add(report['id'])
- return [report['id']]
+ self.oops_ids.add(report["id"])
+ return [report["id"]]
@adapter(ErrorReportEvent)
def _recordOops(self, event):
@@ -371,14 +401,17 @@ class CaptureOops(Fixture):
channel = connection.channel()
try:
channel.basic_publish(
- message, config.error_reports.error_exchange,
- config.error_reports.error_queue_key)
+ message,
+ config.error_reports.error_exchange,
+ config.error_reports.error_queue_key,
+ )
finally:
channel.close()
finally:
connection.close()
receiver = oops_amqp.Receiver(
- self.oops_config, connect, self.queue_name)
+ self.oops_config, connect, self.queue_name
+ )
receiver.sentinel = self.AMQP_SENTINEL
try:
receiver.run_forever()
@@ -397,8 +430,7 @@ class CaptureTimeline(Fixture):
def _setUp(self):
webapp.adapter.set_request_started(time.time())
- self.timeline = get_request_timeline(
- get_current_browser_request())
+ self.timeline = get_request_timeline(get_current_browser_request())
self.addCleanup(webapp.adapter.clear_request_started)
@@ -410,13 +442,16 @@ class DemoMode(Fixture):
"""
def _setUp(self):
- config.push('demo-fixture', '''
+ config.push(
+ "demo-fixture",
+ """
[launchpad]
is_demo: true
site_message = This is a demo site mmk. \
<a href="http://example.com">File a bug</a>.
- ''')
- self.addCleanup(lambda: config.pop('demo-fixture'))
+ """,
+ )
+ self.addCleanup(lambda: config.pop("demo-fixture"))
class DisableTriggerFixture(Fixture):
@@ -430,17 +465,15 @@ class DisableTriggerFixture(Fixture):
self.addCleanup(self._enable_triggers)
def _process_triggers(self, mode):
- with dbuser('postgres'):
+ with dbuser("postgres"):
for table, trigger in self.table_triggers.items():
- sql = ("ALTER TABLE %(table)s %(mode)s trigger "
- "%(trigger)s") % {
- 'table': table,
- 'mode': mode,
- 'trigger': trigger}
+ sql = (
+ "ALTER TABLE %(table)s %(mode)s trigger " "%(trigger)s"
+ ) % {"table": table, "mode": mode, "trigger": trigger}
IStore(LibraryFileAlias).execute(sql)
def _disable_triggers(self):
- self._process_triggers(mode='DISABLE')
+ self._process_triggers(mode="DISABLE")
def _enable_triggers(self):
- self._process_triggers(mode='ENABLE')
+ self._process_triggers(mode="ENABLE")
diff --git a/lib/lp/testing/gpgkeys/__init__.py b/lib/lp/testing/gpgkeys/__init__.py
index 482e049..46b9581 100644
--- a/lib/lp/testing/gpgkeys/__init__.py
+++ b/lib/lp/testing/gpgkeys/__init__.py
@@ -16,8 +16,8 @@ Secret keys are also imported into the local key ring, they are used for
decrypt data in pagetests.
"""
-from io import BytesIO
import os
+from io import BytesIO
import gpgme
import six
@@ -25,13 +25,9 @@ from zope.component import getUtility
from lp.registry.interfaces.gpg import IGPGKeySet
from lp.registry.interfaces.person import IPersonSet
-from lp.services.gpg.interfaces import (
- get_gpgme_context,
- IGPGHandler,
- )
+from lp.services.gpg.interfaces import IGPGHandler, get_gpgme_context
-
-gpgkeysdir = os.path.join(os.path.dirname(__file__), 'data')
+gpgkeysdir = os.path.join(os.path.dirname(__file__), "data")
def import_public_key(email_addr):
@@ -43,10 +39,10 @@ def import_public_key(email_addr):
key = gpghandler.importPublicKey(pubkey)
# Strip out any '-passwordless' annotation from the email addresses.
- email_addr = email_addr.replace('-passwordless', '')
+ email_addr = email_addr.replace("-passwordless", "")
# Some of the keys shouldn't be inserted into the db.
- if email_addr.endswith('do-not-insert-into-db'):
+ if email_addr.endswith("do-not-insert-into-db"):
return
person = personset.getByEmail(email_addr)
@@ -69,13 +65,14 @@ def import_public_key(email_addr):
fingerprint=key.fingerprint,
keysize=key.keysize,
algorithm=key.algorithm,
- active=(not key.revoked))
+ active=(not key.revoked),
+ )
def iter_test_key_emails():
"""Iterates over the email addresses for the keys in the gpgkeysdir."""
for name in sorted(os.listdir(gpgkeysdir), reverse=True):
- if name.endswith('.pub'):
+ if name.endswith(".pub"):
yield name[:-4]
@@ -85,32 +82,32 @@ def import_public_test_keys():
import_public_key(email)
-def import_secret_test_key(keyfile='test@xxxxxxxxxxxxxxxxx'):
+def import_secret_test_key(keyfile="test@xxxxxxxxxxxxxxxxx"):
"""Imports the secret key located in gpgkeysdir into local keyring.
:param keyfile: The name of the file to be imported.
"""
gpghandler = getUtility(IGPGHandler)
- with open(os.path.join(gpgkeysdir, keyfile), 'rb') as f:
+ with open(os.path.join(gpgkeysdir, keyfile), "rb") as f:
seckey = f.read()
return gpghandler.importSecretKey(seckey)
def test_pubkey_file_from_email(email_addr):
"""Get the file name for a test pubkey by email address."""
- return os.path.join(gpgkeysdir, email_addr + '.pub')
+ return os.path.join(gpgkeysdir, email_addr + ".pub")
def test_pubkey_from_email(email_addr):
"""Get the on disk content for a test pubkey by email address."""
- with open(test_pubkey_file_from_email(email_addr), 'rb') as f:
+ with open(test_pubkey_file_from_email(email_addr), "rb") as f:
return f.read()
def test_keyrings():
"""Iterate over the filenames for test keyrings."""
for entry in os.scandir(gpgkeysdir):
- if entry.name.endswith('.gpg'):
+ if entry.name.endswith(".gpg"):
yield entry.path
@@ -124,10 +121,10 @@ def decrypt_content(content, password):
:password: password to unlock the secret key in question
"""
if not isinstance(password, str):
- raise TypeError('Password must be a str.')
+ raise TypeError("Password must be a str.")
if not isinstance(content, bytes):
- raise TypeError('Content must be bytes.')
+ raise TypeError("Content must be bytes.")
ctx = get_gpgme_context()
@@ -136,7 +133,7 @@ def decrypt_content(content, password):
plain = BytesIO()
def passphrase_cb(uid_hint, passphrase_info, prev_was_bad, fd):
- os.write(fd, six.ensure_binary('%s\n' % password))
+ os.write(fd, six.ensure_binary("%s\n" % password))
ctx.passphrase_cb = passphrase_cb
diff --git a/lib/lp/testing/html5browser.py b/lib/lp/testing/html5browser.py
index 7230ab2..ef19904 100644
--- a/lib/lp/testing/html5browser.py
+++ b/lib/lp/testing/html5browser.py
@@ -24,25 +24,21 @@
"""A Web browser that can be driven by an application."""
__all__ = [
- 'Browser',
- 'Command',
- ]
+ "Browser",
+ "Command",
+]
import gi
+gi.require_version("Gtk", "3.0")
+gi.require_version("WebKit", "3.0")
-gi.require_version('Gtk', '3.0')
-gi.require_version('WebKit', '3.0')
-
-from gi.repository import ( # noqa: E402
- GLib,
- Gtk,
- WebKit,
- )
+from gi.repository import GLib, Gtk, WebKit # noqa: E402
class Command:
"""A representation of the status and result of a command."""
+
STATUS_RUNNING = object()
STATUS_COMPLETE = object()
@@ -50,8 +46,9 @@ class Command:
CODE_SUCCESS = 0
CODE_FAIL = 1
- def __init__(self, status=STATUS_RUNNING, return_code=CODE_UNKNOWN,
- content=None):
+ def __init__(
+ self, status=STATUS_RUNNING, return_code=CODE_UNKNOWN, content=None
+ ):
self.status = status
self.return_code = return_code
self.content = content
@@ -60,9 +57,9 @@ class Command:
class Browser(WebKit.WebView):
"""A browser that can be driven by an application."""
- STATUS_PREFIX = '::::'
+ STATUS_PREFIX = "::::"
TIMEOUT = 5000
- INCREMENTAL_PREFIX = '>>>>'
+ INCREMENTAL_PREFIX = ">>>>"
INITIAL_TIMEOUT = None
INCREMENTAL_TIMEOUT = None
@@ -74,51 +71,65 @@ class Browser(WebKit.WebView):
self.script = None
self.command = None
self.listeners = {}
- self._connect('console-message', self._on_console_message, False)
-
- def load_page(self, uri,
- timeout=TIMEOUT,
- initial_timeout=INITIAL_TIMEOUT,
- incremental_timeout=INCREMENTAL_TIMEOUT):
+ self._connect("console-message", self._on_console_message, False)
+
+ def load_page(
+ self,
+ uri,
+ timeout=TIMEOUT,
+ initial_timeout=INITIAL_TIMEOUT,
+ incremental_timeout=INCREMENTAL_TIMEOUT,
+ ):
"""Load a page and return the content."""
self._setup_listening_operation(
- timeout, initial_timeout, incremental_timeout)
- if uri.startswith('/'):
- uri = 'file://' + uri
+ timeout, initial_timeout, incremental_timeout
+ )
+ if uri.startswith("/"):
+ uri = "file://" + uri
self.load_uri(uri)
Gtk.main()
return self.command
- def run_script(self, script,
- timeout=TIMEOUT,
- initial_timeout=INITIAL_TIMEOUT,
- incremental_timeout=INCREMENTAL_TIMEOUT):
+ def run_script(
+ self,
+ script,
+ timeout=TIMEOUT,
+ initial_timeout=INITIAL_TIMEOUT,
+ incremental_timeout=INCREMENTAL_TIMEOUT,
+ ):
"""Run a script and return the result."""
self._setup_listening_operation(
- timeout, initial_timeout, incremental_timeout)
+ timeout, initial_timeout, incremental_timeout
+ )
self.script = script
- self._connect('notify::load-status', self._on_script_load_finished)
+ self._connect("notify::load-status", self._on_script_load_finished)
self.load_string(
- '<html><head></head><body></body></html>',
- 'text/html', 'UTF-8', 'file:///')
+ "<html><head></head><body></body></html>",
+ "text/html",
+ "UTF-8",
+ "file:///",
+ )
Gtk.main()
return self.command
- def _setup_listening_operation(self, timeout, initial_timeout,
- incremental_timeout):
+ def _setup_listening_operation(
+ self, timeout, initial_timeout, incremental_timeout
+ ):
"""Setup a one-time listening operation for command's completion."""
self._create_window()
self.command = Command()
self._last_status = None
self._incremental_timeout = incremental_timeout
self._connect(
- 'status-bar-text-changed', self._on_status_bar_text_changed)
+ "status-bar-text-changed", self._on_status_bar_text_changed
+ )
self._timeout_source = GLib.timeout_add(timeout, self._on_timeout)
if initial_timeout is None:
initial_timeout = incremental_timeout
if initial_timeout is not None:
self._incremental_timeout_source = GLib.timeout_add(
- initial_timeout, self._on_timeout)
+ initial_timeout, self._on_timeout
+ )
else:
self._incremental_timeout_source = None
@@ -148,11 +159,12 @@ class Browser(WebKit.WebView):
self._last_status = text[4:]
if self._incremental_timeout:
self._incremental_timeout_source = GLib.timeout_add(
- self._incremental_timeout, self._on_timeout)
+ self._incremental_timeout, self._on_timeout
+ )
elif text.startswith(self.STATUS_PREFIX):
self._clear_timeout()
self._clear_incremental_timeout()
- self._disconnect('status-bar-text-changed')
+ self._disconnect("status-bar-text-changed")
self._clear_status()
self.command.status = Command.STATUS_COMPLETE
self.command.return_code = Command.CODE_SUCCESS
@@ -161,10 +173,10 @@ class Browser(WebKit.WebView):
def _on_script_load_finished(self, view, load_status):
# pywebkit does not have WebKit.LoadStatus.FINISHED.
- statuses = ('WEBKIT_LOAD_FINISHED', 'WEBKIT_LOAD_FAILED')
+ statuses = ("WEBKIT_LOAD_FINISHED", "WEBKIT_LOAD_FAILED")
if self.props.load_status.value_name not in statuses:
return
- self._disconnect('notify::load-status')
+ self._disconnect("notify::load-status")
self.execute_script(self.script)
self.script = None
diff --git a/lib/lp/testing/karma.py b/lib/lp/testing/karma.py
index 0393a4b..d59764e 100644
--- a/lib/lp/testing/karma.py
+++ b/lib/lp/testing/karma.py
@@ -4,9 +4,9 @@
"""Helper functions/classes to be used when testing the karma framework."""
__all__ = [
- 'KarmaAssignedEventListener',
- 'KarmaRecorder',
- ]
+ "KarmaAssignedEventListener",
+ "KarmaRecorder",
+]
from lp.registry.interfaces.karma import IKarmaAssignedEvent
from lp.registry.interfaces.person import IPerson
@@ -24,8 +24,14 @@ class KarmaRecorder:
property.
"""
- def __init__(self, person=None, action_name=None, product=None,
- distribution=None, sourcepackagename=None):
+ def __init__(
+ self,
+ person=None,
+ action_name=None,
+ product=None,
+ distribution=None,
+ sourcepackagename=None,
+ ):
"""Create a `KarmaRecorder`, but do not activate it yet.
:param person: If given, record only karma for this `Person`.
@@ -53,11 +59,14 @@ class KarmaRecorder:
def filter(self, karma):
"""Does `karma` match our filters?"""
return (
- self._filterFor(self.person, karma.person) and
- self._filterFor(self.action_name, karma.action.name) and
- self._filterFor(self.product, karma.product) and
- self._filterFor(self.distribution, karma.distribution) and
- self._filterFor(self.sourcepackagename, karma.sourcepackagename))
+ self._filterFor(self.person, karma.person)
+ and self._filterFor(self.action_name, karma.action.name)
+ and self._filterFor(self.product, karma.product)
+ and self._filterFor(self.distribution, karma.distribution)
+ and self._filterFor(
+ self.sourcepackagename, karma.sourcepackagename
+ )
+ )
def record(self, karma):
"""Overridable: record the assignment of karma.
@@ -79,7 +88,8 @@ class KarmaRecorder:
def register_listener(self):
"""Register listener. Must be `unregister`ed later."""
self.listener = ZopeEventHandlerFixture(
- self.receive, (IPerson, IKarmaAssignedEvent))
+ self.receive, (IPerson, IKarmaAssignedEvent)
+ )
self.listener.setUp()
def unregister_listener(self):
diff --git a/lib/lp/testing/keyserver/__init__.py b/lib/lp/testing/keyserver/__init__.py
index 581e05b..8c52527 100644
--- a/lib/lp/testing/keyserver/__init__.py
+++ b/lib/lp/testing/keyserver/__init__.py
@@ -2,9 +2,9 @@
# Affero General Public License version 3 (see the file LICENSE).
__all__ = [
- 'InProcessKeyServerFixture',
- 'KeyServerTac',
- ]
+ "InProcessKeyServerFixture",
+ "KeyServerTac",
+]
from lp.testing.keyserver.harness import KeyServerTac
from lp.testing.keyserver.inprocess import InProcessKeyServerFixture
diff --git a/lib/lp/testing/keyserver/harness.py b/lib/lp/testing/keyserver/harness.py
index eda5316..1235e1d 100644
--- a/lib/lp/testing/keyserver/harness.py
+++ b/lib/lp/testing/keyserver/harness.py
@@ -7,8 +7,7 @@ import shutil
from lp.services.config import config
from lp.services.daemons.tachandler import TacTestSetup
-
-KEYS_DIR = os.path.join(os.path.dirname(__file__), 'tests/keys')
+KEYS_DIR = os.path.join(os.path.dirname(__file__), "tests/keys")
class KeyServerTac(TacTestSetup):
@@ -27,18 +26,21 @@ class KeyServerTac(TacTestSetup):
@property
def tacfile(self):
return os.path.abspath(
- os.path.join(os.path.dirname(__file__), 'testkeyserver.tac'))
+ os.path.join(os.path.dirname(__file__), "testkeyserver.tac")
+ )
@property
def pidfile(self):
- return os.path.join(self.root, 'testkeyserver.pid')
+ return os.path.join(self.root, "testkeyserver.pid")
@property
def logfile(self):
- return os.path.join(self.root, 'testkeyserver.log')
+ return os.path.join(self.root, "testkeyserver.log")
@property
def url(self):
"""The URL that the web server will be running on."""
- return 'http://%s:%d' % (
- config.gpghandler.host, config.gpghandler.port)
+ return "http://%s:%d" % (
+ config.gpghandler.host,
+ config.gpghandler.port,
+ )
diff --git a/lib/lp/testing/keyserver/inprocess.py b/lib/lp/testing/keyserver/inprocess.py
index b994bea..2a5e528 100644
--- a/lib/lp/testing/keyserver/inprocess.py
+++ b/lib/lp/testing/keyserver/inprocess.py
@@ -4,20 +4,13 @@
"""In-process keyserver fixture."""
__all__ = [
- 'InProcessKeyServerFixture',
- ]
+ "InProcessKeyServerFixture",
+]
from textwrap import dedent
-from fixtures import (
- Fixture,
- TempDir,
- )
-from twisted.internet import (
- defer,
- endpoints,
- reactor,
- )
+from fixtures import Fixture, TempDir
+from twisted.internet import defer, endpoints, reactor
from twisted.python.compat import nativeString
from twisted.web import server
@@ -56,10 +49,16 @@ class InProcessKeyServerFixture(Fixture):
resource = KeyServerResource(self.useFixture(TempDir()).path)
endpoint = endpoints.serverFromString(reactor, nativeString("tcp:0"))
self._port = yield endpoint.listen(server.Site(resource))
- config.push("in-process-key-server-fixture", dedent("""
+ config.push(
+ "in-process-key-server-fixture",
+ dedent(
+ """
[gpghandler]
port: %s
- """) % self._port.getHost().port)
+ """
+ )
+ % self._port.getHost().port,
+ )
self.addCleanup(config.pop, "in-process-key-server-fixture")
@defer.inlineCallbacks
@@ -72,5 +71,6 @@ class InProcessKeyServerFixture(Fixture):
@property
def url(self):
"""The URL that the web server will be running on."""
- return ("http://%s:%d" % (
- config.gpghandler.host, config.gpghandler.port)).encode("UTF-8")
+ return (
+ "http://%s:%d" % (config.gpghandler.host, config.gpghandler.port)
+ ).encode("UTF-8")
diff --git a/lib/lp/testing/keyserver/testkeyserver.tac b/lib/lp/testing/keyserver/testkeyserver.tac
index e308e8e..b6efaa7 100644
--- a/lib/lp/testing/keyserver/testkeyserver.tac
+++ b/lib/lp/testing/keyserver/testkeyserver.tac
@@ -4,10 +4,7 @@
# Twisted Application Configuration file.
# Use with "twistd -y <file.tac>", e.g. "twistd -noy server.tac"
-from twisted.application import (
- service,
- strports,
- )
+from twisted.application import service, strports
from twisted.web import server
from lp.services.config import config
@@ -15,11 +12,10 @@ from lp.services.daemons import readyservice
from lp.services.scripts import execute_zcml_for_scripts
from lp.testing.keyserver.web import KeyServerResource
-
# Needed for using IGPGHandler for processing key submit.
execute_zcml_for_scripts()
-application = service.Application('testkeyserver')
+application = service.Application("testkeyserver")
svc = service.IServiceCollection(application)
# Service that announces when the daemon is ready
@@ -29,5 +25,5 @@ site = server.Site(KeyServerResource(config.testkeyserver.root))
site.displayTracebacks = False
# Run on the port that gpghandler is configured to hit.
-port = 'tcp:%s' % (config.gpghandler.port,)
+port = "tcp:%s" % (config.gpghandler.port,)
strports.service(port, site).setServiceParent(svc)
diff --git a/lib/lp/testing/keyserver/tests/test_harness.py b/lib/lp/testing/keyserver/tests/test_harness.py
index e0727f4..78c4754 100644
--- a/lib/lp/testing/keyserver/tests/test_harness.py
+++ b/lib/lp/testing/keyserver/tests/test_harness.py
@@ -10,14 +10,13 @@ from lp.testing.keyserver.web import GREETING
class TestKeyServerTac(TestCase):
-
def test_url(self):
# The url is the one that gpghandler is configured to hit.
fixture = KeyServerTac()
self.assertEqual(
- 'http://%s:%d' % (
- config.gpghandler.host, config.gpghandler.port),
- fixture.url)
+ "http://%s:%d" % (config.gpghandler.host, config.gpghandler.port),
+ fixture.url,
+ )
def test_starts_properly(self):
# Make sure the tac starts properly and that we can load the page.
diff --git a/lib/lp/testing/keyserver/tests/test_inprocess.py b/lib/lp/testing/keyserver/tests/test_inprocess.py
index 350844b..9cb4698 100644
--- a/lib/lp/testing/keyserver/tests/test_inprocess.py
+++ b/lib/lp/testing/keyserver/tests/test_inprocess.py
@@ -3,10 +3,10 @@
"""In-process keyserver fixture tests."""
+import treq
from testtools.twistedsupport import (
AsynchronousDeferredRunTestForBrokenTwisted,
- )
-import treq
+)
from twisted.internet import defer
from lp.services.config import config
@@ -20,7 +20,8 @@ from lp.testing.keyserver.web import GREETING
class TestInProcessKeyServerFixture(TestCase):
run_tests_with = AsynchronousDeferredRunTestForBrokenTwisted.make_factory(
- timeout=30)
+ timeout=30
+ )
@defer.inlineCallbacks
def test_url(self):
@@ -28,15 +29,18 @@ class TestInProcessKeyServerFixture(TestCase):
fixture = self.useFixture(InProcessKeyServerFixture())
yield fixture.start()
self.assertEqual(
- ("http://%s:%d" % (
- config.gpghandler.host,
- config.gpghandler.port)).encode("UTF-8"),
- fixture.url)
+ (
+ "http://%s:%d"
+ % (config.gpghandler.host, config.gpghandler.port)
+ ).encode("UTF-8"),
+ fixture.url,
+ )
@defer.inlineCallbacks
def test_starts_properly(self):
# The fixture starts properly and we can load the page.
from twisted.internet import reactor
+
fixture = self.useFixture(InProcessKeyServerFixture())
yield fixture.start()
client = self.useFixture(TReqFixture(reactor)).client
diff --git a/lib/lp/testing/keyserver/tests/test_locate_key.py b/lib/lp/testing/keyserver/tests/test_locate_key.py
index 37eed49..24242fc 100644
--- a/lib/lp/testing/keyserver/tests/test_locate_key.py
+++ b/lib/lp/testing/keyserver/tests/test_locate_key.py
@@ -8,7 +8,7 @@ from lp.testing.keyserver.web import locate_key
class LocateKeyTestCase(TestCase):
- root = os.path.join(os.path.dirname(__file__), 'keys')
+ root = os.path.join(os.path.dirname(__file__), "keys")
def assertKeyFile(self, suffix, filename):
"""Verify that a suffix maps to the given filename."""
@@ -19,18 +19,19 @@ class LocateKeyTestCase(TestCase):
def test_locate_key_exact_fingerprint_match(self):
self.assertKeyFile(
- '0xA419AE861E88BC9E04B9C26FBA2B9389DFD20543.get',
- '0xA419AE861E88BC9E04B9C26FBA2B9389DFD20543.get')
+ "0xA419AE861E88BC9E04B9C26FBA2B9389DFD20543.get",
+ "0xA419AE861E88BC9E04B9C26FBA2B9389DFD20543.get",
+ )
def test_locate_key_keyid_glob_match(self):
self.assertKeyFile(
- '0xDFD20543.get',
- '0xA419AE861E88BC9E04B9C26FBA2B9389DFD20543.get')
+ "0xDFD20543.get", "0xA419AE861E88BC9E04B9C26FBA2B9389DFD20543.get"
+ )
def test_locate_key_keyid_without_prefix_glob_match(self):
self.assertKeyFile(
- 'DFD20543.get',
- '0xA419AE861E88BC9E04B9C26FBA2B9389DFD20543.get')
+ "DFD20543.get", "0xA419AE861E88BC9E04B9C26FBA2B9389DFD20543.get"
+ )
def test_locate_key_no_match(self):
- self.assertKeyFile('0xDEADBEEF.get', None)
+ self.assertKeyFile("0xDEADBEEF.get", None)
diff --git a/lib/lp/testing/keyserver/tests/test_web.py b/lib/lp/testing/keyserver/tests/test_web.py
index 5798db8..851ea73 100644
--- a/lib/lp/testing/keyserver/tests/test_web.py
+++ b/lib/lp/testing/keyserver/tests/test_web.py
@@ -6,8 +6,8 @@
import os
import shutil
-from testtools.twistedsupport import AsynchronousDeferredRunTest
import treq
+from testtools.twistedsupport import AsynchronousDeferredRunTest
from twisted.internet.endpoints import serverFromString
from twisted.python.failure import Failure
from twisted.web.server import Site
@@ -31,28 +31,33 @@ class TestWebResources(TestCase):
def setUpKeysDirectory(self):
path = self.makeTemporaryDirectory()
- path = os.path.join(path, 'keys')
+ path = os.path.join(path, "keys")
shutil.copytree(KEYS_DIR, path)
return path
def makeService(self):
"""Run a test key server on whatever port we have available."""
from twisted.internet import reactor
+
resource = KeyServerResource(self.setUpKeysDirectory())
site = Site(resource)
- endpoint = serverFromString(reactor, 'tcp:0')
+ endpoint = serverFromString(reactor, "tcp:0")
return endpoint.listen(site)
def fetchResource(self, listening_port, path):
- """GET the content at 'path' from the web server at 'listening_port'.
- """
+ """GET the content at 'path' from the server at 'listening_port'."""
from twisted.internet import reactor
- url = 'http://localhost:%s/%s' % (
+
+ url = "http://localhost:%s/%s" % (
listening_port.getHost().port,
- path.lstrip('/'))
+ path.lstrip("/"),
+ )
client = self.useFixture(TReqFixture(reactor)).client
- return client.get(url).addCallback(check_status).addCallback(
- treq.text_content)
+ return (
+ client.get(url)
+ .addCallback(check_status)
+ .addCallback(treq.text_content)
+ )
def getURL(self, path):
"""Start a test key server and get the content at 'path'."""
@@ -61,6 +66,7 @@ class TestWebResources(TestCase):
def service_started(port):
self.addCleanup(port.stopListening)
return self.fetchResource(port, path)
+
return d.addCallback(service_started)
def assertContentMatches(self, path, content):
@@ -94,15 +100,16 @@ class TestWebResources(TestCase):
def check_error_details(failure):
if isinstance(failure.value, RegularCallbackExecuted):
- self.fail('Response was not an HTTP error response.')
+ self.fail("Response was not an HTTP error response.")
if not isinstance(failure, Failure):
raise failure
- self.assertEqual(b'404', failure.value.status)
+ self.assertEqual(b"404", failure.value.status)
self.assertEqual(
- b'<html><head><title>Error handling request</title></head>\n'
- b'<body><h1>Error handling request</h1>'
- b'No results found: No keys found</body></html>',
- failure.value.response)
+ b"<html><head><title>Error handling request</title></head>\n"
+ b"<body><h1>Error handling request</h1>"
+ b"No results found: No keys found</body></html>",
+ failure.value.response,
+ )
d.addCallback(regular_execution_callback)
return d.addErrback(check_error_details)
@@ -110,22 +117,23 @@ class TestWebResources(TestCase):
def test_index_lookup(self):
# A key index lookup form via GET.
return self.assertContentMatches(
- '/pks/lookup?fingerprint=on&op=index&search=0xDFD20543',
- '''\
+ "/pks/lookup?fingerprint=on&op=index&search=0xDFD20543",
+ """\
<html>
...
<title>Results for Key 0xDFD20543</title>
...
pub 1024D/DFD20543 2005-04-13 Sample Person (revoked) <sample.revoked@xxxxxxxxxxxxx>
...
-''') # noqa: E501
+""", # noqa: E501
+ )
def test_content_lookup(self):
# A key content lookup form via GET.
return self.assertContentMatches(
- '/pks/lookup?fingerprint=on&op=get&'
- 'search=0xA419AE861E88BC9E04B9C26FBA2B9389DFD20543',
- '''\
+ "/pks/lookup?fingerprint=on&op=get&"
+ "search=0xA419AE861E88BC9E04B9C26FBA2B9389DFD20543",
+ """\
<html>
...
<title>Results for Key 0xA419AE861E88BC9E04B9C26FBA2B9389DFD20543</title>
@@ -135,14 +143,15 @@ Version: GnuPG v1.4.9 (GNU/Linux)
<BLANKLINE>
mQGiBEJdmOcRBADkNJPTBuCIefBdRAhvWyD9SSVHh8GHQWS7l9sRLEsirQkKz1yB
...
-''')
+""",
+ )
def test_lookup_key_id(self):
# We can also request a key ID instead of a fingerprint, and it will
# glob for the fingerprint.
return self.assertContentMatches(
- '/pks/lookup?fingerprint=on&op=get&search=0xDFD20543',
- '''\
+ "/pks/lookup?fingerprint=on&op=get&search=0xDFD20543",
+ """\
<html>
...
<title>Results for Key 0xDFD20543</title>
@@ -152,21 +161,24 @@ Version: GnuPG v1.4.9 (GNU/Linux)
<BLANKLINE>
mQGiBEJdmOcRBADkNJPTBuCIefBdRAhvWyD9SSVHh8GHQWS7l9sRLEsirQkKz1yB
...
-''')
+""",
+ )
def test_nonexistent_key(self):
# If we request a nonexistent key, we get a nice error.
return self.assertRaises404ErrorForKeyNotFound(
- '/pks/lookup?fingerprint=on&op=get&search=0xDFD20544')
+ "/pks/lookup?fingerprint=on&op=get&search=0xDFD20544"
+ )
def test_add_key(self):
# A key submit form via POST (see doc/gpghandler.rst for more
# information).
return self.assertContentMatches(
- '/pks/add',
- '''\
+ "/pks/add",
+ """\
<html>
...
<title>Submit a key</title>
...
-''')
+""",
+ )
diff --git a/lib/lp/testing/keyserver/web.py b/lib/lp/testing/keyserver/web.py
index c2eb26d..03d76b5 100644
--- a/lib/lp/testing/keyserver/web.py
+++ b/lib/lp/testing/keyserver/web.py
@@ -27,8 +27,8 @@ $ gpg --export -a cprov > 0x681B6469.get
"""
__all__ = [
- 'KeyServerResource',
- ]
+ "KeyServerResource",
+]
import glob
import html
@@ -43,10 +43,9 @@ from lp.services.gpg.interfaces import (
IGPGHandler,
MoreThanOneGPGKeyFound,
SecretGPGKeyImportDetected,
- )
+)
-
-GREETING = b'Copyright 2004-2009 Canonical Ltd.\n'
+GREETING = b"Copyright 2004-2009 Canonical Ltd.\n"
def locate_key(root, suffix):
@@ -65,9 +64,9 @@ def locate_key(root, suffix):
if not os.path.exists(path):
# GPG might request a key ID from us, but we name the keys by
# fingerprint. Let's glob.
- if suffix.startswith('0x'):
+ if suffix.startswith("0x"):
suffix = suffix[2:]
- keys = glob.glob(os.path.join(root, '*' + suffix))
+ keys = glob.glob(os.path.join(root, "*" + suffix))
if len(keys) == 1:
path = keys[0]
else:
@@ -77,13 +76,11 @@ def locate_key(root, suffix):
class _BaseResource(Resource):
-
def getChild(self, name, request):
"""Redirect trailing slash correctly."""
- if name == b'':
+ if name == b"":
return self
- return Resource.getChild(
- self, name, request)
+ return Resource.getChild(self, name, request)
class KeyServerResource(_BaseResource):
@@ -91,33 +88,33 @@ class KeyServerResource(_BaseResource):
def __init__(self, root):
_BaseResource.__init__(self)
- self.putChild(b'pks', PksResource(root))
+ self.putChild(b"pks", PksResource(root))
def render_GET(self, request):
return GREETING
class PksResource(_BaseResource):
-
def __init__(self, root):
_BaseResource.__init__(self)
- self.putChild(b'lookup', LookUp(root))
- self.putChild(b'add', SubmitKey(root))
+ self.putChild(b"lookup", LookUp(root))
+ self.putChild(b"add", SubmitKey(root))
def render_GET(self, request):
- return b'Welcome To Fake SKS service.\n'
+ return b"Welcome To Fake SKS service.\n"
KEY_NOT_FOUND_BODY = (
b"<html><head><title>Error handling request</title></head>\n"
b"<body><h1>Error handling request</h1>No results found: "
- b"No keys found</body></html>")
+ b"No keys found</body></html>"
+)
class LookUp(Resource):
isLeaf = True
- permitted_actions = ['index', 'get']
+ permitted_actions = ["index", "get"]
def __init__(self, root):
Resource.__init__(self)
@@ -125,10 +122,10 @@ class LookUp(Resource):
def render_GET(self, request):
try:
- action = request.args[b'op'][0].decode('ISO-8859-1')
- keyid = request.args[b'search'][0].decode('ISO-8859-1')
+ action = request.args[b"op"][0].decode("ISO-8859-1")
+ keyid = request.args[b"search"][0].decode("ISO-8859-1")
except KeyError:
- return ('Invalid Arguments %s' % request.args).encode('UTF-8')
+ return ("Invalid Arguments %s" % request.args).encode("UTF-8")
return self.processRequest(action, keyid, request)
@@ -138,20 +135,22 @@ class LookUp(Resource):
sleep(0.02)
if (action not in self.permitted_actions) or not keyid:
message = 'Forbidden: "%s" on ID "%s"' % (action, keyid)
- return message.encode('UTF-8')
+ return message.encode("UTF-8")
- filename = '%s.%s' % (keyid, action)
+ filename = "%s.%s" % (keyid, action)
path = locate_key(self.root, filename)
if path is not None:
with open(path) as f:
content = html.escape(f.read(), quote=False)
- page = ('<html>\n<head>\n'
- '<title>Results for Key %s</title>\n'
- '</head>\n<body>'
- '<h1>Results for Key %s</h1>\n'
- '<pre>\n%s\n</pre>\n</html>') % (keyid, keyid, content)
- return page.encode('UTF-8')
+ page = (
+ "<html>\n<head>\n"
+ "<title>Results for Key %s</title>\n"
+ "</head>\n<body>"
+ "<h1>Results for Key %s</h1>\n"
+ "<pre>\n%s\n</pre>\n</html>"
+ ) % (keyid, keyid, content)
+ return page.encode("UTF-8")
else:
request.setResponseCode(404)
return KEY_NOT_FOUND_BODY
@@ -182,27 +181,30 @@ class SubmitKey(Resource):
self.root = root
def render_GET(self, request):
- return (SUBMIT_KEY_PAGE % {'banner': ''}).encode('UTF-8')
+ return (SUBMIT_KEY_PAGE % {"banner": ""}).encode("UTF-8")
def render_POST(self, request):
try:
- keytext = request.args[b'keytext'][0]
+ keytext = request.args[b"keytext"][0]
except KeyError:
- return ('Invalid Arguments %s' % request.args).encode('UTF-8')
+ return ("Invalid Arguments %s" % request.args).encode("UTF-8")
return self.storeKey(keytext)
def storeKey(self, keytext):
gpghandler = getUtility(IGPGHandler)
try:
key = gpghandler.importPublicKey(keytext)
- except (GPGKeyNotFoundError, SecretGPGKeyImportDetected,
- MoreThanOneGPGKeyFound) as err:
- return (SUBMIT_KEY_PAGE % {'banner': str(err)}).encode('UTF-8')
-
- filename = '0x%s.get' % key.fingerprint
+ except (
+ GPGKeyNotFoundError,
+ SecretGPGKeyImportDetected,
+ MoreThanOneGPGKeyFound,
+ ) as err:
+ return (SUBMIT_KEY_PAGE % {"banner": str(err)}).encode("UTF-8")
+
+ filename = "0x%s.get" % key.fingerprint
path = os.path.join(self.root, filename)
- with open(path, 'wb') as fp:
+ with open(path, "wb") as fp:
fp.write(keytext)
- return (SUBMIT_KEY_PAGE % {'banner': 'Key added'}).encode('UTF-8')
+ return (SUBMIT_KEY_PAGE % {"banner": "Key added"}).encode("UTF-8")
diff --git a/lib/lp/testing/layers.py b/lib/lp/testing/layers.py
index abdc224..4539ae2 100644
--- a/lib/lp/testing/layers.py
+++ b/lib/lp/testing/layers.py
@@ -19,37 +19,35 @@ of one, forcing us to attempt to make some sort of layer tree.
"""
__all__ = [
- 'AppServerLayer',
- 'BaseLayer',
- 'BingLaunchpadFunctionalLayer',
- 'BingServiceLayer',
- 'DatabaseFunctionalLayer',
- 'DatabaseLayer',
- 'FunctionalLayer',
- 'LaunchpadFunctionalLayer',
- 'LaunchpadLayer',
- 'LaunchpadScriptLayer',
- 'LaunchpadTestSetup',
- 'LaunchpadZopelessLayer',
- 'LayerInvariantError',
- 'LayerIsolationError',
- 'LibrarianLayer',
- 'PageTestLayer',
- 'RabbitMQLayer',
- 'TwistedLayer',
- 'YUITestLayer',
- 'YUIAppServerLayer',
- 'ZopelessAppServerLayer',
- 'ZopelessDatabaseLayer',
- 'ZopelessLayer',
- 'reconnect_stores',
- ]
+ "AppServerLayer",
+ "BaseLayer",
+ "BingLaunchpadFunctionalLayer",
+ "BingServiceLayer",
+ "DatabaseFunctionalLayer",
+ "DatabaseLayer",
+ "FunctionalLayer",
+ "LaunchpadFunctionalLayer",
+ "LaunchpadLayer",
+ "LaunchpadScriptLayer",
+ "LaunchpadTestSetup",
+ "LaunchpadZopelessLayer",
+ "LayerInvariantError",
+ "LayerIsolationError",
+ "LibrarianLayer",
+ "PageTestLayer",
+ "RabbitMQLayer",
+ "TwistedLayer",
+ "YUITestLayer",
+ "YUIAppServerLayer",
+ "ZopelessAppServerLayer",
+ "ZopelessDatabaseLayer",
+ "ZopelessLayer",
+ "reconnect_stores",
+]
import base64
-from cProfile import Profile
import datetime
import errno
-from functools import partial
import gc
import os
import select
@@ -58,103 +56,70 @@ import socket
import subprocess
import sys
import tempfile
-from textwrap import dedent
import threading
import time
-from unittest import (
- TestCase,
- TestResult,
- )
-from urllib.error import (
- HTTPError,
- URLError,
- )
+from cProfile import Profile
+from functools import partial
+from textwrap import dedent
+from unittest import TestCase, TestResult
+from urllib.error import HTTPError, URLError
from urllib.parse import urlparse
from urllib.request import urlopen
-from fixtures import (
- Fixture,
- MonkeyPatch,
- )
import psycopg2
+import transaction
+import wsgi_intercept
+import zope.testbrowser.wsgi
+from fixtures import Fixture, MonkeyPatch
from requests import Session
from requests.adapters import HTTPAdapter
from storm.uri import URI
from talisker.context import Context
-import transaction
from webob.request import environ_from_url as orig_environ_from_url
-import wsgi_intercept
from wsgi_intercept import httplib2_intercept
from zope.app.wsgi import WSGIPublisherApplication
-from zope.component import (
- getUtility,
- globalregistry,
- provideUtility,
- )
+from zope.component import getUtility, globalregistry, provideUtility
from zope.component.testlayer import ZCMLFileLayer
from zope.event import notify
from zope.interface.interfaces import ComponentLookupError
from zope.processlifetime import DatabaseOpened
-from zope.security.management import (
- endInteraction,
- getSecurityPolicy,
- )
+from zope.security.management import endInteraction, getSecurityPolicy
from zope.testbrowser.browser import HostNotAllowed
-import zope.testbrowser.wsgi
from zope.testbrowser.wsgi import AuthorizationMiddleware
+import lp.services.mail.stub
+import lp.services.webapp.session
+import zcml
from lp.services import pidfile
-from lp.services.config import (
- config,
- dbconfig,
- LaunchpadConfig,
- )
-from lp.services.config.fixture import (
- ConfigFixture,
- ConfigUseFixture,
- )
+from lp.services.config import LaunchpadConfig, config, dbconfig
+from lp.services.config.fixture import ConfigFixture, ConfigUseFixture
from lp.services.database.interfaces import IStore
-from lp.services.database.sqlbase import (
- disconnect_stores,
- session_store,
- )
+from lp.services.database.sqlbase import disconnect_stores, session_store
from lp.services.encoding import wsgi_native_string
from lp.services.job.tests import celery_worker
from lp.services.librarian.model import LibraryFileAlias
from lp.services.librarianserver.testing.server import LibrarianServerFixture
-from lp.services.mail.mailbox import (
- IMailBox,
- TestMailBox,
- )
+from lp.services.mail.mailbox import IMailBox, TestMailBox
from lp.services.mail.sendmail import set_immediate_mail_delivery
-import lp.services.mail.stub
from lp.services.memcache.client import memcache_client_factory
from lp.services.osutils import kill_by_pidfile
from lp.services.rabbit.server import RabbitServer
from lp.services.scripts import execute_zcml_for_scripts
from lp.services.sitesearch.tests.bingserviceharness import (
BingServiceTestSetup,
- )
+)
from lp.services.testing.profiled import profiled
from lp.services.timeout import (
get_default_timeout_function,
set_default_timeout_function,
- )
+)
from lp.services.webapp.authorization import LaunchpadPermissiveSecurityPolicy
from lp.services.webapp.interfaces import IOpenLaunchBag
from lp.services.webapp.servers import (
register_launchpad_request_publication_factories,
- )
-import lp.services.webapp.session
-from lp.testing import (
- ANONYMOUS,
- login,
- logout,
- reset_logging,
- )
+)
+from lp.testing import ANONYMOUS, login, logout, reset_logging
from lp.testing.pgsql import PgTestSetup
-import zcml
-
WAIT_INTERVAL = datetime.timedelta(seconds=180)
@@ -169,6 +134,7 @@ class LayerInvariantError(LayerError):
This indicates the Layer infrastructure has messed up. The test run
should be aborted.
"""
+
pass
@@ -204,13 +170,13 @@ def reconnect_stores(reset=False):
dbconfig.reset()
main_store = IStore(LibraryFileAlias)
- assert main_store is not None, 'Failed to reconnect'
+ assert main_store is not None, "Failed to reconnect"
# Confirm that SQLOS is again talking to the database (it connects
# as soon as SQLBase._connection is accessed
- r = main_store.execute('SELECT count(*) FROM LaunchpadDatabaseRevision')
- assert r.get_one()[0] > 0, 'Storm is not talking to the database'
- assert session_store() is not None, 'Failed to reconnect'
+ r = main_store.execute("SELECT count(*) FROM LaunchpadDatabaseRevision")
+ assert r.get_one()[0] > 0, "Storm is not talking to the database"
+ assert session_store() is not None, "Failed to reconnect"
class BaseLayer:
@@ -224,6 +190,7 @@ class BaseLayer:
get these checks. The Z3 test runner should be updated so that a layer
can be specified to use for unit tests.
"""
+
# Set to True when we are running tests in this layer.
isSetUp = False
@@ -268,13 +235,14 @@ class BaseLayer:
def setUp(cls):
# Set the default appserver config instance name.
# May be changed as required eg when running parallel tests.
- cls.appserver_config_name = 'testrunner-appserver'
+ cls.appserver_config_name = "testrunner-appserver"
BaseLayer.isSetUp = True
cls.fixture = Fixture()
cls.fixture.setUp()
- cls.fixture.addCleanup(setattr, cls, 'fixture', None)
+ cls.fixture.addCleanup(setattr, cls, "fixture", None)
BaseLayer.persist_test_services = (
- os.environ.get('LP_PERSISTENT_TEST_SERVICES') is not None)
+ os.environ.get("LP_PERSISTENT_TEST_SERVICES") is not None
+ )
# We can only do unique test allocation and parallelisation if
# LP_PERSISTENT_TEST_SERVICES is off.
if not BaseLayer.persist_test_services:
@@ -283,29 +251,33 @@ class BaseLayer:
# PostgreSQL's 63-character limit for identifiers. Linux
# currently allows up to 2^22 PIDs, so PIDs may be up to seven
# digits long.
- test_instance = '%d_%s' % (
- os.getpid(), base64.b16encode(os.urandom(12)).decode().lower())
- os.environ['LP_TEST_INSTANCE'] = test_instance
- cls.fixture.addCleanup(os.environ.pop, 'LP_TEST_INSTANCE', '')
+ test_instance = "%d_%s" % (
+ os.getpid(),
+ base64.b16encode(os.urandom(12)).decode().lower(),
+ )
+ os.environ["LP_TEST_INSTANCE"] = test_instance
+ cls.fixture.addCleanup(os.environ.pop, "LP_TEST_INSTANCE", "")
# Kill any Memcached or Librarian left running from a previous
# test run, or from the parent test process if the current
# layer is being run in a subprocess. No need to be polite
# about killing memcached - just do it quickly.
kill_by_pidfile(MemcachedLayer.getPidFile(), num_polls=0)
- config_name = 'testrunner_%s' % test_instance
- cls.make_config(config_name, 'testrunner', 'config_fixture')
- app_config_name = 'testrunner-appserver_%s' % test_instance
+ config_name = "testrunner_%s" % test_instance
+ cls.make_config(config_name, "testrunner", "config_fixture")
+ app_config_name = "testrunner-appserver_%s" % test_instance
cls.make_config(
- app_config_name, 'testrunner-appserver',
- 'appserver_config_fixture')
+ app_config_name,
+ "testrunner-appserver",
+ "appserver_config_fixture",
+ )
cls.appserver_config_name = app_config_name
else:
- config_name = 'testrunner'
- app_config_name = 'testrunner-appserver'
+ config_name = "testrunner"
+ app_config_name = "testrunner-appserver"
cls.config_name = config_name
- cls.fixture.addCleanup(setattr, cls, 'config_name', None)
+ cls.fixture.addCleanup(setattr, cls, "config_name", None)
cls.appserver_config_name = app_config_name
- cls.fixture.addCleanup(setattr, cls, 'appserver_config_name', None)
+ cls.fixture.addCleanup(setattr, cls, "appserver_config_name", None)
use_fixture = ConfigUseFixture(config_name)
cls.fixture.addCleanup(use_fixture.cleanUp)
use_fixture.setUp()
@@ -338,11 +310,12 @@ class BaseLayer:
# name. The testrunner doesn't provide this, so we have to do
# some snooping.
import inspect
+
frame = inspect.currentframe()
try:
- while frame.f_code.co_name != 'startTest':
+ while frame.f_code.co_name != "startTest":
frame = frame.f_back
- BaseLayer.test_name = str(frame.f_locals['test'])
+ BaseLayer.test_name = str(frame.f_locals["test"])
finally:
del frame # As per no-leak stack inspection in Python reference.
@@ -361,7 +334,8 @@ class BaseLayer:
# run can continue.
if cwd != BaseLayer.original_working_directory:
BaseLayer.flagTestIsolationFailure(
- "Test failed to restore working directory.")
+ "Test failed to restore working directory."
+ )
os.chdir(BaseLayer.original_working_directory)
BaseLayer.original_working_directory = None
@@ -372,8 +346,10 @@ class BaseLayer:
def new_live_threads():
return [
- thread for thread in threading.enumerate()
- if thread not in BaseLayer._threads and thread.is_alive()]
+ thread
+ for thread in threading.enumerate()
+ if thread not in BaseLayer._threads and thread.is_alive()
+ ]
if BaseLayer.disable_thread_check:
new_threads = None
@@ -401,19 +377,20 @@ class BaseLayer:
# tests that leave threads behind from failing. Its use
# should only ever be temporary.
if BaseLayer.disable_thread_check:
- print((
- "ERROR DISABLED: "
- "Test left new live threads: %s") % repr(new_threads))
+ print(
+ ("ERROR DISABLED: " "Test left new live threads: %s")
+ % repr(new_threads)
+ )
else:
BaseLayer.flagTestIsolationFailure(
- "Test left new live threads: %s" % repr(new_threads))
+ "Test left new live threads: %s" % repr(new_threads)
+ )
BaseLayer.disable_thread_check = False
del BaseLayer._threads
if signal.getsignal(signal.SIGCHLD) != signal.SIG_DFL:
- BaseLayer.flagTestIsolationFailure(
- "Test left SIGCHLD handler.")
+ BaseLayer.flagTestIsolationFailure("Test left SIGCHLD handler.")
# Objects with __del__ methods cannot participate in reference cycles.
# Fail tests with memory leaks now rather than when Launchpad crashes
@@ -423,10 +400,14 @@ class BaseLayer:
gc.collect() # Expensive, so only do if there might be garbage.
if gc.garbage:
BaseLayer.flagTestIsolationFailure(
- "Test left uncollectable garbage\n"
- "%s (referenced from %s; referencing %s)"
- % (gc.garbage, gc.get_referrers(*gc.garbage),
- gc.get_referents(*gc.garbage)))
+ "Test left uncollectable garbage\n"
+ "%s (referenced from %s; referencing %s)"
+ % (
+ gc.garbage,
+ gc.get_referrers(*gc.garbage),
+ gc.get_referents(*gc.garbage),
+ )
+ )
@classmethod
@profiled
@@ -439,23 +420,28 @@ class BaseLayer:
"""
if FunctionalLayer.isSetUp and ZopelessLayer.isSetUp:
raise LayerInvariantError(
- "Both Zopefull and Zopeless CA environments setup")
+ "Both Zopefull and Zopeless CA environments setup"
+ )
# Detect a test that causes the component architecture to be loaded.
# This breaks test isolation, as it cannot be torn down.
- if (is_ca_available()
+ if (
+ is_ca_available()
and not FunctionalLayer.isSetUp
- and not ZopelessLayer.isSetUp):
+ and not ZopelessLayer.isSetUp
+ ):
raise LayerIsolationError(
"Component architecture should not be loaded by tests. "
- "This should only be loaded by the Layer.")
+ "This should only be loaded by the Layer."
+ )
# Detect a test that forgot to reset the default socket timeout.
# This safety belt is cheap and protects us from very nasty
# intermittent test failures: see bug #140068 for an example.
if socket.getdefaulttimeout() is not None:
raise LayerIsolationError(
- "Test didn't reset the socket default timeout.")
+ "Test didn't reset the socket default timeout."
+ )
@classmethod
def flagTestIsolationFailure(cls, message):
@@ -480,12 +466,13 @@ class BaseLayer:
def getCurrentTestResult(cls):
"""Return the TestResult currently in play."""
import inspect
+
frame = inspect.currentframe()
try:
while True:
- f_self = frame.f_locals.get('self', None)
+ f_self = frame.f_locals.get("self", None)
if isinstance(f_self, TestResult):
- return frame.f_locals['self']
+ return frame.f_locals["self"]
frame = frame.f_back
finally:
del frame # As per no-leak stack inspection in Python reference.
@@ -494,17 +481,18 @@ class BaseLayer:
def getCurrentTestCase(cls):
"""Return the test currently in play."""
import inspect
+
frame = inspect.currentframe()
try:
while True:
- f_self = frame.f_locals.get('self', None)
+ f_self = frame.f_locals.get("self", None)
if isinstance(f_self, TestCase):
return f_self
- f_test = frame.f_locals.get('test', None)
+ f_test = frame.f_locals.get("test", None)
if isinstance(f_test, TestCase):
return f_test
frame = frame.f_back
- return frame.f_locals['test']
+ return frame.f_locals["test"]
finally:
del frame # As per no-leak stack inspection in Python reference.
@@ -514,10 +502,9 @@ class BaseLayer:
return LaunchpadConfig(cls.appserver_config_name)
@classmethod
- def appserver_root_url(cls, facet='mainsite', ensureSlash=False):
+ def appserver_root_url(cls, facet="mainsite", ensureSlash=False):
"""Return the correct app server root url for the given facet."""
- return cls.appserver_config().appserver_root_url(
- facet, ensureSlash)
+ return cls.appserver_config().appserver_root_url(facet, ensureSlash)
class MemcachedLayer(BaseLayer):
@@ -543,8 +530,9 @@ class MemcachedLayer(BaseLayer):
cls._is_setup = True
# Create a client
MemcachedLayer.client = memcache_client_factory()
- if (BaseLayer.persist_test_services and
- os.path.exists(MemcachedLayer.getPidFile())):
+ if BaseLayer.persist_test_services and os.path.exists(
+ MemcachedLayer.getPidFile()
+ ):
return
# First, check to see if there is a memcached already running.
@@ -562,25 +550,31 @@ class MemcachedLayer(BaseLayer):
# the item size at a megabyte. Note that the argument to -m is in
# megabytes.
item_size = min(
- config.memcached.memory_size * 1024 * 1024 / 4,
- 1024 * 1024)
+ config.memcached.memory_size * 1024 * 1024 / 4, 1024 * 1024
+ )
cmd = [
- 'memcached',
- '-m', str(config.memcached.memory_size),
- '-I', str(item_size),
- '-l', str(config.memcached.address),
- '-p', str(config.memcached.port),
- '-U', str(config.memcached.port),
- ]
+ "memcached",
+ "-m",
+ str(config.memcached.memory_size),
+ "-I",
+ str(item_size),
+ "-l",
+ str(config.memcached.address),
+ "-p",
+ str(config.memcached.port),
+ "-U",
+ str(config.memcached.port),
+ ]
if config.memcached.verbose:
- cmd.append('-vv')
+ cmd.append("-vv")
stdout = sys.stdout
stderr = sys.stderr
else:
stdout = tempfile.NamedTemporaryFile()
stderr = tempfile.NamedTemporaryFile()
MemcachedLayer._memcached_process = subprocess.Popen(
- cmd, stdin=subprocess.PIPE, stdout=stdout, stderr=stderr)
+ cmd, stdin=subprocess.PIPE, stdout=stdout, stderr=stderr
+ )
MemcachedLayer._memcached_process.stdin.close()
# Wait for the memcached to become operational.
@@ -592,12 +586,13 @@ class MemcachedLayer(BaseLayer):
if MemcachedLayer._memcached_process.returncode is not None:
raise LayerInvariantError(
"memcached never started or has died.",
- MemcachedLayer._memcached_process.stdout.read())
+ MemcachedLayer._memcached_process.stdout.read(),
+ )
time.sleep(0.1)
# Store the pidfile for other processes to kill.
pid_file = MemcachedLayer.getPidFile()
- with open(pid_file, 'w') as f:
+ with open(pid_file, "w") as f:
f.write(str(MemcachedLayer._memcached_process.pid))
@classmethod
@@ -634,7 +629,7 @@ class MemcachedLayer(BaseLayer):
@classmethod
def getPidFile(cls):
- return os.path.join(config.root, '.memcache.pid')
+ return os.path.join(config.root, ".memcache.pid")
@classmethod
def purge(cls):
@@ -655,10 +650,10 @@ class RabbitMQLayer(BaseLayer):
@profiled
def setUp(cls):
cls.rabbit.setUp()
- cls.config_fixture.add_section(
- cls.rabbit.config.service_config)
+ cls.config_fixture.add_section(cls.rabbit.config.service_config)
cls.appserver_config_fixture.add_section(
- cls.rabbit.config.service_config)
+ cls.rabbit.config.service_config
+ )
cls._is_setup = True
@classmethod
@@ -667,9 +662,9 @@ class RabbitMQLayer(BaseLayer):
if not cls._is_setup:
return
cls.appserver_config_fixture.remove_section(
- cls.rabbit.config.service_config)
- cls.config_fixture.remove_section(
- cls.rabbit.config.service_config)
+ cls.rabbit.config.service_config
+ )
+ cls.config_fixture.remove_section(cls.rabbit.config.service_config)
cls.rabbit.cleanUp()
cls._is_setup = False
@@ -703,9 +698,13 @@ class DatabaseLayer(BaseLayer):
def setUp(cls):
cls._is_setup = True
# Allocate a template for this test instance
- if os.environ.get('LP_TEST_INSTANCE'):
- template_name = '_'.join([LaunchpadTestSetup.template,
- os.environ.get('LP_TEST_INSTANCE')])
+ if os.environ.get("LP_TEST_INSTANCE"):
+ template_name = "_".join(
+ [
+ LaunchpadTestSetup.template,
+ os.environ.get("LP_TEST_INSTANCE"),
+ ]
+ )
cls._db_template_fixture = LaunchpadTestSetup(dbname=template_name)
cls._db_template_fixture.setUp()
else:
@@ -739,7 +738,7 @@ class DatabaseLayer(BaseLayer):
cls.force_dirty_database()
cls._db_fixture.tearDown()
cls._db_fixture = None
- if os.environ.get('LP_TEST_INSTANCE'):
+ if os.environ.get("LP_TEST_INSTANCE"):
cls._db_template_fixture.tearDown()
cls._db_template_fixture = None
@@ -755,10 +754,12 @@ class DatabaseLayer(BaseLayer):
# Fail tests that forget to uninstall their database policies.
from lp.services.webapp.adapter import StoreSelector
+
while StoreSelector.get_current() is not None:
BaseLayer.flagTestIsolationFailure(
"Database policy %s still installed"
- % repr(StoreSelector.pop()))
+ % repr(StoreSelector.pop())
+ )
# Reset/bring up the db - makes it available for either the next test,
# or a subordinate layer which builds on the db. This wastes one setup
# per db layer teardown per run, but thats tolerable.
@@ -788,7 +789,8 @@ class LibrarianLayer(DatabaseLayer):
@profiled
def setUp(cls):
cls.librarian_fixture = LibrarianServerFixture(
- BaseLayer.config_fixture)
+ BaseLayer.config_fixture
+ )
cls.librarian_fixture.setUp()
cls._check_and_reset()
@@ -805,7 +807,8 @@ class LibrarianLayer(DatabaseLayer):
if cls.librarian_fixture is None:
return
cls.appserver_config_fixture.remove_section(
- cls.appserver_service_config)
+ cls.appserver_service_config
+ )
try:
cls._check_and_reset()
finally:
@@ -820,16 +823,17 @@ class LibrarianLayer(DatabaseLayer):
try:
session = Session()
session.mount(
- config.librarian.download_url,
- HTTPAdapter(max_retries=3))
+ config.librarian.download_url, HTTPAdapter(max_retries=3)
+ )
session.get(config.librarian.download_url).content
except Exception as e:
raise LayerIsolationError(
- "Librarian has been killed or has hung."
- "Tests should use LibrarianLayer.hide() and "
- "LibrarianLayer.reveal() where possible, and ensure "
- "the Librarian is restarted if it absolutely must be "
- "shutdown: " + str(e))
+ "Librarian has been killed or has hung."
+ "Tests should use LibrarianLayer.hide() and "
+ "LibrarianLayer.reveal() where possible, and ensure "
+ "the Librarian is restarted if it absolutely must be "
+ "shutdown: " + str(e)
+ )
else:
cls.librarian_fixture.reset()
@@ -865,17 +869,22 @@ class LibrarianLayer(DatabaseLayer):
# Bind to a socket, but don't listen to it. This way we
# guarantee that connections to the given port will fail.
cls._fake_upload_socket = socket.socket(
- socket.AF_INET, socket.SOCK_STREAM)
- assert config.librarian.upload_host == 'localhost', (
- 'Can only hide librarian if it is running locally')
- cls._fake_upload_socket.bind(('127.0.0.1', 0))
+ socket.AF_INET, socket.SOCK_STREAM
+ )
+ assert (
+ config.librarian.upload_host == "localhost"
+ ), "Can only hide librarian if it is running locally"
+ cls._fake_upload_socket.bind(("127.0.0.1", 0))
host, port = cls._fake_upload_socket.getsockname()
- librarian_data = dedent("""
+ librarian_data = dedent(
+ """
[librarian]
upload_port: %s
- """ % port)
- config.push('hide_librarian', librarian_data)
+ """
+ % port
+ )
+ config.push("hide_librarian", librarian_data)
@classmethod
@profiled
@@ -885,7 +894,7 @@ class LibrarianLayer(DatabaseLayer):
This just involves restoring the config to the original value.
"""
cls._hidden = False
- config.pop('hide_librarian')
+ config.pop("hide_librarian")
def test_default_timeout():
@@ -921,7 +930,8 @@ class LaunchpadLayer(LibrarianLayer, MemcachedLayer, RabbitMQLayer):
# By default, don't make external service tests timeout.
if get_default_timeout_function() is not None:
raise LayerIsolationError(
- "Global default timeout function should be None.")
+ "Global default timeout function should be None."
+ )
set_default_timeout_function(test_default_timeout)
@classmethod
@@ -929,7 +939,8 @@ class LaunchpadLayer(LibrarianLayer, MemcachedLayer, RabbitMQLayer):
def testTearDown(cls):
if get_default_timeout_function() is not test_default_timeout:
raise LayerIsolationError(
- "Test didn't reset default timeout function.")
+ "Test didn't reset default timeout function."
+ )
set_default_timeout_function(None)
# A database connection to the session database, created by the first
@@ -946,12 +957,16 @@ class LaunchpadLayer(LibrarianLayer, MemcachedLayer, RabbitMQLayer):
"""
if LaunchpadLayer._raw_sessiondb_connection is None:
from lp.services.webapp.adapter import LaunchpadSessionDatabase
+
launchpad_session_database = LaunchpadSessionDatabase(
- URI('launchpad-session:'))
+ URI("launchpad-session:")
+ )
LaunchpadLayer._raw_sessiondb_connection = (
- launchpad_session_database.raw_connect())
+ launchpad_session_database.raw_connect()
+ )
LaunchpadLayer._raw_sessiondb_connection.cursor().execute(
- "DELETE FROM SessionData")
+ "DELETE FROM SessionData"
+ )
class BasicTaliskerMiddleware:
@@ -996,7 +1011,7 @@ class RemoteAddrMiddleware:
self.app = app
def __call__(self, environ, start_response):
- environ.setdefault('REMOTE_ADDR', wsgi_native_string('127.0.0.1'))
+ environ.setdefault("REMOTE_ADDR", wsgi_native_string("127.0.0.1"))
return self.app(environ, start_response)
@@ -1037,7 +1052,7 @@ class _FunctionalBrowserLayer(zope.testbrowser.wsgi.Layer, ZCMLFileLayer):
SortHeadersMiddleware,
TransactionMiddleware,
BasicTaliskerMiddleware,
- ]
+ ]
def setUp(self):
super().setUp()
@@ -1093,7 +1108,8 @@ class FunctionalLayer(BaseLayer):
# around this by creating a BrowserLayer instance here rather than
# having this layer subclass it.
FunctionalLayer.browser_layer = _FunctionalBrowserLayer(
- zcml, zcml_file='ftesting.zcml')
+ zcml, zcml_file="ftesting.zcml"
+ )
FunctionalLayer.browser_layer.setUp()
# Assert that ZCMLFileLayer did what it says it does
@@ -1113,9 +1129,11 @@ class FunctionalLayer(BaseLayer):
# that use lazr.restfulclient or launchpadlib) still talk to the app
# server over HTTP and need to be intercepted.
wsgi_intercept.add_wsgi_intercept(
- 'localhost', 80, _FunctionalBrowserLayer.get_app)
+ "localhost", 80, _FunctionalBrowserLayer.get_app
+ )
wsgi_intercept.add_wsgi_intercept(
- 'api.launchpad.test', 80, _FunctionalBrowserLayer.get_app)
+ "api.launchpad.test", 80, _FunctionalBrowserLayer.get_app
+ )
httplib2_intercept.install()
# webob.request.environ_from_url defaults to HTTP/1.0, which is
@@ -1124,11 +1142,12 @@ class FunctionalLayer(BaseLayer):
# HTTP/1.1 instead.
def environ_from_url_http11(path):
env = orig_environ_from_url(path)
- env['SERVER_PROTOCOL'] = 'HTTP/1.1'
+ env["SERVER_PROTOCOL"] = "HTTP/1.1"
return env
FunctionalLayer._environ_from_url_http11 = MonkeyPatch(
- 'webob.request.environ_from_url', environ_from_url_http11)
+ "webob.request.environ_from_url", environ_from_url_http11
+ )
FunctionalLayer._environ_from_url_http11.setUp()
@classmethod
@@ -1136,8 +1155,8 @@ class FunctionalLayer(BaseLayer):
def tearDown(cls):
FunctionalLayer.isSetUp = False
FunctionalLayer._environ_from_url_http11.cleanUp()
- wsgi_intercept.remove_wsgi_intercept('localhost', 80)
- wsgi_intercept.remove_wsgi_intercept('api.launchpad.test', 80)
+ wsgi_intercept.remove_wsgi_intercept("localhost", 80)
+ wsgi_intercept.remove_wsgi_intercept("api.launchpad.test", 80)
httplib2_intercept.uninstall()
FunctionalLayer.browser_layer.tearDown()
# Signal Layer cannot be torn down fully
@@ -1152,14 +1171,15 @@ class FunctionalLayer(BaseLayer):
# Allow the WSGI test browser to talk to our various test hosts.
def _assertAllowed(self, url):
parsed = urlparse(url)
- host = parsed.netloc.partition(':')[0]
- if host == 'localhost' or host.endswith('.test'):
+ host = parsed.netloc.partition(":")[0]
+ if host == "localhost" or host.endswith(".test"):
return
raise HostNotAllowed(url)
FunctionalLayer._testbrowser_allowed = MonkeyPatch(
- 'zope.testbrowser.browser.TestbrowserApp._assertAllowed',
- _assertAllowed)
+ "zope.testbrowser.browser.TestbrowserApp._assertAllowed",
+ _assertAllowed,
+ )
FunctionalLayer._testbrowser_allowed.setUp()
FunctionalLayer.browser_layer.testSetUp()
@@ -1167,7 +1187,8 @@ class FunctionalLayer(BaseLayer):
# mighty nasty has happened if this is triggered.
if not is_ca_available():
raise LayerInvariantError(
- "Component architecture not loaded or totally screwed")
+ "Component architecture not loaded or totally screwed"
+ )
@classmethod
@profiled
@@ -1179,7 +1200,8 @@ class FunctionalLayer(BaseLayer):
# mighty nasty has happened if this is triggered.
if not is_ca_available():
raise LayerInvariantError(
- "Component architecture not loaded or totally screwed")
+ "Component architecture not loaded or totally screwed"
+ )
transaction.abort()
@@ -1202,7 +1224,8 @@ class ZopelessLayer(BaseLayer):
if not is_ca_available():
raise LayerInvariantError(
"Component architecture not loaded by "
- "execute_zcml_for_scripts")
+ "execute_zcml_for_scripts"
+ )
# If our request publication factories were defined using
# ZCML, they'd be set up by execute_zcml_for_scripts(). Since
@@ -1224,14 +1247,15 @@ class ZopelessLayer(BaseLayer):
# mighty nasty has happened if this is triggered.
if not is_ca_available():
raise LayerInvariantError(
- "Component architecture not loaded or totally screwed")
+ "Component architecture not loaded or totally screwed"
+ )
# This should not happen here, it should be caught by the
# testTearDown() method. If it does, something very nasty
# happened.
if getSecurityPolicy() != LaunchpadPermissiveSecurityPolicy:
raise LayerInvariantError(
"Previous test removed the LaunchpadPermissiveSecurityPolicy."
- )
+ )
# execute_zcml_for_scripts() sets up an interaction for the
# anonymous user. A previous script may have changed or removed
@@ -1245,13 +1269,15 @@ class ZopelessLayer(BaseLayer):
# mighty nasty has happened if this is triggered.
if not is_ca_available():
raise LayerInvariantError(
- "Component architecture not loaded or totally screwed")
+ "Component architecture not loaded or totally screwed"
+ )
# Make sure that a test that changed the security policy, reset it
# back to its default value.
if getSecurityPolicy() != LaunchpadPermissiveSecurityPolicy:
raise LayerInvariantError(
"This test removed the LaunchpadPermissiveSecurityPolicy and "
- "didn't restore it.")
+ "didn't restore it."
+ )
logout()
@@ -1293,10 +1319,7 @@ class TwistedLayer(BaseLayer):
@profiled
def testSetUp(cls):
TwistedLayer._save_signals()
- from twisted.internet import (
- interfaces,
- reactor,
- )
+ from twisted.internet import interfaces, reactor
from twisted.python import threadpool
# zope.exception demands more of frame objects than
@@ -1304,11 +1327,11 @@ class TwistedLayer(BaseLayer):
# to make it work with them as of 2009-09-16. See
# https://bugs.launchpad.net/bugs/425113.
cls._patch = MonkeyPatch(
- 'twisted.python.failure._Frame.f_locals',
- property(lambda self: {}))
+ "twisted.python.failure._Frame.f_locals", property(lambda self: {})
+ )
cls._patch.setUp()
if interfaces.IReactorThreads.providedBy(reactor):
- pool = getattr(reactor, 'threadpool', None)
+ pool = getattr(reactor, "threadpool", None)
# If the Twisted threadpool has been obliterated (probably by
# testTearDown), then re-build it using the values that Twisted
# uses.
@@ -1321,13 +1344,11 @@ class TwistedLayer(BaseLayer):
def testTearDown(cls):
# Shutdown and obliterate the Twisted threadpool, to plug up leaking
# threads.
- from twisted.internet import (
- interfaces,
- reactor,
- )
+ from twisted.internet import interfaces, reactor
+
if interfaces.IReactorThreads.providedBy(reactor):
reactor.suggestThreadPoolSize(0)
- pool = getattr(reactor, 'threadpool', None)
+ pool = getattr(reactor, "threadpool", None)
if pool is not None:
reactor.threadpool.stop()
reactor.threadpool = None
@@ -1403,6 +1424,7 @@ class LaunchpadFunctionalLayer(LaunchpadLayer, FunctionalLayer):
def testSetUp(cls):
# Reset any statistics
from lp.services.webapp.opstats import OpStats
+
OpStats.resetStats()
# Connect Storm
@@ -1417,14 +1439,14 @@ class LaunchpadFunctionalLayer(LaunchpadLayer, FunctionalLayer):
# Reset any statistics
from lp.services.webapp.opstats import OpStats
+
OpStats.resetStats()
# Disconnect Storm so it doesn't get in the way of database resets
disconnect_stores()
-class BingLaunchpadFunctionalLayer(LaunchpadFunctionalLayer,
- BingServiceLayer):
+class BingLaunchpadFunctionalLayer(LaunchpadFunctionalLayer, BingServiceLayer):
"""Provides Bing service in addition to LaunchpadFunctionalLayer."""
@classmethod
@@ -1497,7 +1519,7 @@ class LaunchpadScriptLayer(ZopelessLayer, LaunchpadLayer):
@profiled
def tearDown(cls):
if not globalregistry.base.unregisterUtility(cls._mailbox):
- raise NotImplementedError('failed to unregister mailbox')
+ raise NotImplementedError("failed to unregister mailbox")
@classmethod
@profiled
@@ -1513,9 +1535,9 @@ class LaunchpadScriptLayer(ZopelessLayer, LaunchpadLayer):
class LaunchpadTestSetup(PgTestSetup):
- template = 'launchpad_ftest_template'
- dbuser = 'launchpad'
- host = 'localhost'
+ template = "launchpad_ftest_template"
+ dbuser = "launchpad"
+ host = "localhost"
class LaunchpadZopelessLayer(LaunchpadScriptLayer):
@@ -1539,7 +1561,7 @@ class LaunchpadZopelessLayer(LaunchpadScriptLayer):
@classmethod
@profiled
def testSetUp(cls):
- dbconfig.override(isolation_level='read_committed')
+ dbconfig.override(isolation_level="read_committed")
# XXX wgrant 2011-09-24 bug=29744: initZopeless used to do this.
# Tests that still need it should eventually set this directly,
# so the whole layer is not polluted.
@@ -1584,30 +1606,33 @@ class ProfilingMiddleware:
class PageTestLayer(LaunchpadFunctionalLayer, BingServiceLayer):
- """Environment for page tests.
- """
+ """Environment for page tests."""
@classmethod
@profiled
def setUp(cls):
- if os.environ.get('PROFILE_PAGETESTS_REQUESTS'):
+ if os.environ.get("PROFILE_PAGETESTS_REQUESTS"):
PageTestLayer.profiler = Profile()
else:
PageTestLayer.profiler = None
PageTestLayer._profiling_middleware = partial(
- ProfilingMiddleware, profiler=PageTestLayer.profiler)
+ ProfilingMiddleware, profiler=PageTestLayer.profiler
+ )
FunctionalLayer.browser_layer.addMiddlewares(
- PageTestLayer._profiling_middleware)
+ PageTestLayer._profiling_middleware
+ )
@classmethod
@profiled
def tearDown(cls):
FunctionalLayer.browser_layer.removeMiddlewares(
- PageTestLayer._profiling_middleware)
+ PageTestLayer._profiling_middleware
+ )
if PageTestLayer.profiler:
PageTestLayer.profiler.dump_stats(
- os.environ.get('PROFILE_PAGETESTS_REQUESTS'))
+ os.environ.get("PROFILE_PAGETESTS_REQUESTS")
+ )
@classmethod
@profiled
@@ -1637,7 +1662,8 @@ class LayerProcessController:
def setConfig(cls):
"""Stash a config for use."""
cls.appserver_config = LaunchpadConfig(
- BaseLayer.appserver_config_name, 'runlaunchpad')
+ BaseLayer.appserver_config_name, "runlaunchpad"
+ )
@classmethod
def setUp(cls):
@@ -1646,10 +1672,10 @@ class LayerProcessController:
@classmethod
@profiled
- def startAppServer(cls, run_name='run'):
+ def startAppServer(cls, run_name="run"):
"""Start the app server if it hasn't already been started."""
if cls.appserver is not None:
- raise LayerInvariantError('App server already running')
+ raise LayerInvariantError("App server already running")
cls._cleanUpStaleAppServer()
cls._runAppServer(run_name)
cls._waitUntilAppServerIsReady()
@@ -1716,8 +1742,9 @@ class LayerProcessController:
"""
if cls.appserver.poll() is not None:
raise LayerIsolationError(
- "App server died in this test (status=%s):\n%s" % (
- cls.appserver.returncode, cls.appserver.stdout.read()))
+ "App server died in this test (status=%s):\n%s"
+ % (cls.appserver.returncode, cls.appserver.stdout.read())
+ )
# Cleanup the app server's output buffer between tests.
while True:
# Read while we have something available at the stdout.
@@ -1731,7 +1758,7 @@ class LayerProcessController:
@classmethod
def _cleanUpStaleAppServer(cls):
"""Kill any stale app server or pid file."""
- pid = pidfile.get_pid('launchpad', cls.appserver_config)
+ pid = pidfile.get_pid("launchpad", cls.appserver_config)
if pid is not None:
# Don't worry if the process no longer exists.
try:
@@ -1739,18 +1766,22 @@ class LayerProcessController:
except OSError as error:
if error.errno != errno.ESRCH:
raise
- pidfile.remove_pidfile('launchpad', cls.appserver_config)
+ pidfile.remove_pidfile("launchpad", cls.appserver_config)
@classmethod
def _runAppServer(cls, run_name):
"""Start the app server using runlaunchpad.py"""
_config = cls.appserver_config
- cmd = [os.path.join(_config.root, 'bin', run_name)]
+ cmd = [os.path.join(_config.root, "bin", run_name)]
environ = dict(os.environ)
- environ['LPCONFIG'] = _config.instance_name
+ environ["LPCONFIG"] = _config.instance_name
cls.appserver = subprocess.Popen(
- cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
- env=environ, cwd=_config.root)
+ cmd,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ env=environ,
+ cwd=_config.root,
+ )
@classmethod
def appserver_root_url(cls):
@@ -1770,8 +1801,9 @@ class LayerProcessController:
if error.code == 503:
raise RuntimeError(
"App server is returning unknown error code %s. Is "
- "there another instance running in the same port?" %
- error.code)
+ "there another instance running in the same port?"
+ % error.code
+ )
except URLError as error:
# We are interested in a wrapped socket.error.
if not isinstance(error.reason, socket.error):
@@ -1781,8 +1813,9 @@ class LayerProcessController:
returncode = cls.appserver.poll()
if returncode is not None:
raise RuntimeError(
- 'App server failed to start (status=%d):\n%s' % (
- returncode, cls.appserver.stdout.read()))
+ "App server failed to start (status=%d):\n%s"
+ % (returncode, cls.appserver.stdout.read())
+ )
time.sleep(0.5)
else:
connection.close()
@@ -1791,12 +1824,11 @@ class LayerProcessController:
os.kill(cls.appserver.pid, signal.SIGTERM)
cls.appserver = None
# Go no further.
- raise AssertionError('App server startup timed out.')
+ raise AssertionError("App server startup timed out.")
class AppServerLayer(LaunchpadFunctionalLayer):
- """Layer for tests that run in the webapp environment with an app server.
- """
+ """Layer for tests that run in a webapp environment with an app server."""
@classmethod
@profiled
@@ -1827,7 +1859,7 @@ class CeleryJobLayer(AppServerLayer):
@classmethod
@profiled
def setUp(cls):
- cls.celery_worker = celery_worker('launchpad_job')
+ cls.celery_worker = celery_worker("launchpad_job")
cls.celery_worker.__enter__()
@classmethod
@@ -1845,7 +1877,7 @@ class CelerySlowJobLayer(AppServerLayer):
@classmethod
@profiled
def setUp(cls):
- cls.celery_worker = celery_worker('launchpad_job_slow')
+ cls.celery_worker = celery_worker("launchpad_job_slow")
cls.celery_worker.__enter__()
@classmethod
@@ -1863,7 +1895,7 @@ class CeleryBzrsyncdJobLayer(AppServerLayer):
@classmethod
@profiled
def setUp(cls):
- cls.celery_worker = celery_worker('bzrsyncd_job')
+ cls.celery_worker = celery_worker("bzrsyncd_job")
cls.celery_worker.__enter__()
@classmethod
@@ -1881,7 +1913,7 @@ class CeleryBranchWriteJobLayer(AppServerLayer):
@classmethod
@profiled
def setUp(cls):
- cls.celery_worker = celery_worker('branch_write_job')
+ cls.celery_worker = celery_worker("branch_write_job")
cls.celery_worker.__enter__()
@classmethod
@@ -1892,8 +1924,7 @@ class CeleryBranchWriteJobLayer(AppServerLayer):
class ZopelessAppServerLayer(LaunchpadZopelessLayer):
- """Layer for tests that run in the zopeless environment with an appserver.
- """
+ """Layer for Zopeless tests with an appserver."""
@classmethod
@profiled
@@ -1947,7 +1978,7 @@ class YUIAppServerLayer(MemcachedLayer):
@profiled
def setUp(cls):
LayerProcessController.setConfig()
- LayerProcessController.startAppServer('run-testapp')
+ LayerProcessController.startAppServer("run-testapp")
@classmethod
@profiled
diff --git a/lib/lp/testing/librarianhelpers.py b/lib/lp/testing/librarianhelpers.py
index a416473..7151d20 100644
--- a/lib/lp/testing/librarianhelpers.py
+++ b/lib/lp/testing/librarianhelpers.py
@@ -4,7 +4,7 @@
"""Various helper functions for using the librarian in testing.."""
__all__ = [
- 'get_newest_librarian_file',
+ "get_newest_librarian_file",
]
from storm.expr import Desc
@@ -23,6 +23,10 @@ def get_newest_librarian_file():
:return: A file-like object of the file content.
"""
- alias = IStore(LibraryFileAlias).find(LibraryFileAlias).order_by(
- Desc(LibraryFileAlias.date_created)).first()
+ alias = (
+ IStore(LibraryFileAlias)
+ .find(LibraryFileAlias)
+ .order_by(Desc(LibraryFileAlias.date_created))
+ .first()
+ )
return getUtility(ILibrarianClient).getFileByAlias(alias.id)
diff --git a/lib/lp/testing/mail.py b/lib/lp/testing/mail.py
index 7198142..016b5b5 100644
--- a/lib/lp/testing/mail.py
+++ b/lib/lp/testing/mail.py
@@ -3,31 +3,28 @@
"""Useful helper functions used for testing."""
-from email.utils import formatdate
import os
+from email.utils import formatdate
from zope.component import getUtility
from lp.services.mail.mailbox import IMailBox
-from lp.services.mail.sendmail import (
- get_msgid,
- MailController,
- )
+from lp.services.mail.sendmail import MailController, get_msgid
-def create_mail_for_directoryMailBox(from_addr, to_addrs, subject, body,
- headers=None):
+def create_mail_for_directoryMailBox(
+ from_addr, to_addrs, subject, body, headers=None
+):
"""Create a email in the DirectoryMailBox."""
mc = MailController(from_addr, to_addrs, subject, body, headers)
message = mc.makeMessage()
- if 'message-id' not in message:
- message['Message-Id'] = get_msgid()
- if 'date' not in message:
- message['Date'] = formatdate()
+ if "message-id" not in message:
+ message["Message-Id"] = get_msgid()
+ if "date" not in message:
+ message["Date"] = formatdate()
# Since this is faking incoming email, set the X-Original-To.
- message['X-Original-To'] = to_addrs
+ message["X-Original-To"] = to_addrs
mailbox = getUtility(IMailBox)
- msg_file = open(
- os.path.join(mailbox.mail_dir, message['Message-Id']), 'w')
+ msg_file = open(os.path.join(mailbox.mail_dir, message["Message-Id"]), "w")
msg_file.write(message.as_string())
msg_file.close()
diff --git a/lib/lp/testing/mail_helpers.py b/lib/lp/testing/mail_helpers.py
index 5792861..d344936 100644
--- a/lib/lp/testing/mail_helpers.py
+++ b/lib/lp/testing/mail_helpers.py
@@ -16,7 +16,7 @@ from lp.registry.interfaces.persontransferjob import (
ISelfRenewalNotificationJobSource,
ITeamInvitationNotificationJobSource,
ITeamJoinNotificationJobSource,
- )
+)
from lp.services.config import config
from lp.services.job.runner import JobRunner
from lp.services.log.logger import DevNullLogger
@@ -38,13 +38,13 @@ def pop_notifications(sort_key=None, commit=True):
if commit:
transaction.commit()
if sort_key is None:
- sort_key = operator.itemgetter('To')
+ sort_key = operator.itemgetter("To")
notifications = []
for fromaddr, toaddrs, raw_message in stub.test_emails:
notification = email.message_from_bytes(raw_message)
- notification['X-Envelope-To'] = ', '.join(toaddrs)
- notification['X-Envelope-From'] = fromaddr
+ notification["X-Envelope-To"] = ", ".join(toaddrs)
+ notification["X-Envelope-From"] = fromaddr
notifications.append(notification)
stub.test_emails = []
@@ -53,14 +53,19 @@ def pop_notifications(sort_key=None, commit=True):
def sort_addresses(header):
"""Sort an address-list in an email header field body."""
- addresses = {address.strip() for address in header.split(',')}
+ addresses = {address.strip() for address in header.split(",")}
return ", ".join(sorted(addresses))
-def print_emails(include_reply_to=False, group_similar=False,
- include_rationale=False, include_for=False,
- notifications=None, include_notification_type=False,
- decode=False):
+def print_emails(
+ include_reply_to=False,
+ group_similar=False,
+ include_rationale=False,
+ include_for=False,
+ notifications=None,
+ include_notification_type=False,
+ decode=False,
+):
"""Pop all messages from stub.test_emails and print them with
their recipients.
@@ -87,49 +92,59 @@ def print_emails(include_reply_to=False, group_similar=False,
notifications = pop_notifications()
for message in notifications:
recipients = {
- recipient.strip()
- for recipient in message['To'].split(',')}
+ recipient.strip() for recipient in message["To"].split(",")
+ }
body = message.get_payload(decode=decode)
if group_similar:
# Strip the first line as it's different for each recipient.
- body = body[body.find(b'\n' if decode else '\n') + 1:]
+ body = body[body.find(b"\n" if decode else "\n") + 1 :]
if body in distinct_bodies and group_similar:
message, existing_recipients = distinct_bodies[body]
distinct_bodies[body] = (
- message, existing_recipients.union(recipients))
+ message,
+ existing_recipients.union(recipients),
+ )
else:
distinct_bodies[body] = (message, recipients)
for body in sorted(distinct_bodies):
message, recipients = distinct_bodies[body]
- print('From:', message['From'])
- print('To:', ", ".join(sorted(recipients)))
+ print("From:", message["From"])
+ print("To:", ", ".join(sorted(recipients)))
if include_reply_to:
- print('Reply-To:', message['Reply-To'])
- rationale_header = 'X-Launchpad-Message-Rationale'
+ print("Reply-To:", message["Reply-To"])
+ rationale_header = "X-Launchpad-Message-Rationale"
if include_rationale and rationale_header in message:
- print('%s: %s' % (rationale_header, message[rationale_header]))
- for_header = 'X-Launchpad-Message-For'
+ print("%s: %s" % (rationale_header, message[rationale_header]))
+ for_header = "X-Launchpad-Message-For"
if include_for and for_header in message:
- print('%s: %s' % (for_header, message[for_header]))
- notification_type_header = 'X-Launchpad-Notification-Type'
+ print("%s: %s" % (for_header, message[for_header]))
+ notification_type_header = "X-Launchpad-Notification-Type"
if include_notification_type and notification_type_header in message:
- print('%s: %s' % (
- notification_type_header, message[notification_type_header]))
- print('Subject:', message['Subject'])
+ print(
+ "%s: %s"
+ % (notification_type_header, message[notification_type_header])
+ )
+ print("Subject:", message["Subject"])
print(six.ensure_text(body))
print("-" * 40)
-def print_distinct_emails(include_reply_to=False, include_rationale=True,
- include_for=False, include_notification_type=True,
- decode=False):
+def print_distinct_emails(
+ include_reply_to=False,
+ include_rationale=True,
+ include_for=False,
+ include_notification_type=True,
+ decode=False,
+):
"""A convenient shortcut for `print_emails`(group_similar=True)."""
- return print_emails(group_similar=True,
- include_reply_to=include_reply_to,
- include_rationale=include_rationale,
- include_for=include_for,
- include_notification_type=include_notification_type,
- decode=decode)
+ return print_emails(
+ group_similar=True,
+ include_reply_to=include_reply_to,
+ include_rationale=include_rationale,
+ include_for=include_for,
+ include_notification_type=include_notification_type,
+ decode=decode,
+ )
def run_mail_jobs():
@@ -146,12 +161,12 @@ def run_mail_jobs():
# the queued jobs.
transaction.commit()
for interface in (
- IExpiringMembershipNotificationJobSource,
- IMembershipNotificationJobSource,
- ISelfRenewalNotificationJobSource,
- ITeamInvitationNotificationJobSource,
- ITeamJoinNotificationJobSource,
- ):
+ IExpiringMembershipNotificationJobSource,
+ IMembershipNotificationJobSource,
+ ISelfRenewalNotificationJobSource,
+ ITeamInvitationNotificationJobSource,
+ ITeamJoinNotificationJobSource,
+ ):
job_source = getUtility(interface)
logger = DevNullLogger()
dbuser_name = getattr(config, interface.__name__).dbuser
diff --git a/lib/lp/testing/matchers.py b/lib/lp/testing/matchers.py
index 2f5ffad..47e7c92 100644
--- a/lib/lp/testing/matchers.py
+++ b/lib/lp/testing/matchers.py
@@ -2,52 +2,49 @@
# GNU Affero General Public License version 3 (see the file LICENSE).
__all__ = [
- 'BrowsesWithQueryLimit',
- 'Contains',
- 'DocTestMatches',
- 'DoesNotCorrectlyProvide',
- 'DoesNotProvide',
- 'EqualsIgnoringWhitespace',
- 'FileContainsBytes',
- 'HasQueryCount',
- 'IsNotProxied',
- 'IsProxied',
- 'MatchesPickerText',
- 'MatchesTagText',
- 'MissingElement',
- 'MultipleElements',
- 'Provides',
- 'ProvidesAndIsProxied',
- ]
+ "BrowsesWithQueryLimit",
+ "Contains",
+ "DocTestMatches",
+ "DoesNotCorrectlyProvide",
+ "DoesNotProvide",
+ "EqualsIgnoringWhitespace",
+ "FileContainsBytes",
+ "HasQueryCount",
+ "IsNotProxied",
+ "IsProxied",
+ "MatchesPickerText",
+ "MatchesTagText",
+ "MissingElement",
+ "MultipleElements",
+ "Provides",
+ "ProvidesAndIsProxied",
+]
from lazr.lifecycle.snapshot import Snapshot
from testtools import matchers
from testtools.content import text_content
+from testtools.matchers import DocTestMatches as OriginalDocTestMatches
from testtools.matchers import (
- DocTestMatches as OriginalDocTestMatches,
Equals,
FileContains,
LessThan,
Matcher,
Mismatch,
PathExists,
- )
+)
from testtools.matchers._higherorder import MismatchesAll
from zope.interface.exceptions import (
BrokenImplementation,
BrokenMethodImplementation,
DoesNotImplement,
- )
+)
from zope.interface.verify import verifyObject
from zope.security.proxy import Proxy
from lp.services.database.sqlbase import flush_database_caches
from lp.services.webapp import canonical_url
from lp.services.webapp.batching import BatchNavigator
-from lp.testing import (
- normalize_whitespace,
- RequestTimelineCollector,
- )
+from lp.testing import RequestTimelineCollector, normalize_whitespace
from lp.testing._login import person_logged_in
@@ -75,9 +72,11 @@ class BrowsesWithQueryLimit(Matcher):
def match(self, context):
# circular dependencies.
from lp.testing.pages import setupBrowserForUser
+
with person_logged_in(self.user):
context_url = canonical_url(
- context, view_name=self.view_name, **self.options)
+ context, view_name=self.view_name, **self.options
+ )
browser = setupBrowserForUser(self.user)
flush_database_caches()
with RequestTimelineCollector() as collector:
@@ -126,8 +125,11 @@ class DoesNotCorrectlyProvide(DoesNotProvide):
extra = ": %s" % self.extra
else:
extra = "."
- return ("%r claims to provide %r, but does not do so correctly%s"
- % (self.obj, self.interface, extra))
+ return "%r claims to provide %r, but does not do so correctly%s" % (
+ self.obj,
+ self.interface,
+ extra,
+ )
class Provides(Matcher):
@@ -151,13 +153,17 @@ class Provides(Matcher):
try:
if not verifyObject(self.interface, matchee):
passed = False
- except (BrokenImplementation, BrokenMethodImplementation,
- DoesNotImplement) as e:
+ except (
+ BrokenImplementation,
+ BrokenMethodImplementation,
+ DoesNotImplement,
+ ) as e:
passed = False
extra = str(e)
if not passed:
return DoesNotCorrectlyProvide(
- matchee, self.interface, extra=extra)
+ matchee, self.interface, extra=extra
+ )
return None
@@ -188,8 +194,10 @@ class HasQueryCount(Matcher):
if mismatch is None:
return None
return _MismatchedQueryCount(
- mismatch, something,
- other_query_collector=self.other_query_collector)
+ mismatch,
+ something,
+ other_query_collector=self.other_query_collector,
+ )
class _MismatchedQueryCount(Mismatch):
@@ -208,20 +216,22 @@ class _MismatchedQueryCount(Mismatch):
result = []
for query in collector.queries:
start, stop, dbname, statement, backtrace = query
- result.append('%d-%d@%s %s' % (
- start, stop, dbname, statement.rstrip()))
- result.append('-' * 70)
+ result.append(
+ "%d-%d@%s %s" % (start, stop, dbname, statement.rstrip())
+ )
+ result.append("-" * 70)
if backtrace is not None:
result.append(backtrace.rstrip())
- result.append('.' * 70)
- return text_content('\n'.join(result))
+ result.append("." * 70)
+ return text_content("\n".join(result))
def get_details(self):
details = {}
- details['queries'] = self._getQueryDetails(self.query_collector)
+ details["queries"] = self._getQueryDetails(self.query_collector)
if self.other_query_collector is not None:
- details['other_queries'] = self._getQueryDetails(
- self.other_query_collector)
+ details["other_queries"] = self._getQueryDetails(
+ self.other_query_collector
+ )
return details
@@ -272,7 +282,6 @@ class ProvidesAndIsProxied(Matcher):
class DoesNotContain(Mismatch):
-
def __init__(self, matchee, expected):
"""Create a DoesNotContain Mismatch.
@@ -283,8 +292,7 @@ class DoesNotContain(Mismatch):
self.expected = expected
def describe(self):
- return "'%s' does not contain '%s'." % (
- self.matchee, self.expected)
+ return "'%s' does not contain '%s'." % (self.matchee, self.expected)
class Contains(Matcher):
@@ -323,23 +331,28 @@ class IsConfiguredBatchNavigator(Matcher):
if batch_size:
self._batch = Equals(batch_size)
self.matchers = dict(
- _singular_heading=self._single, _plural_heading=self._plural)
+ _singular_heading=self._single, _plural_heading=self._plural
+ )
if self._batch:
- self.matchers['default_size'] = self._batch
+ self.matchers["default_size"] = self._batch
def __str__(self):
if self._batch:
batch = ", %r" % self._batch.expected
else:
- batch = ''
+ batch = ""
return "ConfiguredBatchNavigator(%r, %r%s)" % (
- self._single.expected, self._plural.expected, batch)
+ self._single.expected,
+ self._plural.expected,
+ batch,
+ )
def match(self, matchee):
if not isinstance(matchee, BatchNavigator):
# Testtools doesn't have an IsInstanceMismatch yet.
return matchers._BinaryMismatch(
- BatchNavigator, 'isinstance', matchee)
+ BatchNavigator, "isinstance", matchee
+ )
mismatches = []
for attrname, matcher in self.matchers.items():
mismatch = matcher.match(getattr(matchee, attrname))
@@ -350,14 +363,15 @@ class IsConfiguredBatchNavigator(Matcher):
class WasSnapshotted(Mismatch):
-
def __init__(self, matchee, attribute):
self.matchee = matchee
self.attribute = attribute
def describe(self):
return "Snapshot of %s should not include %s" % (
- self.matchee, self.attribute)
+ self.matchee,
+ self.attribute,
+ )
class DoesNotSnapshot(Matcher):
@@ -370,7 +384,9 @@ class DoesNotSnapshot(Matcher):
def __str__(self):
return "Does not include %s when Snapshot is provided %s." % (
- ', '.join(self.attr_list), self.interface)
+ ", ".join(self.attr_list),
+ self.interface,
+ )
def match(self, matchee):
snapshot = Snapshot(matchee, providing=self.interface)
@@ -391,29 +407,27 @@ def DocTestMatches(example):
Uses the default doctest flags used across Launchpad.
"""
from lp.testing.systemdocs import default_optionflags
+
return OriginalDocTestMatches(example, default_optionflags)
class SoupMismatch(Mismatch):
-
def __init__(self, widget_id, soup_content):
self.widget_id = widget_id
self.soup_content = soup_content
def get_details(self):
- return {'content': text_content(str(self.soup_content))}
+ return {"content": text_content(str(self.soup_content))}
class MissingElement(SoupMismatch):
-
def describe(self):
- return 'No HTML element found with id %r' % self.widget_id
+ return "No HTML element found with id %r" % self.widget_id
class MultipleElements(SoupMismatch):
-
def describe(self):
- return 'HTML id %r found multiple times in document' % self.widget_id
+ return "HTML id %r found multiple times in document" % self.widget_id
class MatchesTagText(Matcher):
@@ -430,6 +444,7 @@ class MatchesTagText(Matcher):
def match(self, matchee):
# Here to avoid circular dependancies.
from lp.testing.pages import extract_text
+
widgets = self.soup_content.find_all(id=self.tag_id)
if len(widgets) == 0:
return MissingElement(self.tag_id, self.soup_content)
@@ -454,13 +469,14 @@ class MatchesPickerText(Matcher):
def match(self, matchee):
# Here to avoid circular dependancies.
from lp.testing.pages import extract_text
+
widgets = self.soup_content.find_all(id=self.widget_id)
if len(widgets) == 0:
return MissingElement(self.widget_id, self.soup_content)
elif len(widgets) > 1:
return MultipleElements(self.widget_id, self.soup_content)
widget = widgets[0]
- text = widget.find_all(attrs={'class': 'yui3-activator-data-box'})[0]
+ text = widget.find_all(attrs={"class": "yui3-activator-data-box"})[0]
text_matcher = DocTestMatches(extract_text(text))
return text_matcher.match(matchee)
diff --git a/lib/lp/testing/menu.py b/lib/lp/testing/menu.py
index bce4988..61f2c83 100644
--- a/lib/lp/testing/menu.py
+++ b/lib/lp/testing/menu.py
@@ -4,14 +4,11 @@
"""Helpers for testing menus."""
__all__ = [
- 'summarise_tal_links',
- 'make_fake_request',
- ]
+ "summarise_tal_links",
+ "make_fake_request",
+]
-from zope.security.management import (
- endInteraction,
- newInteraction,
- )
+from zope.security.management import endInteraction, newInteraction
from zope.security.proxy import isinstance as zope_isinstance
from lp.services.webapp import urlsplit
@@ -23,14 +20,14 @@ from lp.services.webapp.servers import LaunchpadTestRequest
def check_menu_links(menu):
context = menu.context
for link in menu.iterlinks():
- if link.target.startswith(('/', 'http://')):
+ if link.target.startswith(("/", "http://")):
# The context is not the context of this target.
continue
- if '?' in link.target:
- view_name, _args = link.target.split('?')
+ if "?" in link.target:
+ view_name, _args = link.target.split("?")
else:
view_name = link.target
- if view_name == '':
+ if view_name == "":
view_name = None
try:
canonical_url(context, view_name=view_name, rootsite=link.site)
@@ -39,7 +36,7 @@ def check_menu_links(menu):
url = canonical_url(context)
except Exception:
url = repr(context)
- return 'Bad link %s: %s' % (link.name, url)
+ return "Bad link %s: %s" % (link.name, url)
return True
@@ -60,14 +57,14 @@ def summarise_tal_links(links):
else:
link = key
if ILink.providedBy(link):
- print('link %s' % link.name)
- attributes = ('url', 'enabled', 'menu', 'selected', 'linked')
+ print("link %s" % link.name)
+ attributes = ("url", "enabled", "menu", "selected", "linked")
for attrname in attributes:
if not hasattr(link, attrname):
continue
- print(' %s:' % attrname, getattr(link, attrname))
+ print(" %s:" % attrname, getattr(link, attrname))
else:
- print('attribute %s: %s' % (key, link))
+ print("attribute %s: %s" % (key, link))
def make_fake_request(url, traversed_objects=None):
@@ -77,12 +74,10 @@ def make_fake_request(url, traversed_objects=None):
traversed_objects attribute.
"""
url_parts = urlsplit(url)
- server_url = '://'.join(url_parts[0:2])
+ server_url = "://".join(url_parts[0:2])
path_info = url_parts[2]
- request = LaunchpadTestRequest(
- SERVER_URL=server_url,
- PATH_INFO=path_info)
- request._traversed_names = path_info.split('/')[1:]
+ request = LaunchpadTestRequest(SERVER_URL=server_url, PATH_INFO=path_info)
+ request._traversed_names = path_info.split("/")[1:]
if traversed_objects is not None:
request.traversed_objects = traversed_objects[:]
# After making the request, setup a new interaction.
diff --git a/lib/lp/testing/pages.py b/lib/lp/testing/pages.py
index 6e2d360..f0eb960 100644
--- a/lib/lp/testing/pages.py
+++ b/lib/lp/testing/pages.py
@@ -3,16 +3,18 @@
"""Testing infrastructure for page tests."""
-from contextlib import contextmanager
-from datetime import datetime
import doctest
-from io import BytesIO
-from itertools import chain
import os
import re
import unittest
+from contextlib import contextmanager
+from datetime import datetime
+from io import BytesIO
+from itertools import chain
from urllib.parse import urljoin
+import six
+import transaction
from bs4.element import (
CData,
Comment,
@@ -22,52 +24,36 @@ from bs4.element import (
PageElement,
ProcessingInstruction,
Tag,
- )
+)
from lazr.restful.testing.webservice import WebServiceCaller
from oauthlib import oauth1
-import six
from soupsieve import escape as css_escape
-import transaction
from webtest import TestRequest
-from zope.app.wsgi.testlayer import (
- FakeResponse,
- NotInBrowserLayer,
- )
+from zope.app.wsgi.testlayer import FakeResponse, NotInBrowserLayer
from zope.component import getUtility
from zope.security.management import setSecurityPolicy
from zope.security.proxy import removeSecurityProxy
+from zope.testbrowser.browser import BrowserStateError
+from zope.testbrowser.browser import Link as _Link
from zope.testbrowser.browser import (
- BrowserStateError,
- isMatching,
- Link as _Link,
LinkNotFoundError,
+ isMatching,
normalizeWhitespace,
- )
-from zope.testbrowser.wsgi import (
- Browser as _Browser,
- Layer as TestBrowserWSGILayer,
- )
+)
+from zope.testbrowser.wsgi import Browser as _Browser
+from zope.testbrowser.wsgi import Layer as TestBrowserWSGILayer
from lp.app.interfaces.launchpad import ILaunchpadCelebrities
from lp.registry.errors import NameAlreadyTaken
from lp.registry.interfaces.teammembership import TeamMembershipStatus
-from lp.services.beautifulsoup import (
- BeautifulSoup,
- SoupStrainer,
- )
+from lp.services.beautifulsoup import BeautifulSoup, SoupStrainer
from lp.services.config import config
from lp.services.encoding import wsgi_native_string
from lp.services.helpers import backslashreplace
-from lp.services.oauth.interfaces import (
- IOAuthConsumerSet,
- OAUTH_REALM,
- )
+from lp.services.oauth.interfaces import OAUTH_REALM, IOAuthConsumerSet
from lp.services.webapp import canonical_url
from lp.services.webapp.authorization import LaunchpadPermissiveSecurityPolicy
-from lp.services.webapp.interfaces import (
- ISession,
- OAuthPermission,
- )
+from lp.services.webapp.interfaces import ISession, OAuthPermission
from lp.services.webapp.servers import LaunchpadTestRequest
from lp.services.webapp.url import urlsplit
from lp.testing import (
@@ -77,22 +63,17 @@ from lp.testing import (
login_person,
logout,
person_logged_in,
- )
+)
from lp.testing.dbuser import dbuser
from lp.testing.factory import LaunchpadObjectFactory
from lp.testing.layers import PageTestLayer
-from lp.testing.systemdocs import (
- LayeredDocFileSuite,
- PrettyPrinter,
- stop,
- )
-
+from lp.testing.systemdocs import LayeredDocFileSuite, PrettyPrinter, stop
SAMPLEDATA_ACCESS_SECRETS = {
- 'salgado-read-nonprivate': 'secret',
- 'salgado-change-anything': 'test',
- 'nopriv-read-nonprivate': 'mystery',
- }
+ "salgado-read-nonprivate": "secret",
+ "salgado-change-anything": "test",
+ "nopriv-read-nonprivate": "mystery",
+}
def http(string, handle_errors=True):
@@ -109,17 +90,17 @@ def http(string, handle_errors=True):
raise NotInBrowserLayer(NotInBrowserLayer.__doc__)
if not isinstance(string, bytes):
- string = string.encode('UTF-8')
+ string = string.encode("UTF-8")
request = TestRequest.from_file(BytesIO(string.lstrip()))
- request.environ['wsgi.handleErrors'] = handle_errors
- if 'HTTP_HOST' in request.environ:
- if ':' in request.environ['HTTP_HOST']:
- host, port = request.environ['HTTP_HOST'].split(':', 1)
+ request.environ["wsgi.handleErrors"] = handle_errors
+ if "HTTP_HOST" in request.environ:
+ if ":" in request.environ["HTTP_HOST"]:
+ host, port = request.environ["HTTP_HOST"].split(":", 1)
else:
- host = request.environ['HTTP_HOST']
+ host = request.environ["HTTP_HOST"]
port = 80
- request.environ['SERVER_NAME'] = host
- request.environ['SERVER_PORT'] = int(port)
+ request.environ["SERVER_NAME"] = host
+ request.environ["SERVER_PORT"] = int(port)
response = request.get_response(app)
return FakeResponse(response, request)
@@ -127,11 +108,17 @@ def http(string, handle_errors=True):
class LaunchpadWebServiceCaller(WebServiceCaller):
"""A class for making calls to Launchpad web services."""
- def __init__(self, oauth_consumer_key=None, oauth_access_key=None,
- oauth_access_secret=None, access_token_secret=None,
- handle_errors=True,
- domain='api.launchpad.test', protocol='http',
- default_api_version=None):
+ def __init__(
+ self,
+ oauth_consumer_key=None,
+ oauth_access_key=None,
+ oauth_access_secret=None,
+ access_token_secret=None,
+ handle_errors=True,
+ domain="api.launchpad.test",
+ protocol="http",
+ default_api_version=None,
+ ):
"""Create a LaunchpadWebServiceCaller.
:param oauth_consumer_key: The OAuth consumer key to use.
:param oauth_access_key: The OAuth access key to use for the request.
@@ -148,12 +135,14 @@ class LaunchpadWebServiceCaller(WebServiceCaller):
if oauth_consumer_key is not None and oauth_access_key is not None:
if oauth_access_secret is None:
oauth_access_secret = SAMPLEDATA_ACCESS_SECRETS.get(
- oauth_access_key, '')
+ oauth_access_key, ""
+ )
self.oauth_client = oauth1.Client(
oauth_consumer_key,
resource_owner_key=oauth_access_key,
resource_owner_secret=oauth_access_secret,
- signature_method=oauth1.SIGNATURE_PLAINTEXT)
+ signature_method=oauth1.SIGNATURE_PLAINTEXT,
+ )
logout()
elif access_token_secret is not None:
self.access_token_secret = access_token_secret
@@ -167,15 +156,20 @@ class LaunchpadWebServiceCaller(WebServiceCaller):
def addHeadersTo(self, full_url, full_headers):
if self.oauth_client is not None:
_, oauth_headers, _ = self.oauth_client.sign(
- full_url, realm=OAUTH_REALM)
- full_headers.update({
- wsgi_native_string(key): wsgi_native_string(value)
- for key, value in oauth_headers.items()})
+ full_url, realm=OAUTH_REALM
+ )
+ full_headers.update(
+ {
+ wsgi_native_string(key): wsgi_native_string(value)
+ for key, value in oauth_headers.items()
+ }
+ )
elif self.access_token_secret is not None:
- full_headers['Authorization'] = (
- 'Token %s' % self.access_token_secret)
+ full_headers["Authorization"] = (
+ "Token %s" % self.access_token_secret
+ )
if not self.handle_errors:
- full_headers['X_Zope_handle_errors'] = 'False'
+ full_headers["X_Zope_handle_errors"] = "False"
def extract_url_parameter(url, parameter):
@@ -186,9 +180,9 @@ def extract_url_parameter(url, parameter):
or how the parameters are ordered.
"""
scheme, host, path, query, fragment = urlsplit(url)
- args = query.split('&')
+ args = query.split("&")
for arg in args:
- key, value = arg.split('=')
+ key, value = arg.split("=")
if key == parameter:
return arg
return None
@@ -201,18 +195,20 @@ class DuplicateIdError(Exception):
def find_tag_by_id(content, id):
"""Find and return the tag with the given ID"""
if isinstance(content, PageElement):
- elements_with_id = content.find_all(True, {'id': id})
+ elements_with_id = content.find_all(True, {"id": id})
else:
elements_with_id = [
- tag for tag in BeautifulSoup(
- content, parse_only=SoupStrainer(id=id))]
+ tag
+ for tag in BeautifulSoup(content, parse_only=SoupStrainer(id=id))
+ ]
if len(elements_with_id) == 0:
return None
elif len(elements_with_id) == 1:
return elements_with_id[0]
else:
raise DuplicateIdError(
- "Found %d elements with id '%s'" % (len(elements_with_id), id))
+ "Found %d elements with id '%s'" % (len(elements_with_id), id)
+ )
def first_tag_by_class(content, class_):
@@ -230,13 +226,15 @@ def find_tags_by_class(content, class_, only_first=False):
return False
classes = set(value.split())
return match_classes.issubset(classes)
+
soup = BeautifulSoup(
- content, parse_only=SoupStrainer(attrs={'class': class_matcher}))
+ content, parse_only=SoupStrainer(attrs={"class": class_matcher})
+ )
if only_first:
find = BeautifulSoup.find
else:
find = BeautifulSoup.find_all
- return find(soup, attrs={'class': class_matcher})
+ return find(soup, attrs={"class": class_matcher})
def find_portlet(content, name):
@@ -245,23 +243,23 @@ def find_portlet(content, name):
ending whitespace is also ignored, as are non-text elements such as
images.
"""
- whitespace_re = re.compile(r'\s+')
- name = whitespace_re.sub(' ', name.strip())
- for portlet in find_tags_by_class(content, 'portlet'):
- if portlet.find('h2'):
- portlet_title = extract_text(portlet.find('h2'))
- if name == whitespace_re.sub(' ', portlet_title.strip()):
+ whitespace_re = re.compile(r"\s+")
+ name = whitespace_re.sub(" ", name.strip())
+ for portlet in find_tags_by_class(content, "portlet"):
+ if portlet.find("h2"):
+ portlet_title = extract_text(portlet.find("h2"))
+ if name == whitespace_re.sub(" ", portlet_title.strip()):
return portlet
return None
def find_main_content(content):
"""Return the main content of the page, excluding any portlets."""
- main_content = find_tag_by_id(content, 'maincontent')
+ main_content = find_tag_by_id(content, "maincontent")
if main_content is None:
# One-column pages don't use a <div id="maincontent">, so we
# use the next best thing: <div id="container">.
- main_content = find_tag_by_id(content, 'container')
+ main_content = find_tag_by_id(content, "container")
if main_content is None:
# Simple pages have neither of these, so as a last resort, we get
# the page <body>.
@@ -271,15 +269,20 @@ def find_main_content(content):
def get_feedback_messages(content):
"""Find and return the feedback messages of the page."""
- message_classes = ['message', 'informational message', 'error message',
- 'warning message']
+ message_classes = [
+ "message",
+ "informational message",
+ "error message",
+ "warning message",
+ ]
soup = BeautifulSoup(
content,
- parse_only=SoupStrainer(['div', 'p'], {'class': message_classes}))
+ parse_only=SoupStrainer(["div", "p"], {"class": message_classes}),
+ )
return [extract_text(tag) for tag in soup]
-def print_feedback_messages(content, formatter='minimal'):
+def print_feedback_messages(content, formatter="minimal"):
"""Print out the feedback messages."""
for message in get_feedback_messages(content):
print(extract_text(message, formatter=formatter))
@@ -295,11 +298,11 @@ def print_table(content, columns=None, skip_rows=None, sep="\t"):
None no rows are skipped.
:param sep the separator to be used between output items.
"""
- for row_num, row in enumerate(content.find_all('tr')):
+ for row_num, row in enumerate(content.find_all("tr")):
if skip_rows is not None and row_num in skip_rows:
continue
row_content = []
- for col_num, item in enumerate(row.find_all('td')):
+ for col_num, item in enumerate(row.find_all("td")):
if columns is None or col_num in columns:
row_content.append(extract_text(item))
if len(row_content) > 0:
@@ -312,18 +315,18 @@ def get_radio_button_text_for_field(soup, name):
The resulting output will look something like:
['(*) A checked option', '( ) An unchecked option']
"""
- buttons = soup.find_all(
- 'input', {'name': 'field.%s' % name})
+ buttons = soup.find_all("input", {"name": "field.%s" % name})
for button in buttons:
- if button.parent.name == 'label':
+ if button.parent.name == "label":
label = extract_text(button.parent)
else:
label = extract_text(
- soup.find('label', attrs={'for': button['id']}))
- if button.get('checked', None):
- radio = '(*)'
+ soup.find("label", attrs={"for": button["id"]})
+ )
+ if button.get("checked", None):
+ radio = "(*)"
else:
- radio = '( )'
+ radio = "( )"
yield "%s %s" % (radio, label)
@@ -341,23 +344,49 @@ def print_radio_button_field(content, name):
def strip_label(label):
"""Strip surrounding whitespace and non-breaking spaces."""
- return label.replace('\xC2', '').replace('\xA0', '').strip()
+ return label.replace("\xC2", "").replace("\xA0", "").strip()
IGNORED_ELEMENTS = [
- Comment, Declaration, Doctype, ProcessingInstruction,
- ]
+ Comment,
+ Declaration,
+ Doctype,
+ ProcessingInstruction,
+]
ELEMENTS_INTRODUCING_NEWLINE = [
- 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ul', 'ol', 'pre', 'dl',
- 'div', 'noscript', 'blockquote', 'form', 'hr', 'table', 'fieldset',
- 'address', 'li', 'dt', 'dd', 'th', 'td', 'caption', 'br']
-
-
-NEWLINES_RE = re.compile('\n+')
-LEADING_AND_TRAILING_SPACES_RE = re.compile(
- '(^[ \t]+)|([ \t]$)', re.MULTILINE)
-TABS_AND_SPACES_RE = re.compile('[ \t]+')
-NBSP_RE = re.compile(' | |\xa0')
+ "p",
+ "h1",
+ "h2",
+ "h3",
+ "h4",
+ "h5",
+ "h6",
+ "ul",
+ "ol",
+ "pre",
+ "dl",
+ "div",
+ "noscript",
+ "blockquote",
+ "form",
+ "hr",
+ "table",
+ "fieldset",
+ "address",
+ "li",
+ "dt",
+ "dd",
+ "th",
+ "td",
+ "caption",
+ "br",
+]
+
+
+NEWLINES_RE = re.compile("\n+")
+LEADING_AND_TRAILING_SPACES_RE = re.compile("(^[ \t]+)|([ \t]$)", re.MULTILINE)
+TABS_AND_SPACES_RE = re.compile("[ \t]+")
+NBSP_RE = re.compile(" | |\xa0")
def extract_link_from_tag(tag, base=None):
@@ -371,15 +400,16 @@ def extract_link_from_tag(tag, base=None):
else:
link = tag
- href = dict(link.attrs).get('href')
+ href = dict(link.attrs).get("href")
if base is None:
return href
else:
return urljoin(base, href)
-def extract_text(content, extract_image_text=False, skip_tags=None,
- formatter='minimal'):
+def extract_text(
+ content, extract_image_text=False, skip_tags=None, formatter="minimal"
+):
"""Return the text stripped of all tags.
All runs of tabs and spaces are replaced by a single space and runs of
@@ -387,7 +417,7 @@ def extract_text(content, extract_image_text=False, skip_tags=None,
spaces are stripped.
"""
if skip_tags is None:
- skip_tags = ['script']
+ skip_tags = ["script"]
if not isinstance(content, PageElement):
soup = BeautifulSoup(content)
else:
@@ -406,31 +436,31 @@ def extract_text(content, extract_image_text=False, skip_tags=None,
else:
if isinstance(node, Tag):
# If the node has the class "sortkey" then it is invisible.
- if node.get('class') == ['sortkey']:
+ if node.get("class") == ["sortkey"]:
continue
- elif getattr(node, 'name', '') in skip_tags:
+ elif getattr(node, "name", "") in skip_tags:
continue
if node.name.lower() in ELEMENTS_INTRODUCING_NEWLINE:
- result.append('\n')
+ result.append("\n")
# If extract_image_text is True and the node is an
# image, try to find its title or alt attributes.
- if extract_image_text and node.name.lower() == 'img':
+ if extract_image_text and node.name.lower() == "img":
# Title outweighs alt text for the purposes of
# pagetest output.
- if node.get('title') is not None:
- result.append(node['title'])
- elif node.get('alt') is not None:
- result.append(node['alt'])
+ if node.get("title") is not None:
+ result.append(node["title"])
+ elif node.get("alt") is not None:
+ result.append(node["alt"])
# Process this node's children next.
nodes[0:0] = list(node)
- text = ''.join(result)
- text = NBSP_RE.sub(' ', text)
- text = TABS_AND_SPACES_RE.sub(' ', text)
- text = LEADING_AND_TRAILING_SPACES_RE.sub('', text)
- text = NEWLINES_RE.sub('\n', text)
+ text = "".join(result)
+ text = NBSP_RE.sub(" ", text)
+ text = TABS_AND_SPACES_RE.sub(" ", text)
+ text = LEADING_AND_TRAILING_SPACES_RE.sub("", text)
+ text = NEWLINES_RE.sub("\n", text)
# Remove possible newlines at beginning and end.
return text.strip()
@@ -445,49 +475,49 @@ def parse_relationship_section(content):
See package-relationship-pages.rst and related.
"""
soup = BeautifulSoup(content)
- section = soup.find('ul')
- whitespace_re = re.compile(r'\s+')
+ section = soup.find("ul")
+ whitespace_re = re.compile(r"\s+")
if section is None:
- print('EMPTY SECTION')
+ print("EMPTY SECTION")
return
- for li in section.find_all('li'):
+ for li in section.find_all("li"):
if li.a:
link = li.a
- content = whitespace_re.sub(' ', link.string.strip())
- url = link['href']
+ content = whitespace_re.sub(" ", link.string.strip())
+ url = link["href"]
print('LINK: "%s" -> %s' % (content, url))
else:
- content = whitespace_re.sub(' ', li.string.strip())
+ content = whitespace_re.sub(" ", li.string.strip())
print('TEXT: "%s"' % content)
def print_action_links(content):
"""Print action menu urls."""
- actions = find_tag_by_id(content, 'actions')
+ actions = find_tag_by_id(content, "actions")
if actions is None:
print("No actions portlet")
return
- entries = actions.find_all('li')
+ entries = actions.find_all("li")
for entry in entries:
if entry.a:
- print('%s: %s' % (entry.a.string, entry.a['href']))
+ print("%s: %s" % (entry.a.string, entry.a["href"]))
elif entry.strong:
print(entry.strong.string)
def print_navigation_links(content):
"""Print navigation menu urls."""
- navigation_links = find_tag_by_id(content, 'navigation-tabs')
+ navigation_links = find_tag_by_id(content, "navigation-tabs")
if navigation_links is None:
print("No navigation links")
return
- title = navigation_links.find('label')
+ title = navigation_links.find("label")
if title is not None:
- print('= %s =' % title.string)
- entries = navigation_links.find_all(['strong', 'a'])
+ print("= %s =" % title.string)
+ entries = navigation_links.find_all(["strong", "a"])
for entry in entries:
try:
- print('%s: %s' % (entry.span.string, entry['href']))
+ print("%s: %s" % (entry.span.string, entry["href"]))
except KeyError:
print(entry.span.string)
@@ -512,13 +542,15 @@ def print_portlet_links(content, name, base=None):
if portlet_contents is None:
print("No portlet found with name:", name)
return
- portlet_links = portlet_contents.find_all('a')
+ portlet_links = portlet_contents.find_all("a")
if len(portlet_links) == 0:
print("No links were found in the portlet.")
return
for portlet_link in portlet_links:
- print('%s: %s' % (portlet_link.string,
- extract_link_from_tag(portlet_link, base)))
+ print(
+ "%s: %s"
+ % (portlet_link.string, extract_link_from_tag(portlet_link, base))
+ )
def print_submit_buttons(content):
@@ -527,19 +559,20 @@ def print_submit_buttons(content):
Use this to check that the buttons on a page match your expectations.
"""
buttons = find_main_content(content).find_all(
- 'input', attrs={'class': 'button', 'type': 'submit'})
+ "input", attrs={"class": "button", "type": "submit"}
+ )
if buttons is None:
print("No buttons found")
else:
for button in buttons:
- print(button['value'])
+ print(button["value"])
def print_comments(page):
"""Print the comments on a BugTask index page."""
main_content = find_main_content(page)
- for comment in main_content('div', 'boardCommentBody'):
- for li_tag in comment('li'):
+ for comment in main_content("div", "boardCommentBody"):
+ for li_tag in comment("li"):
print("Attachment: %s" % li_tag.a.decode_contents())
print(comment.div.decode_contents())
print("-" * 40)
@@ -547,22 +580,22 @@ def print_comments(page):
def print_batch_header(soup):
"""Print the batch navigator header."""
- navigation = soup.find('td', {'class': 'batch-navigation-index'})
+ navigation = soup.find("td", {"class": "batch-navigation-index"})
print(backslashreplace(extract_text(navigation)))
def print_self_link_of_entries(json_body):
"""Print the self_link attribute of each entry in the given JSON body."""
- links = sorted(entry['self_link'] for entry in json_body['entries'])
+ links = sorted(entry["self_link"] for entry in json_body["entries"])
for link in links:
print(link)
def print_ppa_packages(contents):
- packages = find_tags_by_class(contents, 'archive_package_row')
+ packages = find_tags_by_class(contents, "archive_package_row")
for pkg in packages:
print(extract_text(pkg))
- empty_section = find_tag_by_id(contents, 'empty-result')
+ empty_section = find_tag_by_id(contents, "empty-result")
if empty_section is not None:
print(extract_text(empty_section))
@@ -576,37 +609,37 @@ def print_location(contents):
for example, Overview, Bugs, and Translations.
The main heading is the first <h1> element in the page.
"""
- doc = find_tag_by_id(contents, 'document')
- heading = doc.find(attrs={'id': 'watermark-heading'}).find_all('a')
- container = doc.find(attrs={'class': 'breadcrumbs'})
+ doc = find_tag_by_id(contents, "document")
+ heading = doc.find(attrs={"id": "watermark-heading"}).find_all("a")
+ container = doc.find(attrs={"class": "breadcrumbs"})
hierarchy = container.find_all(recursive=False) if container else []
segments = [extract_text(step) for step in chain(heading, hierarchy)]
if len(segments) == 0:
- breadcrumbs = 'None displayed'
+ breadcrumbs = "None displayed"
else:
- breadcrumbs = ' > '.join(segments)
+ breadcrumbs = " > ".join(segments)
- print('Hierarchy:', breadcrumbs)
- print('Tabs:')
+ print("Hierarchy:", breadcrumbs)
+ print("Tabs:")
print_location_apps(contents)
main_heading = doc.h1
if main_heading:
main_heading = extract_text(main_heading)
else:
- main_heading = '(No main heading)'
+ main_heading = "(No main heading)"
print("Main heading: %s" % main_heading)
def print_location_apps(contents):
"""Print the application tabs' text and URL."""
- location_apps = find_tag_by_id(contents, 'lp-apps')
+ location_apps = find_tag_by_id(contents, "lp-apps")
if location_apps is None:
- location_apps = first_tag_by_class(contents, 'watermark-apps-portlet')
+ location_apps = first_tag_by_class(contents, "watermark-apps-portlet")
if location_apps is not None:
- location_apps = location_apps.ul.find_all('li')
+ location_apps = location_apps.ul.find_all("li")
else:
- location_apps = location_apps.find_all('span')
+ location_apps = location_apps.find_all("span")
if location_apps is None:
print("(Application tabs omitted)")
elif len(location_apps) == 0:
@@ -614,12 +647,12 @@ def print_location_apps(contents):
else:
for tab in location_apps:
tab_text = extract_text(tab)
- if 'active' in tab['class']:
- tab_text += ' (selected)'
+ if "active" in tab["class"]:
+ tab_text += " (selected)"
if tab.a:
- link = tab.a['href']
+ link = tab.a["href"]
else:
- link = 'not linked'
+ link = "not linked"
print("* %s - %s" % (tab_text, link))
@@ -631,7 +664,7 @@ def print_tag_with_id(contents, id):
def print_errors(contents):
"""Print all the errors on the page."""
- errors = find_tags_by_class(contents, 'error')
+ errors = find_tags_by_class(contents, "error")
error_texts = [extract_text(error) for error in errors]
for error in error_texts:
print(error)
@@ -664,26 +697,29 @@ class Browser(_Browser):
for descendant in elem.descendants:
if isinstance(descendant, (NavigableString, CData)):
yield descendant
- elif isinstance(descendant, Tag) and descendant.name == 'img':
- yield '%s[%s]' % (
- descendant.get('alt', ''), descendant.name.upper())
+ elif isinstance(descendant, Tag) and descendant.name == "img":
+ yield "%s[%s]" % (
+ descendant.get("alt", ""),
+ descendant.name.upper(),
+ )
- return ''.join(list(get_strings(element)))
+ return "".join(list(get_strings(element)))
def getLink(self, text=None, url=None, id=None, index=0):
"""Search for both text nodes and image alt attributes."""
# XXX cjwatson 2019-11-09: This should be merged back into
# `zope.testbrowser.browser.Browser.getLink`.
- qa = 'a' if id is None else 'a#%s' % css_escape(id)
- qarea = 'area' if id is None else 'area#%s' % css_escape(id)
+ qa = "a" if id is None else "a#%s" % css_escape(id)
+ qarea = "area" if id is None else "area#%s" % css_escape(id)
html = self._html
links = html.select(qa)
links.extend(html.select(qarea))
matching = []
for elem in links:
- matches = (isMatching(self._getText(elem), text) and
- isMatching(elem.get('href', ''), url))
+ matches = isMatching(self._getText(elem), text) and isMatching(
+ elem.get("href", ""), url
+ )
if matches:
matching.append(elem)
@@ -733,12 +769,12 @@ def setupBrowserFreshLogin(user):
"""
request = LaunchpadTestRequest()
session = ISession(request)
- authdata = session['launchpad.authenticateduser']
- authdata['logintime'] = datetime.utcnow()
+ authdata = session["launchpad.authenticateduser"]
+ authdata["logintime"] = datetime.utcnow()
namespace = config.launchpad_session.cookie
- cookie = '%s=%s' % (namespace, session.client_id)
+ cookie = "%s=%s" % (namespace, session.client_id)
browser = setupBrowserForUser(user)
- browser.addHeader('Cookie', cookie)
+ browser.addHeader("Cookie", cookie)
return browser
@@ -747,10 +783,14 @@ def safe_canonical_url(*args, **kwargs):
return str(canonical_url(*args, **kwargs))
-def webservice_for_person(person, consumer_key='launchpad-library',
- permission=OAuthPermission.READ_PUBLIC,
- context=None, default_api_version=None,
- access_token_secret=None):
+def webservice_for_person(
+ person,
+ consumer_key="launchpad-library",
+ permission=OAuthPermission.READ_PUBLIC,
+ context=None,
+ default_api_version=None,
+ access_token_secret=None,
+):
"""Return a valid LaunchpadWebServiceCaller for the person.
Use this method to create a way to test the webservice that doesn't depend
@@ -759,7 +799,7 @@ def webservice_for_person(person, consumer_key='launchpad-library',
kwargs = {}
if person is not None:
if person.is_team:
- raise AssertionError('This cannot be used with teams.')
+ raise AssertionError("This cannot be used with teams.")
login(ANONYMOUS)
if access_token_secret is None:
oacs = getUtility(IOAuthConsumerSet)
@@ -769,12 +809,12 @@ def webservice_for_person(person, consumer_key='launchpad-library',
request_token, _ = consumer.newRequestToken()
request_token.review(person, permission, context)
access_token, access_secret = request_token.createAccessToken()
- kwargs['oauth_consumer_key'] = consumer_key
- kwargs['oauth_access_key'] = access_token.key
- kwargs['oauth_access_secret'] = access_secret
+ kwargs["oauth_consumer_key"] = consumer_key
+ kwargs["oauth_access_key"] = access_token.key
+ kwargs["oauth_access_secret"] = access_secret
else:
- kwargs['access_token_secret'] = access_token_secret
- kwargs['default_api_version'] = default_api_version
+ kwargs["access_token_secret"] = access_token_secret
+ kwargs["default_api_version"] = default_api_version
logout()
service = LaunchpadWebServiceCaller(**kwargs)
service.user = person
@@ -786,10 +826,11 @@ def setupDTCBrowser():
Ubuntu is the configured distribution.
"""
- login('foo.bar@xxxxxxxxxxxxx')
+ login("foo.bar@xxxxxxxxxxxxx")
try:
dtg_member = LaunchpadObjectFactory().makePerson(
- name='ubuntu-translations-coordinator', email="dtg-member@xxxxxx")
+ name="ubuntu-translations-coordinator", email="dtg-member@xxxxxx"
+ )
except NameAlreadyTaken:
# We have already created the translations coordinator
pass
@@ -797,31 +838,36 @@ def setupDTCBrowser():
dtg = LaunchpadObjectFactory().makeTranslationGroup(
name="ubuntu-translators",
title="Ubuntu Translators",
- owner=dtg_member)
+ owner=dtg_member,
+ )
ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
ubuntu.translationgroup = dtg
logout()
- return setupBrowser(auth='Basic dtg-member@xxxxxx:test')
+ return setupBrowser(auth="Basic dtg-member@xxxxxx:test")
def setupRosettaExpertBrowser():
"""Testbrowser configured for Rosetta Experts."""
- login('admin@xxxxxxxxxxxxx')
+ login("admin@xxxxxxxxxxxxx")
try:
rosetta_expert = LaunchpadObjectFactory().makePerson(
- name='rosetta-experts-member', email='re@xxxxxx')
+ name="rosetta-experts-member", email="re@xxxxxx"
+ )
except NameAlreadyTaken:
# We have already created an Rosetta expert
pass
else:
- rosetta_experts_team = removeSecurityProxy(getUtility(
- ILaunchpadCelebrities).rosetta_experts)
+ rosetta_experts_team = removeSecurityProxy(
+ getUtility(ILaunchpadCelebrities).rosetta_experts
+ )
rosetta_experts_team.addMember(
- rosetta_expert, reviewer=rosetta_experts_team,
- status=TeamMembershipStatus.ADMIN)
+ rosetta_expert,
+ reviewer=rosetta_experts_team,
+ status=TeamMembershipStatus.ADMIN,
+ )
logout()
- return setupBrowser(auth='Basic re@xxxxxx:test')
+ return setupBrowser(auth="Basic re@xxxxxx:test")
@contextmanager
@@ -845,70 +891,77 @@ def permissive_security_policy(dbuser_name=None):
def setUpGlobs(test):
- test.globs['transaction'] = transaction
- test.globs['http'] = http
- test.globs['webservice'] = LaunchpadWebServiceCaller(
- 'launchpad-library', 'salgado-change-anything')
- test.globs['public_webservice'] = LaunchpadWebServiceCaller(
- 'foobar123451432', 'salgado-read-nonprivate')
- test.globs['user_webservice'] = LaunchpadWebServiceCaller(
- 'launchpad-library', 'nopriv-read-nonprivate')
- test.globs['anon_webservice'] = LaunchpadWebServiceCaller(
- 'launchpad-library', '')
- test.globs['setupBrowser'] = setupBrowser
- test.globs['setupDTCBrowser'] = setupDTCBrowser
- test.globs['setupRosettaExpertBrowser'] = setupRosettaExpertBrowser
- test.globs['browser'] = setupBrowser()
- test.globs['anon_browser'] = setupBrowser()
- test.globs['user_browser'] = setupBrowser(
- auth="Basic no-priv@xxxxxxxxxxxxx:test")
- test.globs['admin_browser'] = setupBrowser(
- auth="Basic foo.bar@xxxxxxxxxxxxx:test")
-
- test.globs['ANONYMOUS'] = ANONYMOUS
+ test.globs["transaction"] = transaction
+ test.globs["http"] = http
+ test.globs["webservice"] = LaunchpadWebServiceCaller(
+ "launchpad-library", "salgado-change-anything"
+ )
+ test.globs["public_webservice"] = LaunchpadWebServiceCaller(
+ "foobar123451432", "salgado-read-nonprivate"
+ )
+ test.globs["user_webservice"] = LaunchpadWebServiceCaller(
+ "launchpad-library", "nopriv-read-nonprivate"
+ )
+ test.globs["anon_webservice"] = LaunchpadWebServiceCaller(
+ "launchpad-library", ""
+ )
+ test.globs["setupBrowser"] = setupBrowser
+ test.globs["setupDTCBrowser"] = setupDTCBrowser
+ test.globs["setupRosettaExpertBrowser"] = setupRosettaExpertBrowser
+ test.globs["browser"] = setupBrowser()
+ test.globs["anon_browser"] = setupBrowser()
+ test.globs["user_browser"] = setupBrowser(
+ auth="Basic no-priv@xxxxxxxxxxxxx:test"
+ )
+ test.globs["admin_browser"] = setupBrowser(
+ auth="Basic foo.bar@xxxxxxxxxxxxx:test"
+ )
+
+ test.globs["ANONYMOUS"] = ANONYMOUS
# If a unicode URL is opened by the test browswer, later navigation
# raises ValueError exceptions in /usr/lib/python2.4/Cookie.py
- test.globs['canonical_url'] = safe_canonical_url
- test.globs['factory'] = LaunchpadObjectFactory()
- test.globs['find_tag_by_id'] = find_tag_by_id
- test.globs['first_tag_by_class'] = first_tag_by_class
- test.globs['find_tags_by_class'] = find_tags_by_class
- test.globs['find_portlet'] = find_portlet
- test.globs['find_main_content'] = find_main_content
- test.globs['print_feedback_messages'] = print_feedback_messages
- test.globs['print_table'] = print_table
- test.globs['extract_link_from_tag'] = extract_link_from_tag
- test.globs['extract_text'] = extract_text
- test.globs['launchpadlib_for'] = launchpadlib_for
- test.globs['login'] = login
- test.globs['login_person'] = login_person
- test.globs['logout'] = logout
- test.globs['parse_relationship_section'] = parse_relationship_section
- test.globs['permissive_security_policy'] = permissive_security_policy
- test.globs['pretty'] = PrettyPrinter(width=1).pformat
- test.globs['print_action_links'] = print_action_links
- test.globs['print_errors'] = print_errors
- test.globs['print_location'] = print_location
- test.globs['print_location_apps'] = print_location_apps
- test.globs['print_navigation_links'] = print_navigation_links
- test.globs['print_portlet_links'] = print_portlet_links
- test.globs['print_comments'] = print_comments
- test.globs['print_submit_buttons'] = print_submit_buttons
- test.globs['print_radio_button_field'] = print_radio_button_field
- test.globs['print_batch_header'] = print_batch_header
- test.globs['print_ppa_packages'] = print_ppa_packages
- test.globs['print_self_link_of_entries'] = print_self_link_of_entries
- test.globs['print_tag_with_id'] = print_tag_with_id
- test.globs['PageTestLayer'] = PageTestLayer
- test.globs['stop'] = stop
- test.globs['six'] = six
- test.globs['backslashreplace'] = backslashreplace
+ test.globs["canonical_url"] = safe_canonical_url
+ test.globs["factory"] = LaunchpadObjectFactory()
+ test.globs["find_tag_by_id"] = find_tag_by_id
+ test.globs["first_tag_by_class"] = first_tag_by_class
+ test.globs["find_tags_by_class"] = find_tags_by_class
+ test.globs["find_portlet"] = find_portlet
+ test.globs["find_main_content"] = find_main_content
+ test.globs["print_feedback_messages"] = print_feedback_messages
+ test.globs["print_table"] = print_table
+ test.globs["extract_link_from_tag"] = extract_link_from_tag
+ test.globs["extract_text"] = extract_text
+ test.globs["launchpadlib_for"] = launchpadlib_for
+ test.globs["login"] = login
+ test.globs["login_person"] = login_person
+ test.globs["logout"] = logout
+ test.globs["parse_relationship_section"] = parse_relationship_section
+ test.globs["permissive_security_policy"] = permissive_security_policy
+ test.globs["pretty"] = PrettyPrinter(width=1).pformat
+ test.globs["print_action_links"] = print_action_links
+ test.globs["print_errors"] = print_errors
+ test.globs["print_location"] = print_location
+ test.globs["print_location_apps"] = print_location_apps
+ test.globs["print_navigation_links"] = print_navigation_links
+ test.globs["print_portlet_links"] = print_portlet_links
+ test.globs["print_comments"] = print_comments
+ test.globs["print_submit_buttons"] = print_submit_buttons
+ test.globs["print_radio_button_field"] = print_radio_button_field
+ test.globs["print_batch_header"] = print_batch_header
+ test.globs["print_ppa_packages"] = print_ppa_packages
+ test.globs["print_self_link_of_entries"] = print_self_link_of_entries
+ test.globs["print_tag_with_id"] = print_tag_with_id
+ test.globs["PageTestLayer"] = PageTestLayer
+ test.globs["stop"] = stop
+ test.globs["six"] = six
+ test.globs["backslashreplace"] = backslashreplace
# This function name doesn't follow our standard naming conventions,
# but does follow the convention of the other doctest related *Suite()
# functions.
+
def PageTestSuite(storydir, package=None, setUp=setUpGlobs, **kw):
"""Create a suite of page tests for files found in storydir.
@@ -927,13 +980,21 @@ def PageTestSuite(storydir, package=None, setUp=setUpGlobs, **kw):
filenames = {
filename
for filename in os.listdir(abs_storydir)
- if filename.lower().endswith('.rst')}
+ if filename.lower().endswith(".rst")
+ }
suite = unittest.TestSuite()
# Add tests to the suite individually.
if filenames:
paths = [os.path.join(storydir, filename) for filename in filenames]
- suite.addTest(LayeredDocFileSuite(
- paths=paths, package=package, stdout_logging=False,
- layer=PageTestLayer, setUp=setUp, **kw))
+ suite.addTest(
+ LayeredDocFileSuite(
+ paths=paths,
+ package=package,
+ stdout_logging=False,
+ layer=PageTestLayer,
+ setUp=setUp,
+ **kw,
+ )
+ )
return suite
diff --git a/lib/lp/testing/pgsql.py b/lib/lp/testing/pgsql.py
index a13f43b..9db1fd0 100644
--- a/lib/lp/testing/pgsql.py
+++ b/lib/lp/testing/pgsql.py
@@ -1,9 +1,9 @@
# Copyright 2009-2021 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
-'''
+"""
Test harness for tests needing a PostgreSQL backend.
-'''
+"""
import atexit
import os
@@ -11,13 +11,10 @@ import random
import sys
import time
+import psycopg2
from breezy.errors import LockContention
from breezy.lock import WriteLock
-import psycopg2
-from psycopg2.errors import (
- InvalidCatalogName,
- ObjectInUse,
- )
+from psycopg2.errors import InvalidCatalogName, ObjectInUse
from lp.services.config import config
from lp.services.database import activity_cols
@@ -31,8 +28,9 @@ class ConnectionWrapper:
auto_close = True
def __init__(self, real_connection):
- assert not isinstance(real_connection, ConnectionWrapper), \
- "Wrapped the wrapper!"
+ assert not isinstance(
+ real_connection, ConnectionWrapper
+ ), "Wrapped the wrapper!"
self.real_connection = real_connection
# Set to True to stop test cleanup forcing the connection closed.
PgTestSetup.connections.append(self)
@@ -92,13 +90,15 @@ class CursorWrapper:
to CursorWrapper.last_executed_sql. This is useful for tests that want to
ensure that certain SQL is generated.
"""
+
real_cursor = None
last_executed_sql = []
record_sql = False
def __init__(self, real_cursor):
- assert not isinstance(real_cursor, CursorWrapper), \
- "Wrapped the wrapper!"
+ assert not isinstance(
+ real_cursor, CursorWrapper
+ ), "Wrapped the wrapper!"
self.real_cursor = real_cursor
def execute(self, *args, **kwargs):
@@ -106,9 +106,15 @@ class CursorWrapper:
# but should be good enough. In particular, it won't notice
# data modification made by stored procedures.
mutating_commands = [
- 'INSERT', 'UPDATE', 'DELETE', 'CREATE', 'DROP', 'INTO',
- 'TRUNCATE', 'REPLACE',
- ]
+ "INSERT",
+ "UPDATE",
+ "DELETE",
+ "CREATE",
+ "DROP",
+ "INTO",
+ "TRUNCATE",
+ "REPLACE",
+ ]
for command in mutating_commands:
if command in args[0].upper():
ConnectionWrapper.dirty = True
@@ -160,9 +166,9 @@ class PgTestSetup:
# Use a dynamically generated dbname:
dynamic = object()
- template = 'template1'
+ template = "template1"
# Needs to match configs/testrunner*/*:
- dbname = 'launchpad_ftest'
+ dbname = "launchpad_ftest"
dbuser = None
host = None
port = None
@@ -179,20 +185,24 @@ class PgTestSetup:
# Class attribute. True if we should destroy the DB because changes made.
_reset_db = True
- def __init__(self, template=None, dbname=dynamic, dbuser=None,
- host=None, port=None):
- '''Construct the PgTestSetup
+ def __init__(
+ self, template=None, dbname=dynamic, dbuser=None, host=None, port=None
+ ):
+ """Construct the PgTestSetup
Note that dbuser is not used for setting up or tearing down
the database - it is only used by the connect() method
- '''
+ """
if template is not None:
self.template = template
if dbname is PgTestSetup.dynamic:
from lp.testing.layers import BaseLayer
- if os.environ.get('LP_TEST_INSTANCE'):
+
+ if os.environ.get("LP_TEST_INSTANCE"):
self.dbname = "%s_%s" % (
- self.__class__.dbname, os.environ.get('LP_TEST_INSTANCE'))
+ self.__class__.dbname,
+ os.environ.get("LP_TEST_INSTANCE"),
+ )
# Stash the name we use in the config if a writable config is
# available.
# Avoid circular imports
@@ -200,13 +210,18 @@ class PgTestSetup:
rw_main_primary: dbname=%s
rw_main_standby: dbname=%s
-""" % (self.dbname, self.dbname)
+""" % (
+ self.dbname,
+ self.dbname,
+ )
if BaseLayer.config_fixture is not None:
BaseLayer.config_fixture.add_section(section)
if BaseLayer.appserver_config_fixture is not None:
BaseLayer.appserver_config_fixture.add_section(section)
if config.instance_name in (
- BaseLayer.config_name, BaseLayer.appserver_config_name):
+ BaseLayer.config_name,
+ BaseLayer.appserver_config_name,
+ ):
config.reloadConfig()
else:
# Fallback to the class name.
@@ -224,14 +239,14 @@ rw_main_standby: dbname=%s
self.port = port
def _connectionString(self, dbname, dbuser=None):
- connection_parameters = ['dbname=%s' % dbname]
+ connection_parameters = ["dbname=%s" % dbname]
if dbuser is not None:
- connection_parameters.append('user=%s' % dbuser)
+ connection_parameters.append("user=%s" % dbuser)
if self.host is not None:
- connection_parameters.append('host=%s' % self.host)
+ connection_parameters.append("host=%s" % self.host)
if self.port is not None:
- connection_parameters.append('port=%s' % self.host)
- return ' '.join(connection_parameters)
+ connection_parameters.append("port=%s" % self.host)
+ return " ".join(connection_parameters)
def superuser_connection(self, dbname=None):
if dbname is None:
@@ -239,12 +254,12 @@ rw_main_standby: dbname=%s
return psycopg2.connect(self._connectionString(dbname))
def setUp(self):
- '''Create a fresh database (dropping the old if necessary)
+ """Create a fresh database (dropping the old if necessary)
Skips db creation if reset_db is False
- '''
+ """
# This is now done globally in test.py
- #installFakeConnect()
+ # installFakeConnect()
if (self.template, self.dbname) != PgTestSetup._last_db:
PgTestSetup._reset_db = True
if not PgTestSetup._reset_db:
@@ -261,9 +276,15 @@ rw_main_standby: dbname=%s
# try for up to 10 seconds:
debug = False
if debug:
- sys.stderr.write('%0.2f starting %s\n' % (start, pid,))
+ sys.stderr.write(
+ "%0.2f starting %s\n"
+ % (
+ start,
+ pid,
+ )
+ )
lock = None
- lockname = '/tmp/lp.createdb.%s' % (self.template,)
+ lockname = "/tmp/lp.createdb.%s" % (self.template,)
# Wait for the external lock. Most LP tests use the
# DatabaseLayer which does a double-indirect: it clones the
# launchpad_ftest_template into a per-test runner template, so
@@ -277,14 +298,20 @@ rw_main_standby: dbname=%s
while time.time() - start < 30.0:
try:
if debug:
- sys.stderr.write('taking %s\n' % (pid,))
+ sys.stderr.write("taking %s\n" % (pid,))
lock = WriteLock(lockname)
if debug:
- sys.stderr.write('%0.2f taken %s\n' % (time.time(), pid,))
+ sys.stderr.write(
+ "%0.2f taken %s\n"
+ % (
+ time.time(),
+ pid,
+ )
+ )
break
except LockContention:
if debug:
- sys.stderr.write('blocked %s\n' % (pid,))
+ sys.stderr.write("blocked %s\n" % (pid,))
time.sleep(random.random())
if lock is None:
raise LockContention(lockname)
@@ -297,7 +324,8 @@ rw_main_standby: dbname=%s
if debug:
sys.stderr.write(
"%0.2f connecting %s %s\n"
- % (time.time(), pid, self.template))
+ % (time.time(), pid, self.template)
+ )
con = self.superuser_connection(self.template)
try:
con.set_isolation_level(0)
@@ -307,44 +335,48 @@ rw_main_standby: dbname=%s
try:
cur.execute(
"CREATE DATABASE %s TEMPLATE=%s "
- "ENCODING='UNICODE'" % (
- self.dbname, self.template))
+ "ENCODING='UNICODE'"
+ % (self.dbname, self.template)
+ )
# Try to ensure our cleanup gets invoked, even in