Use a common requirements file

We can use newer setuptools and pbr to use environment markers in our
requirements files which allows us to select deps if the environment
matches. With this we restrict the email dep to python < 3.0 which is
the only dep we have that doesn't work across python 2 and 3.

Note that this also updates the pbr machinery to pull in this new
feature support. Part of this update requires updating hacking to avoid
conflicting pbr requirements. This in turn has created some churn in the
format of the code but should largely be a noop.

Change-Id: I0be5dd8a6b33a51329077b5a5f4c7f5576829956
This commit is contained in:
Clark Boylan 2016-07-07 17:06:21 -07:00
parent 8ea0c1e4eb
commit 1a0ce47f8f
15 changed files with 68 additions and 91 deletions

View File

@ -1,29 +0,0 @@
pbr>=0.6,!=0.7,<1.0
jsonschema>=2.0.0,<3.0.0
argparse
alembic>=0.4.1
Babel>=1.3
iso8601>=0.1.9
oauthlib>=0.6
oslo.config>=1.11.0
oslo.context>=0.2.0
oslo.utils>=1.4.0
pecan>=0.4.5
oslo.db>=1.8.0
oslo.log>=1.0.0
pika>=0.9.14
python-openid
PyYAML>=3.1.0
requests>=1.1
six>=1.7.0
SQLAlchemy>=0.9.7,<=0.9.99
WSME>=0.6
sqlalchemy-migrate>=0.9.1,!=0.9.2
SQLAlchemy-FullText-Search
eventlet>=0.13.0
stevedore>=1.3.0
tzlocal>=1.1.2
Jinja2>=2.7.3
PyMySQL>=0.6.2,!=0.6.4
apscheduler>=3.0.1
python_dateutil>=2.4.0

View File

@ -1,4 +1,4 @@
pbr>=0.6,!=0.7,<1.0 pbr>=1.6
jsonschema>=2.0.0,<3.0.0 jsonschema>=2.0.0,<3.0.0
alembic>=0.4.1 alembic>=0.4.1
Babel>=1.3 Babel>=1.3
@ -22,7 +22,7 @@ SQLAlchemy-FullText-Search>=0.2.3
eventlet>=0.13.0 eventlet>=0.13.0
stevedore>=1.3.0 stevedore>=1.3.0
tzlocal>=1.1.2 tzlocal>=1.1.2
email>=4.0.2 email>=4.0.2;python_version<'3.0'
Jinja2>=2.7.3 Jinja2>=2.7.3
PyMySQL>=0.6.2,!=0.6.4 PyMySQL>=0.6.2,!=0.6.4
apscheduler>=3.0.1,<3.1.0 apscheduler>=3.0.1,<3.1.0

View File

@ -1,4 +1,3 @@
#!/usr/bin/env python
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. # Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
@ -14,9 +13,17 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT # This file was pulled from the openstack global requirements repo.
import setuptools import setuptools
# In python < 2.7.4, a lazy loading of package `pbr` will break
# setuptools if some other modules registered functions in `atexit`.
# solution from: http://bugs.python.org/issue15881#msg170215
try:
import multiprocessing # noqa
except ImportError:
pass
setuptools.setup( setuptools.setup(
setup_requires=['pbr'], setup_requires=['pbr>=1.8'],
pbr=True) pbr=True)

View File

@ -138,7 +138,7 @@ class OpenIdClient(object):
for token in verify_data_tokens) for token in verify_data_tokens)
if (verify_response.status_code / 100 != 2 if (verify_response.status_code / 100 != 2
or verify_dict['is_valid'] != 'true'): or verify_dict['is_valid'] != 'true'):
raise AccessDenied(redirect_uri=redirect_uri, raise AccessDenied(redirect_uri=redirect_uri,
message=e_msg.OPEN_ID_TOKEN_INVALID) message=e_msg.OPEN_ID_TOKEN_INVALID)

View File

@ -200,7 +200,7 @@ class StoriesController(rest.RestController):
if not stories_api.story_can_create_story(story.story_type_id): if not stories_api.story_can_create_story(story.story_type_id):
abort(400, _("Can't create story of this type.")) abort(400, _("Can't create story of this type."))
if not "tags" in story_dict or not story_dict["tags"]: if "tags" not in story_dict or not story_dict["tags"]:
story_dict["tags"] = [] story_dict["tags"] = []
# We can't set due dates when creating stories at the moment. # We can't set due dates when creating stories at the moment.

View File

@ -70,7 +70,7 @@ def task_details_changed(event):
def task_deleted(event): def task_deleted(event):
#NOTE: There is nothing to resolve, as the task title is already stored in # NOTE: There is nothing to resolve, as the task title is already stored in
# the info. There is no way to store an id because the task is hard deleted # the info. There is no way to store an id because the task is hard deleted
# at the moment we would query it. # at the moment we would query it.
return event return event

