Use positional library instead of our own copy
The positional library was spun directly out of what keystoneauth1 was using so this is a fairly trivial change. Change-Id: I7931ed1547d2a05e2d248bc3240a576dc68a0a40changes/00/267300/2
parent
f33cb0e280
commit
f21def7061
|
@ -11,8 +11,6 @@
|
|||
# under the License.
|
||||
|
||||
import datetime
|
||||
import functools
|
||||
import inspect
|
||||
import logging
|
||||
|
||||
import iso8601
|
||||
|
@ -27,161 +25,6 @@ def get_logger(name):
|
|||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class positional(object):
|
||||
"""A decorator which enforces only some args may be passed positionally.
|
||||
|
||||
This idea and some of the code was taken from the oauth2 client of the
|
||||
google-api client.
|
||||
|
||||
This decorator makes it easy to support Python 3 style key-word only
|
||||
parameters. For example, in Python 3 it is possible to write::
|
||||
|
||||
def fn(pos1, *, kwonly1, kwonly2=None):
|
||||
...
|
||||
|
||||
All named parameters after * must be a keyword::
|
||||
|
||||
fn(10, 'kw1', 'kw2') # Raises exception.
|
||||
fn(10, kwonly1='kw1', kwonly2='kw2') # Ok.
|
||||
|
||||
To replicate this behaviour with the positional decorator you simply
|
||||
specify how many arguments may be passed positionally. To replicate the
|
||||
example above::
|
||||
|
||||
@positional(1)
|
||||
def fn(pos1, kwonly1=None, kwonly2=None):
|
||||
...
|
||||
|
||||
If no default value is provided to a keyword argument, it becomes a
|
||||
required keyword argument::
|
||||
|
||||
@positional(0)
|
||||
def fn(required_kw):
|
||||
...
|
||||
|
||||
This must be called with the keyword parameter::
|
||||
|
||||
fn() # Raises exception.
|
||||
fn(10) # Raises exception.
|
||||
fn(required_kw=10) # Ok.
|
||||
|
||||
When defining instance or class methods always remember that in python the
|
||||
first positional argument passed is always the instance so you will need to
|
||||
account for `self` and `cls`::
|
||||
|
||||
class MyClass(object):
|
||||
|
||||
@positional(2)
|
||||
def my_method(self, pos1, kwonly1=None):
|
||||
...
|
||||
|
||||
@classmethod
|
||||
@positional(2)
|
||||
def my_method(cls, pos1, kwonly1=None):
|
||||
...
|
||||
|
||||
If you would prefer not to account for `self` and `cls` you can use the
|
||||
`method` and `classmethod` helpers which do not consider the initial
|
||||
positional argument. So the following class is exactly the same as the one
|
||||
above::
|
||||
|
||||
class MyClass(object):
|
||||
|
||||
@positional.method(1)
|
||||
def my_method(self, pos1, kwonly1=None):
|
||||
...
|
||||
|
||||
@positional.classmethod(1)
|
||||
def my_method(cls, pos1, kwonly1=None):
|
||||
...
|
||||
|
||||
If a value isn't provided to the decorator then it will enforce that
|
||||
every variable without a default value will be required to be a kwarg::
|
||||
|
||||
@positional()
|
||||
def fn(pos1, kwonly1=None):
|
||||
...
|
||||
|
||||
fn(10) # Ok.
|
||||
fn(10, 20) # Raises exception.
|
||||
fn(10, kwonly1=20) # Ok.
|
||||
|
||||
This behaviour will work with the `positional.method` and
|
||||
`positional.classmethod` helper functions as well::
|
||||
|
||||
class MyClass(object):
|
||||
|
||||
@positional.classmethod()
|
||||
def my_method(cls, pos1, kwonly1=None):
|
||||
...
|
||||
|
||||
MyClass.my_method(10) # Ok.
|
||||
MyClass.my_method(10, 20) # Raises exception.
|
||||
MyClass.my_method(10, kwonly1=20) # Ok.
|
||||
|
||||
For compatibility reasons you may wish to not always raise an exception so
|
||||
a WARN mode is available. Rather than raise an exception a warning message
|
||||
will be logged::
|
||||
|
||||
@positional(1, enforcement=positional.WARN):
|
||||
def fn(pos1, kwonly=1):
|
||||
...
|
||||
|
||||
Available modes are:
|
||||
|
||||
- positional.EXCEPT - the default, raise an exception.
|
||||
- positional.WARN - log a warning on mistake.
|
||||
"""
|
||||
|
||||
EXCEPT = 'except'
|
||||
WARN = 'warn'
|
||||
|
||||
def __init__(self, max_positional_args=None, enforcement=EXCEPT):
|
||||
self._max_positional_args = max_positional_args
|
||||
self._enforcement = enforcement
|
||||
|
||||
@classmethod
|
||||
def method(cls, max_positional_args=None, enforcement=EXCEPT):
|
||||
if max_positional_args is not None:
|
||||
max_positional_args += 1
|
||||
|
||||
def f(func):
|
||||
return cls(max_positional_args, enforcement)(func)
|
||||
return f
|
||||
|
||||
@classmethod
|
||||
def classmethod(cls, *args, **kwargs):
|
||||
def f(func):
|
||||
return classmethod(cls.method(*args, **kwargs)(func))
|
||||
return f
|
||||
|
||||
def __call__(self, func):
|
||||
if self._max_positional_args is None:
|
||||
spec = inspect.getargspec(func)
|
||||
self._max_positional_args = len(spec.args) - len(spec.defaults)
|
||||
|
||||
plural = '' if self._max_positional_args == 1 else 's'
|
||||
|
||||
@functools.wraps(func)
|
||||
def inner(*args, **kwargs):
|
||||
if len(args) > self._max_positional_args:
|
||||
message = ('%(name)s takes at most %(max)d positional '
|
||||
'argument%(plural)s (%(given)d given)' %
|
||||
{'name': func.__name__,
|
||||
'max': self._max_positional_args,
|
||||
'given': len(args),
|
||||
'plural': plural})
|
||||
|
||||
if self._enforcement == self.EXCEPT:
|
||||
raise TypeError(message)
|
||||
elif self._enforcement == self.WARN:
|
||||
logger.warning(message)
|
||||
|
||||
return func(*args, **kwargs)
|
||||
|
||||
return inner
|
||||
|
||||
|
||||
def normalize_time(timestamp):
|
||||
"""Normalize time in arbitrary timezone to UTC naive object."""
|
||||
offset = timestamp.utcoffset()
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
import functools
|
||||
|
||||
from positional import positional
|
||||
|
||||
from keystoneauth1 import _utils as utils
|
||||
from keystoneauth1.access import service_catalog
|
||||
from keystoneauth1.access import service_providers
|
||||
|
@ -31,7 +33,7 @@ __all__ = ('AccessInfo',
|
|||
'create')
|
||||
|
||||
|
||||
@utils.positional()
|
||||
@positional()
|
||||
def create(resp=None, body=None, auth_token=None):
|
||||
if resp and not body:
|
||||
body = resp.json()
|
||||
|
|
|
@ -18,9 +18,9 @@
|
|||
|
||||
import abc
|
||||
|
||||
from positional import positional
|
||||
import six
|
||||
|
||||
from keystoneauth1 import _utils as utils
|
||||
from keystoneauth1 import exceptions
|
||||
|
||||
|
||||
|
@ -65,7 +65,7 @@ class ServiceCatalog(object):
|
|||
"""
|
||||
return interface
|
||||
|
||||
@utils.positional()
|
||||
@positional()
|
||||
def get_endpoints(self, service_type=None, interface=None,
|
||||
region_name=None, service_name=None,
|
||||
service_id=None, endpoint_id=None):
|
||||
|
@ -141,7 +141,7 @@ class ServiceCatalog(object):
|
|||
return endpoints
|
||||
|
||||
@abc.abstractmethod
|
||||
@utils.positional()
|
||||
@positional()
|
||||
def get_urls(self, service_type=None, interface='public',
|
||||
region_name=None, service_name=None,
|
||||
service_id=None, endpoint_id=None):
|
||||
|
@ -165,7 +165,7 @@ class ServiceCatalog(object):
|
|||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
@utils.positional()
|
||||
@positional()
|
||||
def url_for(self, service_type=None, interface='public',
|
||||
region_name=None, service_name=None,
|
||||
service_id=None, endpoint_id=None):
|
||||
|
@ -251,7 +251,7 @@ class ServiceCatalogV2(ServiceCatalog):
|
|||
def is_interface_match(self, endpoint, interface):
|
||||
return interface in endpoint
|
||||
|
||||
@utils.positional()
|
||||
@positional()
|
||||
def get_urls(self, service_type=None, interface='publicURL',
|
||||
region_name=None, service_name=None,
|
||||
service_id=None, endpoint_id=None):
|
||||
|
@ -293,7 +293,7 @@ class ServiceCatalogV3(ServiceCatalog):
|
|||
except KeyError:
|
||||
return False
|
||||
|
||||
@utils.positional()
|
||||
@positional()
|
||||
def get_urls(self, service_type=None, interface='publicURL',
|
||||
region_name=None, service_name=None,
|
||||
service_id=None, endpoint_id=None):
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
import os
|
||||
|
||||
from keystoneauth1 import _utils as utils
|
||||
from positional import positional
|
||||
|
||||
|
||||
class Adapter(object):
|
||||
|
@ -45,7 +45,7 @@ class Adapter(object):
|
|||
:type logger: logging.Logger
|
||||
"""
|
||||
|
||||
@utils.positional()
|
||||
@positional()
|
||||
def __init__(self, session, service_type=None, service_name=None,
|
||||
interface=None, region_name=None, endpoint_override=None,
|
||||
version=None, auth=None, user_agent=None,
|
||||
|
|
|
@ -23,6 +23,8 @@ raw data specified in version discovery responses.
|
|||
|
||||
import re
|
||||
|
||||
from positional import positional
|
||||
|
||||
from keystoneauth1 import _utils as utils
|
||||
from keystoneauth1 import exceptions
|
||||
|
||||
|
@ -30,7 +32,7 @@ from keystoneauth1 import exceptions
|
|||
_LOGGER = utils.get_logger(__name__)
|
||||
|
||||
|
||||
@utils.positional()
|
||||
@positional()
|
||||
def get_version_data(session, url, authenticated=None):
|
||||
"""Retrieve raw version data from a url."""
|
||||
headers = {'Accept': 'application/json'}
|
||||
|
@ -133,7 +135,7 @@ class Discover(object):
|
|||
DEPRECATED_STATUSES = ('deprecated',)
|
||||
EXPERIMENTAL_STATUSES = ('experimental',)
|
||||
|
||||
@utils.positional()
|
||||
@positional()
|
||||
def __init__(self, session, url, authenticated=None):
|
||||
self._data = get_version_data(session, url,
|
||||
authenticated=authenticated)
|
||||
|
@ -178,7 +180,7 @@ class Discover(object):
|
|||
|
||||
return versions
|
||||
|
||||
@utils.positional()
|
||||
@positional()
|
||||
def version_data(self, reverse=False, **kwargs):
|
||||
"""Get normalized version data.
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from positional import positional
|
||||
|
||||
from keystoneauth1 import _utils as utils
|
||||
|
||||
__all__ = ('DiscoveryList',
|
||||
|
@ -30,7 +32,7 @@ class DiscoveryBase(dict):
|
|||
:param DateTime updated: When the API was last updated.
|
||||
"""
|
||||
|
||||
@utils.positional()
|
||||
@positional()
|
||||
def __init__(self, id, status=None, updated=None):
|
||||
super(DiscoveryBase, self).__init__()
|
||||
|
||||
|
@ -74,7 +76,7 @@ class DiscoveryBase(dict):
|
|||
def updated(self, value):
|
||||
self.updated_str = value.isoformat()
|
||||
|
||||
@utils.positional()
|
||||
@positional()
|
||||
def add_link(self, href, rel='self', type=None):
|
||||
link = {'href': href, 'rel': rel}
|
||||
if type:
|
||||
|
@ -86,7 +88,7 @@ class DiscoveryBase(dict):
|
|||
def media_types(self):
|
||||
return self.setdefault('media-types', [])
|
||||
|
||||
@utils.positional(1)
|
||||
@positional(1)
|
||||
def add_media_type(self, base, type):
|
||||
mt = {'base': base, 'type': type}
|
||||
self.media_types.append(mt)
|
||||
|
@ -110,7 +112,7 @@ class V2Discovery(DiscoveryBase):
|
|||
|
||||
_DESC_URL = 'http://docs.openstack.org/api/openstack-identity-service/2.0/'
|
||||
|
||||
@utils.positional()
|
||||
@positional()
|
||||
def __init__(self, href, id=None, html=True, pdf=True, **kwargs):
|
||||
super(V2Discovery, self).__init__(id or 'v2.0', **kwargs)
|
||||
|
||||
|
@ -156,7 +158,7 @@ class V3Discovery(DiscoveryBase):
|
|||
:param bool xml: Add XML media-type elements to the structure.
|
||||
"""
|
||||
|
||||
@utils.positional()
|
||||
@positional()
|
||||
def __init__(self, href, id=None, json=True, xml=True, **kwargs):
|
||||
super(V3Discovery, self).__init__(id or 'v3.0', **kwargs)
|
||||
|
||||
|
@ -207,7 +209,7 @@ class DiscoveryList(dict):
|
|||
|
||||
TEST_URL = 'http://keystone.host:5000/'
|
||||
|
||||
@utils.positional(2)
|
||||
@positional(2)
|
||||
def __init__(self, href=None, v2=True, v3=True, v2_id=None, v3_id=None,
|
||||
v2_status=None, v2_updated=None, v2_html=True, v2_pdf=True,
|
||||
v3_status=None, v3_updated=None, v3_json=True, v3_xml=True):
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from keystoneauth1 import _utils as utils
|
||||
from positional import positional
|
||||
|
||||
from keystoneauth1.identity import base
|
||||
|
||||
|
||||
|
@ -31,7 +32,7 @@ class AccessInfoPlugin(base.BaseIdentityPlugin):
|
|||
if using the AUTH_INTERFACE with get_endpoint. (optional)
|
||||
"""
|
||||
|
||||
@utils.positional()
|
||||
@positional()
|
||||
def __init__(self, auth_ref, auth_url=None):
|
||||
super(AccessInfoPlugin, self).__init__(auth_url=auth_url,
|
||||
reauthenticate=False)
|
||||
|
|
|
@ -16,6 +16,7 @@ import hashlib
|
|||
import json
|
||||
import threading
|
||||
|
||||
from positional import positional
|
||||
import six
|
||||
|
||||
from keystoneauth1 import _utils as utils
|
||||
|
@ -261,7 +262,7 @@ class BaseIdentityPlugin(plugin.BaseAuthPlugin):
|
|||
except exceptions.ServiceProviderNotFound:
|
||||
return None
|
||||
|
||||
@utils.positional()
|
||||
@positional()
|
||||
def get_discovery(self, session, url, authenticated=None):
|
||||
"""Return the discovery object for a URL.
|
||||
|
||||
|
|
|
@ -10,14 +10,13 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from keystoneauth1 import _utils as utils
|
||||
from positional import positional
|
||||
|
||||
from keystoneauth1 import discover
|
||||
from keystoneauth1.identity.generic import base
|
||||
from keystoneauth1.identity import v2
|
||||
from keystoneauth1.identity import v3
|
||||
|
||||
LOG = utils.get_logger(__name__)
|
||||
|
||||
|
||||
class Password(base.BaseGenericPlugin):
|
||||
"""A common user/password authentication plugin.
|
||||
|
@ -30,7 +29,7 @@ class Password(base.BaseGenericPlugin):
|
|||
|
||||
"""
|
||||
|
||||
@utils.positional()
|
||||
@positional()
|
||||
def __init__(self, auth_url, username=None, user_id=None, password=None,
|
||||
user_domain_id=None, user_domain_name=None, **kwargs):
|
||||
super(Password, self).__init__(auth_url=auth_url, **kwargs)
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
import abc
|
||||
|
||||
from positional import positional
|
||||
import six
|
||||
|
||||
from keystoneauth1 import _utils as utils
|
||||
|
@ -34,7 +35,7 @@ class Auth(base.BaseIdentityPlugin):
|
|||
is going to expire. (optional) default True
|
||||
"""
|
||||
|
||||
@utils.positional()
|
||||
@positional()
|
||||
def __init__(self, auth_url,
|
||||
trust_id=None,
|
||||
tenant_id=None,
|
||||
|
@ -110,7 +111,7 @@ class Password(Auth):
|
|||
:raises TypeError: if a user_id or username is not provided.
|
||||
"""
|
||||
|
||||
@utils.positional(4)
|
||||
@positional(4)
|
||||
def __init__(self, auth_url, username=_NOT_PASSED, password=None,
|
||||
user_id=_NOT_PASSED, **kwargs):
|
||||
super(Password, self).__init__(auth_url, **kwargs)
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
import abc
|
||||
|
||||
from positional import positional
|
||||
import six
|
||||
|
||||
from keystoneauth1 import _utils as utils
|
||||
|
@ -43,7 +44,7 @@ class BaseAuth(base.BaseIdentityPlugin):
|
|||
token. (optional) default True.
|
||||
"""
|
||||
|
||||
@utils.positional()
|
||||
@positional()
|
||||
def __init__(self, auth_url,
|
||||
trust_id=None,
|
||||
domain_id=None,
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from keystoneauth1 import _utils
|
||||
from positional import positional
|
||||
|
||||
from keystoneauth1 import access
|
||||
from keystoneauth1.identity.v3 import federation
|
||||
|
||||
|
@ -131,7 +132,7 @@ class _OidcBase(federation.FederationBaseAuth):
|
|||
class OidcPassword(_OidcBase):
|
||||
"""Implementation for OpenID Connect Resource Owner Password Credential"""
|
||||
|
||||
@_utils.positional(4)
|
||||
@positional(4)
|
||||
def __init__(self, auth_url, identity_provider, protocol,
|
||||
client_id, client_secret, access_token_endpoint,
|
||||
grant_type='password', access_token_type='access_token',
|
||||
|
@ -203,7 +204,7 @@ class OidcPassword(_OidcBase):
|
|||
class OidcAuthorizationCode(_OidcBase):
|
||||
"""Implementation for OpenID Connect Authorization Code"""
|
||||
|
||||
@_utils.positional(4)
|
||||
@positional(4)
|
||||
def __init__(self, auth_url, identity_provider, protocol,
|
||||
client_id, client_secret, access_token_endpoint,
|
||||
grant_type='authorization_code',
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
import argparse
|
||||
import os
|
||||
|
||||
from keystoneauth1 import _utils as utils
|
||||
from positional import positional
|
||||
|
||||
from keystoneauth1.loading import base
|
||||
|
||||
|
||||
|
@ -30,7 +31,7 @@ def _register_plugin_argparse_arguments(parser, plugin):
|
|||
dest='os_%s' % opt.dest)
|
||||
|
||||
|
||||
@utils.positional()
|
||||
@positional()
|
||||
def register_argparse_arguments(parser, argv, default=None):
|
||||
"""Register CLI options needed to create a plugin.
|
||||
|
||||
|
|
|
@ -13,13 +13,13 @@
|
|||
import itertools
|
||||
import os
|
||||
|
||||
from positional import positional
|
||||
|
||||
try:
|
||||
from oslo_config import cfg
|
||||
except ImportError:
|
||||
cfg = None
|
||||
|
||||
from keystoneauth1 import _utils as utils
|
||||
|
||||
|
||||
__all__ = ('Opt',)
|
||||
|
||||
|
@ -62,7 +62,7 @@ class Opt(object):
|
|||
required option is not present loading should fail.
|
||||
"""
|
||||
|
||||
@utils.positional()
|
||||
@positional()
|
||||
def __init__(self,
|
||||
name,
|
||||
type=str,
|
||||
|
|
|
@ -13,12 +13,13 @@
|
|||
import argparse
|
||||
import os
|
||||
|
||||
from positional import positional
|
||||
|
||||
try:
|
||||
from oslo_config import cfg
|
||||
except ImportError:
|
||||
cfg = None
|
||||
|
||||
from keystoneauth1 import _utils as utils
|
||||
from keystoneauth1.loading import base
|
||||
from keystoneauth1 import session
|
||||
|
||||
|
@ -53,7 +54,7 @@ class Session(base.BaseLoader):
|
|||
def get_options(self):
|
||||
return []
|
||||
|
||||
@utils.positional(1)
|
||||
@positional(1)
|
||||
def load_from_options(self,
|
||||
insecure=False,
|
||||
verify=None,
|
||||
|
|
|
@ -20,6 +20,7 @@ import socket
|
|||
import time
|
||||
import uuid
|
||||
|
||||
from positional import positional
|
||||
import requests
|
||||
import six
|
||||
from six.moves import urllib
|
||||
|
@ -117,7 +118,7 @@ class Session(object):
|
|||
|
||||
_DEFAULT_REDIRECT_LIMIT = 30
|
||||
|
||||
@utils.positional(2)
|
||||
@positional(2)
|
||||
def __init__(self, auth=None, session=None, original_ip=None, verify=True,
|
||||
cert=None, timeout=None, user_agent=None,
|
||||
redirect=_DEFAULT_REDIRECT_LIMIT):
|
||||
|
@ -185,7 +186,7 @@ class Session(object):
|
|||
return (header[0], '{SHA1}%s' % token_hash)
|
||||
return header
|
||||
|
||||
@utils.positional()
|
||||
@positional()
|
||||
def _http_log_request(self, url, method=None, data=None,
|
||||
json=None, headers=None, logger=_logger):
|
||||
if not logger.isEnabledFor(logging.DEBUG):
|
||||
|
@ -224,7 +225,7 @@ class Session(object):
|
|||
|
||||
logger.debug(' '.join(string_parts))
|
||||
|
||||
@utils.positional()
|
||||
@positional()
|
||||
def _http_log_response(self, response=None, json=None,
|
||||
status_code=None, headers=None, text=None,
|
||||
logger=_logger):
|
||||
|
@ -253,7 +254,7 @@ class Session(object):
|
|||
|
||||
logger.debug(' '.join(string_parts))
|
||||
|
||||
@utils.positional()
|
||||
@positional()
|
||||
def request(self, url, method, json=None, original_ip=None,
|
||||
user_agent=None, redirect=None, authenticated=None,
|
||||
endpoint_filter=None, auth=None, requests_auth=None,
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
pbr>=1.6 # Apache-2.0
|
||||
argparse # PSF
|
||||
iso8601>=0.1.9 # MIT
|
||||
positional>=1.0.1 # Apache-2.0
|
||||
requests!=2.9.0,>=2.8.1 # Apache-2.0
|
||||
six>=1.9.0 # MIT
|
||||
stevedore>=1.5.0 # Apache-2.0
|
||||
|
|
Loading…
Reference in New Issue