diff options
25 files changed, 253 insertions, 104 deletions
diff --git a/.zuul.yaml b/.zuul.yaml new file mode 100644 index 0000000..67a39c4 --- /dev/null +++ b/.zuul.yaml @@ -0,0 +1,7 @@ +- project: + check: + jobs: + - openstack-tox-lower-constraints + gate: + jobs: + - openstack-tox-lower-constraints @@ -38,7 +38,7 @@ with keystone authentication: .. code:: python >>> from keystoneclient.auth import identity - >>> from keystoneclient import session + >>> from keystoneauth1 import session >>> from barbicanclient import client >>> # We'll use Keystone API v3 for authentication diff --git a/barbicanclient/__init__.py b/barbicanclient/__init__.py index 58f7429..51d78ec 100644 --- a/barbicanclient/__init__.py +++ b/barbicanclient/__init__.py @@ -15,8 +15,54 @@ """Barbican Client Library Binding""" +import importlib +import sys +import warnings + import pbr.version +from barbicanclient.v1 import acls +from barbicanclient.v1 import cas +from barbicanclient.v1 import containers +from barbicanclient.v1 import orders +from barbicanclient.v1 import secrets + version_info = pbr.version.VersionInfo("python-barbicanclient") __version__ = version_info.version_string() + +__all__ = ( + 'acls', + 'cas', + 'containers', + 'orders', + 'secrets', +) + + +class _LazyImporter(object): + def __init__(self, module): + self._module = module + + def __getattr__(self, name): + # This is only called until the import has been done. + lazy_submodules = [ + 'acls', + 'cas', + 'containers', + 'orders', + 'secrets', + ] + if name in lazy_submodules: + warnings.warn("The %s module is moved to barbicanclient/v1 " + "directory, direct import of barbicanclient.%s " + "will be deprecated. Please import " + "barbicanclient.v1.%s instead." + % (name, name, name)) + return importlib.import_module('barbicanclient.v1.%s' % name) + + # Return module attributes like __all__ etc. + return getattr(self._module, name) + + +sys.modules[__name__] = _LazyImporter(sys.modules[__name__]) diff --git a/barbicanclient/barbican.py b/barbicanclient/barbican.py index e26eb34..a462f1d 100644 --- a/barbicanclient/barbican.py +++ b/barbicanclient/barbican.py @@ -46,6 +46,13 @@ _IDENTITY_API_VERSION_3 = ['3'] class Barbican(app.App): """Barbican command line interface.""" + # verbose logging levels + WARNING_LEVEL = 0 + INFO_LEVEL = 1 + DEBUG_LEVEL = 2 + CONSOLE_MESSAGE_FORMAT = '%(message)s' + DEBUG_MESSAGE_FORMAT = '%(levelname)s: %(name)s %(message)s' + def __init__(self, **kwargs): self.client = None @@ -328,6 +335,9 @@ class Barbican(app.App): """ self.client_manager = namedtuple('ClientManager', 'key_manager') if cmd.auth_required: + # NOTE(liujiong): cliff sets log level to DEBUG in run function, + # need to overwrite this configuration to depress DEBUG messages. + self.configure_logging() self.client_manager.key_manager = self.create_client(self.options) def run(self, argv): @@ -337,6 +347,26 @@ class Barbican(app.App): return 1 return super(Barbican, self).run(argv) + def configure_logging(self): + """Create logging handlers for any log output.""" + root_logger = logging.getLogger('') + # Set log level to INFO + root_logger.setLevel(logging.INFO) + + # Send higher-level messages to the console via stderr + console = logging.StreamHandler(self.stderr) + console_level = {self.WARNING_LEVEL: logging.WARNING, + self.INFO_LEVEL: logging.INFO, + self.DEBUG_LEVEL: logging.DEBUG, + }.get(self.options.verbose_level, logging.INFO) + if logging.DEBUG == console_level: + formatter = logging.Formatter(self.DEBUG_MESSAGE_FORMAT) + else: + formatter = logging.Formatter(self.CONSOLE_MESSAGE_FORMAT) + console.setFormatter(formatter) + root_logger.addHandler(console) + return + def main(argv=sys.argv[1:]): logging.basicConfig() diff --git a/barbicanclient/client.py b/barbicanclient/client.py index c715315..f1910e7 100644 --- a/barbicanclient/client.py +++ b/barbicanclient/client.py @@ -13,8 +13,11 @@ # See the License for the specific language governing permissions and # limitations under the License. +import importlib import logging import os +import sys +import warnings from keystoneauth1 import adapter from keystoneauth1 import session as ks_session @@ -120,7 +123,7 @@ def Client(version=None, session=None, *args, **kwargs): """Barbican client used to interact with barbican service. :param version: The API version to use. - :param session: An instance of keystoneclient.session.Session that + :param session: An instance of keystoneauth1.session.Session that can be either authenticated, or not authenticated. When using a non-authenticated Session, you must provide some additional parameters. When no session is provided it will default to a @@ -191,3 +194,32 @@ def env(*vars, **kwargs): if value: return value return kwargs.get('default', '') + + +class _LazyImporter(object): + def __init__(self, module): + self._module = module + + def __getattr__(self, name): + # This is only called until the import has been done. + lazy_submodules = [ + 'acls', + 'cas', + 'containers', + 'orders', + 'secrets', + ] + if name in lazy_submodules: + warnings.warn("The %s module is moved to barbicanclient/v1 " + "directory, direct import of " + "barbicanclient.client.%s " + "will be deprecated. Please import " + "barbicanclient.v1.%s instead." + % (name, name, name)) + return importlib.import_module('barbicanclient.v1.%s' % name) + + # Return module attributes like __all__ etc. + return getattr(self._module, name) + + +sys.modules[__name__] = _LazyImporter(sys.modules[__name__]) diff --git a/barbicanclient/osc_plugin.py b/barbicanclient/osc_plugin.py index 1d0e0e5..d4fcea7 100644 --- a/barbicanclient/osc_plugin.py +++ b/barbicanclient/osc_plugin.py @@ -26,7 +26,8 @@ API_VERSIONS = { def make_client(instance): """Returns a Barbican service client.""" return client.Client(session=instance.session, - region_name=instance._region_name) + region_name=instance._region_name, + interface=instance.interface) def build_option_parser(parser): diff --git a/barbicanclient/v1/client.py b/barbicanclient/v1/client.py index 2679f7d..37ffc56 100644 --- a/barbicanclient/v1/client.py +++ b/barbicanclient/v1/client.py @@ -30,7 +30,7 @@ class Client(object): def __init__(self, session=None, *args, **kwargs): """Barbican client object used to interact with barbican service. - :param session: An instance of keystoneclient.session.Session that + :param session: An instance of keystoneauth1.session.Session that can be either authenticated, or not authenticated. When using a non-authenticated Session, you must provide some additional parameters. When no session is provided it will default to a diff --git a/doc/requirements.txt b/doc/requirements.txt new file mode 100644 index 0000000..827758f --- /dev/null +++ b/doc/requirements.txt @@ -0,0 +1,5 @@ +# The order of packages is significant, because pip processes them in the order +# of appearance. Changing the order has an impact on the overall integration +# process, which may cause wedges in the gate later. +sphinx!=1.6.6,!=1.6.7,>=1.6.2 # BSD +openstackdocstheme>=1.18.1 # Apache-2.0 diff --git a/doc/source/cli/usage.rst b/doc/source/cli/usage.rst index c95cdb9..418f78b 100644 --- a/doc/source/cli/usage.rst +++ b/doc/source/cli/usage.rst @@ -115,7 +115,7 @@ Example: barbican = client.Client(...) - my_order = barbican.orders.key_order() + my_order = barbican.orders.create_key() my_order.algorithm = 'AES' my_order.mode = 'CBC' my_order.bit_length = 256 diff --git a/etc/functional_tests.conf b/etc/functional_tests.conf index 9bff4ad..4ba58ee 100644 --- a/etc/functional_tests.conf +++ b/etc/functional_tests.conf @@ -3,7 +3,7 @@ [keymanager] #Replace values that represent barbican server and user information -url=http://localhost:9311 +url=http://localhost/key-manager username=barbican password=secretservice project_name=service diff --git a/functionaltests/cli/v1/behaviors/acl_behaviors.py b/functionaltests/cli/v1/behaviors/acl_behaviors.py index d3d7276..443ace7 100644 --- a/functionaltests/cli/v1/behaviors/acl_behaviors.py +++ b/functionaltests/cli/v1/behaviors/acl_behaviors.py @@ -57,8 +57,8 @@ class ACLBehaviors(base_behaviors.BaseBehaviors): def acl_delete(self, entity_ref): """Delete a secret or container acl - :param entity_ref Reference to secret or container entity - :return If error returns stderr string otherwise returns None. + :param entity_ref: Reference to secret or container entity + :return: If error returns stderr string otherwise returns None. """ argv = ['acl', 'delete'] self.add_auth_and_endpoint(argv) @@ -74,8 +74,8 @@ class ACLBehaviors(base_behaviors.BaseBehaviors): def acl_get(self, entity_ref): """Get a 'read' ACL setting for a secret or a container. - :param entity_ref Reference to secret or container entity - :return dict of 'read' operation ACL settings if found otherwise empty + :param entity_ref: Reference to secret or container entity + :return: dict of 'read' operation ACL settings if found otherwise empty dict in case of error. """ argv = ['acl', 'get'] @@ -95,14 +95,14 @@ class ACLBehaviors(base_behaviors.BaseBehaviors): operation_type='read'): """Submits a secret or container ACL - :param entity_ref Reference to secret or container entity - :param users List of users for ACL + :param entity_ref: Reference to secret or container entity + :param users: List of users for ACL :param project_access: Flag to pass for project access behavior :param use_short_arg: Flag to indicate if use short arguments in cli. Default is False :param operation_type: ACL operation type. Default is 'read' as Barbican currently supports only that type of operation. - :return dict of 'read' operation ACL settings if found otherwise empty + :return: dict of 'read' operation ACL settings if found otherwise empty dict in case of error. """ argv = ['acl', 'submit'] @@ -128,14 +128,14 @@ class ACLBehaviors(base_behaviors.BaseBehaviors): operation_type='read'): """Add to a secret or container ACL - :param entity_ref Reference to secret or container entity - :param users List of users to be added in ACL + :param entity_ref: Reference to secret or container entity + :param users: List of users to be added in ACL :param project_access: Flag to pass for project access behavior :param use_short_arg: Flag to indicate if use short arguments in cli. Default is False :param operation_type: ACL operation type. Default is 'read' as Barbican currently supports only that type of operation. - :return dict of 'read' operation ACL settings if found otherwise empty + :return: dict of 'read' operation ACL settings if found otherwise empty dict in case of error. """ argv = ['acl', 'user', 'add'] @@ -162,14 +162,14 @@ class ACLBehaviors(base_behaviors.BaseBehaviors): operation_type='read'): """Remove users from a secret or container ACL - :param entity_ref Reference to secret or container entity - :param users List of users to be removed from ACL + :param entity_ref: Reference to secret or container entity + :param users: List of users to be removed from ACL :param project_access: Flag to pass for project access behavior :param use_short_arg: Flag to indicate if use short arguments in cli. Default is False :param operation_type: ACL operation type. Default is 'read' as Barbican currently supports only that type of operation. - :return dict of 'read' operation ACL settings if found otherwise empty + :return: dict of 'read' operation ACL settings if found otherwise empty dict in case of error. """ argv = ['acl', 'user', 'remove'] diff --git a/functionaltests/cli/v1/behaviors/container_behaviors.py b/functionaltests/cli/v1/behaviors/container_behaviors.py index d487eda..1db4a1f 100644 --- a/functionaltests/cli/v1/behaviors/container_behaviors.py +++ b/functionaltests/cli/v1/behaviors/container_behaviors.py @@ -62,7 +62,7 @@ class ContainerBehaviors(base_behaviors.BaseBehaviors): """Get a container :param: the href to a container - :return dict of container values, or an empty dict if the container + :return: dict of container values, or an empty dict if the container is not found. """ argv = ['secret', 'container', 'get'] diff --git a/functionaltests/cli/v1/behaviors/secret_behaviors.py b/functionaltests/cli/v1/behaviors/secret_behaviors.py index 1e970f1..5ea5e9a 100644 --- a/functionaltests/cli/v1/behaviors/secret_behaviors.py +++ b/functionaltests/cli/v1/behaviors/secret_behaviors.py @@ -83,7 +83,7 @@ class SecretBehaviors(base_behaviors.BaseBehaviors): """Get a secret :param: the href to a secret - :return dict of secret values, or an empty dict if the secret + :return: dict of secret values, or an empty dict if the secret is not found. """ argv = ['secret', 'get'] @@ -104,7 +104,7 @@ class SecretBehaviors(base_behaviors.BaseBehaviors): :param: the href to a secret :param raw if True then add "-f value" to get raw payload (ie not within a PrettyTable). If False then omit -f. - :return string representing the secret payload. + :return: string representing the secret payload. """ argv = ['secret', 'get'] self.add_auth_and_endpoint(argv) diff --git a/functionaltests/client/v1/functional/test_acl.py b/functionaltests/client/v1/functional/test_acl.py index 61de646..d9f8fc8 100644 --- a/functionaltests/client/v1/functional/test_acl.py +++ b/functionaltests/client/v1/functional/test_acl.py @@ -24,7 +24,7 @@ from barbicanclient import exceptions create_secret_defaults_data = { "name": "AES key", - "expiration": "2018-02-28T19:14:44.180394", + "expiration": "2020-02-28T19:14:44.180394", "algorithm": "aes", "bit_length": 256, "mode": "cbc", diff --git a/functionaltests/client/v1/functional/test_containers.py b/functionaltests/client/v1/functional/test_containers.py index e632b23..64b9cdc 100644 --- a/functionaltests/client/v1/functional/test_containers.py +++ b/functionaltests/client/v1/functional/test_containers.py @@ -22,7 +22,7 @@ from barbicanclient import exceptions create_secret_defaults_data = { "name": "AES key", - "expiration": "2018-02-28T19:14:44.180394", + "expiration": "2020-02-28T19:14:44.180394", "algorithm": "aes", "bit_length": 256, "mode": "cbc", diff --git a/functionaltests/client/v1/functional/test_secrets.py b/functionaltests/client/v1/functional/test_secrets.py index 7832154..8d9fcf0 100644 --- a/functionaltests/client/v1/functional/test_secrets.py +++ b/functionaltests/client/v1/functional/test_secrets.py @@ -28,7 +28,7 @@ from testtools import testcase secret_create_defaults_data = { "name": "AES key", - "expiration": "2018-02-28T19:14:44.180394", + "expiration": "2020-02-28T19:14:44.180394", "algorithm": "aes", "bit_length": 256, "mode": "cbc", diff --git a/functionaltests/client/v1/smoke/test_containers.py b/functionaltests/client/v1/smoke/test_containers.py index 2c67bca..584df47 100644 --- a/functionaltests/client/v1/smoke/test_containers.py +++ b/functionaltests/client/v1/smoke/test_containers.py @@ -20,7 +20,7 @@ from testtools import testcase create_secret_defaults_data = { "name": "AES key", - "expiration": "2018-02-28T19:14:44.180394", + "expiration": "2020-02-28T19:14:44.180394", "algorithm": "aes", "bit_length": 256, "mode": "cbc", diff --git a/functionaltests/client/v1/smoke/test_secrets.py b/functionaltests/client/v1/smoke/test_secrets.py index 5482582..3f11740 100644 --- a/functionaltests/client/v1/smoke/test_secrets.py +++ b/functionaltests/client/v1/smoke/test_secrets.py @@ -21,7 +21,7 @@ from testtools import testcase secret_create_defaults_data = { "name": "AES key", - "expiration": "2018-02-28T19:14:44.180394", + "expiration": "2020-02-28T19:14:44.180394", "algorithm": "aes", "bit_length": 256, "mode": "cbc", diff --git a/functionaltests/common/config.py b/functionaltests/common/config.py index 4cee242..dbe4f29 100644 --- a/functionaltests/common/config.py +++ b/functionaltests/common/config.py @@ -42,7 +42,7 @@ def setup_config(config_file=''): keymanager_group = cfg.OptGroup(name='keymanager') keymanager_options = [ - cfg.StrOpt('url', default='http://localhost:9311'), + cfg.StrOpt('url', default='http://localhost/key-manager'), cfg.StrOpt('username', default='admin'), cfg.StrOpt('password', default='secretadmin'), cfg.StrOpt('project_name', default='admin'), diff --git a/functionaltests/utils.py b/functionaltests/utils.py index 3e1c094..367dee0 100644 --- a/functionaltests/utils.py +++ b/functionaltests/utils.py @@ -126,7 +126,7 @@ def create_timestamp_w_tz_and_offset(timezone=None, days=0, hours=0, minutes=0, :param hours: The offset in hours :param minutes: The offset in minutes - :return a timestamp + :return: a timestamp """ if timezone is None: timezone = time.strftime("%z") diff --git a/lower-constraints.txt b/lower-constraints.txt new file mode 100644 index 0000000..7876b87 --- /dev/null +++ b/lower-constraints.txt @@ -0,0 +1,73 @@ +appdirs==1.3.0 +asn1crypto==0.23.0 +Babel==2.3.4 +cffi==1.7.0 +cliff==2.8.0 +cmd2==0.8.0 +coverage==4.0 +cryptography==2.1 +debtcollector==1.2.0 +decorator==3.4.0 +deprecation==1.0 +dogpile.cache==0.6.2 +extras==1.0.0 +fixtures==3.0.0 +flake8==2.5.5 +hacking==0.12.0 +idna==2.6 +iso8601==0.1.11 +jmespath==0.9.0 +jsonpatch==1.16 +jsonpointer==1.13 +jsonschema==2.6.0 +keystoneauth1==3.4.0 +linecache2==1.0.0 +mccabe==0.2.1 +mock==2.0.0 +monotonic==0.6 +mox3==0.20.0 +msgpack-python==0.4.0 +munch==2.1.0 +netaddr==0.7.18 +netifaces==0.10.4 +nose==1.3.7 +openstacksdk==0.11.2 +os-client-config==1.28.0 +os-service-types==1.2.0 +osc-lib==1.8.0 +oslo.config==5.2.0 +oslo.i18n==3.15.3 +oslo.serialization==2.18.0 +oslo.utils==3.33.0 +oslotest==3.2.0 +pbr==2.0.0 +pep8==1.5.7 +positional==1.2.1 +prettytable==0.7.2 +pycparser==2.18 +pyflakes==0.8.1 +pyOpenSSL==17.1.0 +pyparsing==2.1.0 +pyperclip==1.5.27 +python-cinderclient==3.3.0 +python-glanceclient==2.8.0 +python-keystoneclient==3.8.0 +python-mimeparse==1.6.0 +python-novaclient==9.1.0 +python-openstackclient==3.12.0 +python-subunit==1.0.0 +pytz==2013.6 +PyYAML==3.12 +requests==2.14.2 +requests-mock==1.2.0 +requestsexceptions==1.2.0 +rfc3986==0.3.1 +simplejson==3.5.1 +six==1.10.0 +stevedore==1.20.0 +testrepository==0.0.18 +testtools==2.2.0 +traceback2==1.4.0 +unittest2==1.1.0 +warlock==1.2.0 +wrapt==1.7.0 diff --git a/requirements.txt b/requirements.txt index 44da02a..aab6108 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,9 +3,9 @@ # process, which may cause wedges in the gate later. pbr!=2.1.0,>=2.0.0 # Apache-2.0 requests>=2.14.2 # Apache-2.0 -six>=1.9.0 # MIT -cliff>=2.8.0 # Apache-2.0 -keystoneauth1>=3.0.1 # Apache-2.0 -oslo.i18n!=3.15.2,>=2.1.0 # Apache-2.0 -oslo.serialization!=2.19.1,>=1.10.0 # Apache-2.0 -oslo.utils>=3.20.0 # Apache-2.0 +six>=1.10.0 # MIT +cliff!=2.9.0,>=2.8.0 # Apache-2.0 +keystoneauth1>=3.4.0 # Apache-2.0 +oslo.i18n>=3.15.3 # Apache-2.0 +oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0 +oslo.utils>=3.33.0 # Apache-2.0 diff --git a/test-requirements.txt b/test-requirements.txt index 4eedab7..71f8127 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -4,15 +4,11 @@ coverage!=4.4,>=4.0 # Apache-2.0 hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0 fixtures>=3.0.0 # Apache-2.0/BSD -requests-mock>=1.1 # Apache-2.0 -mock>=2.0 # BSD +requests-mock>=1.2.0 # Apache-2.0 +mock>=2.0.0 # BSD testrepository>=0.0.18 # Apache-2.0/BSD -testtools>=1.4.0 # MIT -oslotest>=1.10.0 # Apache-2.0 -nose # LGPL -oslo.config!=4.3.0,!=4.4.0,>=4.0.0 # Apache-2.0 -python-openstackclient!=3.10.0,>=3.3.0 # Apache-2.0 - -# Documentation build requirements -sphinx>=1.6.2 # BSD -openstackdocstheme>=1.11.0 # Apache-2.0 +testtools>=2.2.0 # MIT +oslotest>=3.2.0 # Apache-2.0 +nose>=1.3.7 # LGPL +oslo.config>=5.2.0 # Apache-2.0 +python-openstackclient>=3.12.0 # Apache-2.0 diff --git a/tools/tox_install.sh b/tools/tox_install.sh deleted file mode 100755 index 7203698..0000000 --- a/tools/tox_install.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env bash - -# [liujiong] This file is refer to tox_install.sh in neutron-lib. -# Library constraint file contains this library version pin that is in conflict -# with installing the library from source. We should replace the version pin in -# the constraints file before applying it for from-source installation. - -ZUUL_CLONER=/usr/zuul-env/bin/zuul-cloner -BRANCH_NAME=master -LIB_NAME=python-barbicanclient -requirements_installed=$(echo "import openstack_requirements" | python 2>/dev/null ; echo $?) - -set -e - -CONSTRAINTS_FILE=$1 -shift - -install_cmd="pip install" -mydir=$(mktemp -dt "$LIB_NAME-tox_install-XXXXXXX") -trap "rm -rf $mydir" EXIT -localfile=$mydir/upper-constraints.txt -if [[ $CONSTRAINTS_FILE != http* ]]; then - CONSTRAINTS_FILE=file://$CONSTRAINTS_FILE -fi -curl $CONSTRAINTS_FILE -k -o $localfile -install_cmd="$install_cmd -c$localfile" - -if [ $requirements_installed -eq 0 ]; then - echo "Requirements already installed; using existing package" -elif [ -x "$ZUUL_CLONER" ]; then - pushd $mydir - $ZUUL_CLONER --cache-dir \ - /opt/git \ - --branch $BRANCH_NAME \ - git://git.openstack.org \ - openstack/requirements - cd openstack/requirements - $install_cmd -e . - popd -else - if [ -z "$REQUIREMENTS_PIP_LOCATION" ]; then - REQUIREMENTS_PIP_LOCATION="git+https://git.openstack.org/openstack/requirements@$BRANCH_NAME#egg=requirements" - fi - $install_cmd -U -e ${REQUIREMENTS_PIP_LOCATION} -fi - -# This is the main purpose of the script: Allow local installation of -# the current repo. It is listed in constraints file and thus any -# install will be constrained and we need to unconstrain it. -edit-constraints $localfile -- $LIB_NAME "-e file://$PWD#egg=$LIB_NAME" - -$install_cmd -U $* -exit $? @@ -5,10 +5,12 @@ skipsdist = True [testenv] usedevelop = True -install_command = {toxinidir}/tools/tox_install.sh {env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages} +install_command = pip install {opts} {packages} setenv = VIRTUAL_ENV={envdir} -deps = -r{toxinidir}/requirements.txt +deps = + -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} + -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt commands = @@ -27,16 +29,26 @@ commands = flake8 {posargs} commands = {posargs} [testenv:docs] -commands = python setup.py build_sphinx +deps = + -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} + -r{toxinidir}/requirements.txt + -r{toxinidir}/doc/requirements.txt +commands = sphinx-build -b html doc/source doc/build/html [testenv:functional] # This tox env is purely to make local test development easier # Note: This requires local running instances of Barbican -deps = - {[testenv]deps} +deps = {[testenv]deps} commands = nosetests {toxinidir}/functionaltests/{posargs} -v [flake8] ignore = H202 show-source = True exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build + +[testenv:lower-constraints] +basepython = python3 +deps = + -c{toxinidir}/lower-constraints.txt + -r{toxinidir}/test-requirements.txt + -r{toxinidir}/requirements.txt |