View File

@ -14,7 +14,7 @@
# limitations under the License. # limitations under the License.
class MasterBranchHelper: class MasterBranchHelper(object):
name = "master" name = "master"
project_id = None project_id = None
expired = False expired = False

View File

@ -216,8 +216,8 @@ def get_card(board, item_type, item_id, archived=False):
for lane in board.lanes: for lane in board.lanes:
for card in lane.worklist.items: for card in lane.worklist.items:
if (card.item_type == item_type and if (card.item_type == item_type and
card.item_id == item_id and card.item_id == item_id and
card.archived == archived): card.archived == archived):
return card return card

View File

@ -63,7 +63,7 @@ def table_args():
MYSQL_MEDIUM_TEXT = UnicodeText().with_variant(MEDIUMTEXT(), 'mysql') MYSQL_MEDIUM_TEXT = UnicodeText().with_variant(MEDIUMTEXT(), 'mysql')
class CommonLength: class CommonLength(object):
top_large_length = 255 top_large_length = 255
top_middle_length = 100 top_middle_length = 100
top_short_length = 50 top_short_length = 50

View File

@ -33,19 +33,19 @@ class get_smtp_client(object):
# SSL or not SSL? # SSL or not SSL?
if not email_config.smtp_ssl_certfile \ if not email_config.smtp_ssl_certfile \
or not email_config.smtp_ssl_keyfile: or not email_config.smtp_ssl_keyfile:
self.s = smtplib.SMTP(host=email_config.smtp_host, self.s = smtplib.SMTP(
port=email_config.smtp_port, host=email_config.smtp_host,
local_hostname= port=email_config.smtp_port,
email_config.smtp_local_hostname, local_hostname=email_config.smtp_local_hostname,
timeout=email_config.smtp_timeout) timeout=email_config.smtp_timeout)
else: else:
self.s = smtplib.SMTP_SSL(host=email_config.smtp_host, self.s = smtplib.SMTP_SSL(
port=email_config.smtp_port, host=email_config.smtp_host,
keyfile=email_config.smtp_ssl_keyfile, port=email_config.smtp_port,
certfile=email_config.smtp_ssl_certfile, keyfile=email_config.smtp_ssl_keyfile,
local_hostname= certfile=email_config.smtp_ssl_certfile,
email_config.smtp_local_hostname, local_hostname=email_config.smtp_local_hostname,
timeout=email_config.smtp_timeout) timeout=email_config.smtp_timeout)
# Do we need to log in? # Do we need to log in?
if email_config.smtp_user and email_config.smtp_password: if email_config.smtp_user and email_config.smtp_password:

View File

@ -70,7 +70,7 @@ def terminate(sig, frame):
signal.default_int_handler() signal.default_int_handler()
class DaemonManager(): class DaemonManager(object):
"""A Daemon manager to handle multiple subprocesses. """A Daemon manager to handle multiple subprocesses.
""" """
def __init__(self, child_process_count, daemon_method): def __init__(self, child_process_count, daemon_method):
@ -134,7 +134,7 @@ class DaemonManager():
self._procs.append(process) self._procs.append(process)
class PerpetualTimer(): class PerpetualTimer(object):
"""A timer wrapper class that repeats itself. """A timer wrapper class that repeats itself.
""" """

View File

@ -391,11 +391,11 @@ class TestOAuthAuthorizeReturn(BaseOAuthTest):
with base.HybridSessionManager(): with base.HybridSessionManager():
token = auth_api.authorization_code_get(parameters['code']) token = auth_api.authorization_code_get(parameters['code'])
redirect_uri = self.valid_params['sb_redirect_uri']
# Validate the redirect response # Validate the redirect response
self.assertValidRedirect(response=response, self.assertValidRedirect(response=response,
expected_status_code=302, expected_status_code=302,
redirect_uri= redirect_uri=redirect_uri,
self.valid_params['sb_redirect_uri'],
state=token.state, state=token.state,
code=token.code) code=token.code)
@ -413,11 +413,11 @@ class TestOAuthAuthorizeReturn(BaseOAuthTest):
state=random_state, state=random_state,
**self.valid_params) **self.valid_params)
redirect_uri = self.valid_params['sb_redirect_uri']
# Validate the redirect response # Validate the redirect response
self.assertValidRedirect(response=response, self.assertValidRedirect(response=response,
expected_status_code=302, expected_status_code=302,
redirect_uri= redirect_uri=redirect_uri,
self.valid_params['sb_redirect_uri'],
error='access_denied', error='access_denied',
error_description=e_msg.OPEN_ID_TOKEN_INVALID) error_description=e_msg.OPEN_ID_TOKEN_INVALID)
@ -438,11 +438,11 @@ class TestOAuthAuthorizeReturn(BaseOAuthTest):
state=random_state, state=random_state,
**invalid_params) **invalid_params)
redirect_uri = self.valid_params['sb_redirect_uri']
# Validate the redirect response # Validate the redirect response
self.assertValidRedirect(response=response, self.assertValidRedirect(response=response,
expected_status_code=302, expected_status_code=302,
redirect_uri= redirect_uri=redirect_uri,
self.valid_params['sb_redirect_uri'],
error='invalid_request', error='invalid_request',
error_description=e_msg.INVALID_NO_NAME) error_description=e_msg.INVALID_NO_NAME)
@ -463,11 +463,11 @@ class TestOAuthAuthorizeReturn(BaseOAuthTest):
state=random_state, state=random_state,
**invalid_params) **invalid_params)
redirect_uri = self.valid_params['sb_redirect_uri']
# Validate the redirect response # Validate the redirect response
self.assertValidRedirect(response=response, self.assertValidRedirect(response=response,
expected_status_code=302, expected_status_code=302,
redirect_uri= redirect_uri=redirect_uri,
self.valid_params['sb_redirect_uri'],
error='invalid_request', error='invalid_request',
error_description=e_msg.INVALID_NO_EMAIL) error_description=e_msg.INVALID_NO_EMAIL)
@ -522,14 +522,14 @@ class TestOAuthAccessToken(BaseOAuthTest):
'code': 'test_valid_code' 'code': 'test_valid_code'
}) })
content_type = 'application/x-www-form-urlencoded'
# POST with content: application/x-www-form-urlencoded # POST with content: application/x-www-form-urlencoded
response = self.app.post('/v1/openid/token', response = self.app.post('/v1/openid/token',
params={ params={
'code': authorization_code.code, 'code': authorization_code.code,
'grant_type': 'authorization_code' 'grant_type': 'authorization_code'
}, },
content_type= content_type=content_type,
'application/x-www-form-urlencoded',
expect_errors=True) expect_errors=True)
# Assert that this is a successful response # Assert that this is a successful response
@ -602,13 +602,13 @@ class TestOAuthAccessToken(BaseOAuthTest):
'expires_in': 300 'expires_in': 300
}) })
content_type = 'application/x-www-form-urlencoded'
response = self.app.post('/v1/openid/token', response = self.app.post('/v1/openid/token',
params={ params={
'code': authorization_code.code, 'code': authorization_code.code,
'grant_type': 'authorization_code' 'grant_type': 'authorization_code'
}, },
content_type= content_type=content_type,
'application/x-www-form-urlencoded',
expect_errors=True) expect_errors=True)
# Assert that this is a valid call. # Assert that this is a valid call.
@ -649,14 +649,14 @@ class TestOAuthAccessToken(BaseOAuthTest):
'created_at': expired 'created_at': expired
}) })
content_type = 'application/x-www-form-urlencoded'
# POST with content: application/x-www-form-urlencoded # POST with content: application/x-www-form-urlencoded
response = self.app.post('/v1/openid/token', response = self.app.post('/v1/openid/token',
params={ params={
'code': authorization_code.code, 'code': authorization_code.code,
'grant_type': 'authorization_code' 'grant_type': 'authorization_code'
}, },
content_type= content_type=content_type,
'application/x-www-form-urlencoded',
expect_errors=True) expect_errors=True)
# Assert that this is a valid call. # Assert that this is a valid call.
@ -682,14 +682,14 @@ class TestOAuthAccessToken(BaseOAuthTest):
'expires_in': 300 'expires_in': 300
}) })
content_type = 'application/x-www-form-urlencoded'
# POST with content: application/x-www-form-urlencoded # POST with content: application/x-www-form-urlencoded
response = self.app.post('/v1/openid/token', response = self.app.post('/v1/openid/token',
params={ params={
'code': authorization_code.code, 'code': authorization_code.code,
'grant_type': 'invalid_grant_type' 'grant_type': 'invalid_grant_type'
}, },
content_type= content_type=content_type,
'application/x-www-form-urlencoded',
expect_errors=True) expect_errors=True)
# Assert that this is a successful response # Assert that this is a successful response
@ -704,14 +704,14 @@ class TestOAuthAccessToken(BaseOAuthTest):
appropriate error response. appropriate error response.
""" """
content_type = 'application/x-www-form-urlencoded'
# POST with content: application/x-www-form-urlencoded # POST with content: application/x-www-form-urlencoded
response = self.app.post('/v1/openid/token', response = self.app.post('/v1/openid/token',
params={ params={
'code': 'invalid_access_token', 'code': 'invalid_access_token',
'grant_type': 'invalid_grant_type' 'grant_type': 'invalid_grant_type'
}, },
content_type= content_type=content_type,
'application/x-www-form-urlencoded',
expect_errors=True) expect_errors=True)
# Assert that this is a successful response # Assert that this is a successful response
@ -734,14 +734,14 @@ class TestOAuthAccessToken(BaseOAuthTest):
'code': 'test_valid_code' 'code': 'test_valid_code'
}) })
content_type = 'application/x-www-form-urlencoded'
# Generate an auth and a refresh token. # Generate an auth and a refresh token.
resp_1 = self.app.post('/v1/openid/token', resp_1 = self.app.post('/v1/openid/token',
params={ params={
'code': authorization_code.code, 'code': authorization_code.code,
'grant_type': 'authorization_code' 'grant_type': 'authorization_code'
}, },
content_type= content_type=content_type,
'application/x-www-form-urlencoded',
expect_errors=True) expect_errors=True)
# Assert that this is a successful response # Assert that this is a successful response
@ -762,15 +762,14 @@ class TestOAuthAccessToken(BaseOAuthTest):
self.assertIsNotNone(refresh_token) self.assertIsNotNone(refresh_token)
content_type = 'application/x-www-form-urlencoded'
# Issue a refresh token request. # Issue a refresh token request.
resp_2 = self.app.post('/v1/openid/token', resp_2 = self.app.post('/v1/openid/token',
params={ params={
'refresh_token': t1['refresh_token'], 'refresh_token': t1['refresh_token'],
'grant_type': 'refresh_token' 'grant_type': 'refresh_token'
}, },
content_type= content_type=content_type,
'application/x-www-form-urlencoded',
expect_errors=True) expect_errors=True)
# Assert that the response is good. # Assert that the response is good.
@ -832,14 +831,14 @@ class TestOAuthAccessToken(BaseOAuthTest):
into a valid access token. into a valid access token.
""" """
content_type = 'application/x-www-form-urlencoded'
# Generate an auth and a refresh token. # Generate an auth and a refresh token.
resp_1 = self.app.post('/v1/openid/token', resp_1 = self.app.post('/v1/openid/token',
params={ params={
'refresh_token': 'invalid_refresh_token', 'refresh_token': 'invalid_refresh_token',
'grant_type': 'refresh_token' 'grant_type': 'refresh_token'
}, },
content_type= content_type=content_type,
'application/x-www-form-urlencoded',
expect_errors=True) expect_errors=True)
# Assert that this is a correct response # Assert that this is a correct response

View File

@ -12,7 +12,8 @@
# implied. See the License for the specific language governing permissions and # implied. See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from mock import patch, Mock from mock import Mock
from mock import patch
from storyboard.api.v1.v1_controller import V1Controller from storyboard.api.v1.v1_controller import V1Controller
from storyboard.api.v1.wmodels import Task as TaskWmodel from storyboard.api.v1.wmodels import Task as TaskWmodel
import storyboard.common.hook_priorities as priority import storyboard.common.hook_priorities as priority

View File

@ -1,4 +1,4 @@
hacking>=0.5.6,<0.8 hacking>=0.11.0,<0.12
coverage>=3.6 coverage>=3.6
discover discover

17
tox.ini
View File

@ -25,21 +25,20 @@ commands =
rm -rf doc/source/apidoc doc/source/api rm -rf doc/source/apidoc doc/source/api
python setup.py build_sphinx python setup.py build_sphinx
[testenv:py34]
deps = -r{toxinidir}/requirements-py3.txt
-r{toxinidir}/test-requirements.txt
[testenv:py35]
deps = -r{toxinidir}/requirements-py3.txt
-r{toxinidir}/test-requirements.txt
[testenv:cover] [testenv:cover]
commands = python setup.py testr --coverage --testr-args='{posargs}' commands = python setup.py testr --coverage --testr-args='{posargs}'
[flake8] [flake8]
# E125 and E128 are ignored on purpose, they are invalid pep8 # E125 and E128 are ignored on purpose, they are invalid pep8
# H803 is ignored on purpose - gating on periods in commit messages # H803 is ignored on purpose - gating on periods in commit messages
ignore = E125,E128,H803 # The following rules should either be addressed or determined to be
# skippable long term.
# H405 is ignored to make switch to newer hacking easier
# H234 is ignored to make switch to newer hacking easier
# H233 is ignored to make switch to newer hacking easier
# E265 is ignored to make switch to newer hacking easier
# H236 is ignored to make switch to newer hacking easier
ignore = E125,E128,H803,H405,H234,H233,E265,H236
builtins = _ builtins = _
show-source = True show-source = True
exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build