Package oauth2client :: Module util |
[hide private]
[frames] | no frames]

# Source Code for Module oauth2client.util

      1  #!/usr/bin/env python
      2  #
      3  # Copyright 2010 Google Inc.
      4  #
      5  # Licensed under the Apache License, Version 2.0 (the "License");
      6  # you may not use this file except in compliance with the License.
      7  # You may obtain a copy of the License at
      8  #
      9  #     http://www.apache.org/licenses/LICENSE-2.0
     10  #
     11  # Unless required by applicable law or agreed to in writing, software
     12  # distributed under the License is distributed on an "AS IS" BASIS,
     13  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  # See the License for the specific language governing permissions and
     15  # limitations under the License.
     16  #
     17
     18  """Common utility library."""
     19
     20  __author__ = ['rafek@google.com (Rafe Kaplan)',
     21                'guido@google.com (Guido van Rossum)',
     22  ]
     23  __all__ = [
     24    'positional',
     25    'POSITIONAL_WARNING',
     26    'POSITIONAL_EXCEPTION',
     27    'POSITIONAL_IGNORE',
     28  ]
     29
     30  import inspect
     31  import logging
     32  import types
     33  import urllib
     34  import urlparse
     35
     36  try:
     37    from urlparse import parse_qsl
     38  except ImportError:
     39    from cgi import parse_qsl
     40
     41  logger = logging.getLogger(__name__)
     42
     43  POSITIONAL_WARNING = 'WARNING'
     44  POSITIONAL_EXCEPTION = 'EXCEPTION'
     45  POSITIONAL_IGNORE = 'IGNORE'
     46  POSITIONAL_SET = frozenset([POSITIONAL_WARNING, POSITIONAL_EXCEPTION,
     47                              POSITIONAL_IGNORE])
     48
     49  positional_parameters_enforcement = POSITIONAL_WARNING
     50
     51 -def positional(max_positional_args):
     52    """A decorator to declare that only the first N arguments my be positional.
     53
     54    This decorator makes it easy to support Python 3 style key-word only
     55    parameters. For example, in Python 3 it is possible to write:
     56
     57      def fn(pos1, *, kwonly1=None, kwonly1=None):
     58        ...
     59
     60    All named parameters after * must be a keyword:
     61
     62      fn(10, 'kw1', 'kw2')  # Raises exception.
     63      fn(10, kwonly1='kw1')  # Ok.
     64
     65    Example:
     66      To define a function like above, do:
     67
     68        @positional(1)
     69        def fn(pos1, kwonly1=None, kwonly2=None):
     70          ...
     71
     72      If no default value is provided to a keyword argument, it becomes a required
     73      keyword argument:
     74
     75        @positional(0)
     76        def fn(required_kw):
     77          ...
     78
     79      This must be called with the keyword parameter:
     80
     81        fn()  # Raises exception.
     82        fn(10)  # Raises exception.
     83        fn(required_kw=10)  # Ok.
     84
     85      When defining instance or class methods always remember to account for
     86      'self' and 'cls':
     87
     88        class MyClass(object):
     89
     90          @positional(2)
     91          def my_method(self, pos1, kwonly1=None):
     92            ...
     93
     94          @classmethod
     95          @positional(2)
     96          def my_method(cls, pos1, kwonly1=None):
     97            ...
     98
     99    The positional decorator behavior is controlled by
    100    util.positional_parameters_enforcement, which may be set to
    101    POSITIONAL_EXCEPTION, POSITIONAL_WARNING or POSITIONAL_IGNORE to raise an
    102    exception, log a warning, or do nothing, respectively, if a declaration is
    103    violated.
    104
    105    Args:
    106      max_positional_arguments: Maximum number of positional arguments. All
    107        parameters after the this index must be keyword only.
    108
    109    Returns:
    110      A decorator that prevents using arguments after max_positional_args from
    111      being used as positional parameters.
    112
    113    Raises:
    114      TypeError if a key-word only argument is provided as a positional
    115      parameter, but only if util.positional_parameters_enforcement is set to
    116      POSITIONAL_EXCEPTION.
    117    """
    118    def positional_decorator(wrapped):
    119      def positional_wrapper(*args, **kwargs):
    120        if len(args) > max_positional_args:
    121          plural_s = ''
    122          if max_positional_args != 1:
    123            plural_s = 's'
    124          message = '%s() takes at most %d positional argument%s (%d given)' % (
    125              wrapped.__name__, max_positional_args, plural_s, len(args))
    126          if positional_parameters_enforcement == POSITIONAL_EXCEPTION:
    127            raise TypeError(message)
    128          elif positional_parameters_enforcement == POSITIONAL_WARNING:
    129            logger.warning(message)
    130          else: # IGNORE
    131            pass
    132        return wrapped(*args, **kwargs)
    133      return positional_wrapper
    134
    135    if isinstance(max_positional_args, (int, long)):
    136      return positional_decorator
    137    else:
    138      args, _, _, defaults = inspect.getargspec(max_positional_args)
    139      return positional(len(args) - len(defaults))(max_positional_args)
    140
    141
    142 -def scopes_to_string(scopes):
    143    """Converts scope value to a string.
    144
    145    If scopes is a string then it is simply passed through. If scopes is an
    146    iterable then a string is returned that is all the individual scopes
    147    concatenated with spaces.
    148
    149    Args:
    150      scopes: string or iterable of strings, the scopes.
    151
    152    Returns:
    153      The scopes formatted as a single string.
    154    """
    155    if isinstance(scopes, types.StringTypes):
    156      return scopes
    157    else:
    158      return ' '.join(scopes)
    159
    160
    161 -def dict_to_tuple_key(dictionary):
    162    """Converts a dictionary to a tuple that can be used as an immutable key.
    163
    164    The resulting key is always sorted so that logically equivalent dictionaries
    165    always produce an identical tuple for a key.
    166
    167    Args:
    168      dictionary: the dictionary to use as the key.
    169
    170    Returns:
    171      A tuple representing the dictionary in it's naturally sorted ordering.
    172    """
    173    return tuple(sorted(dictionary.items()))
    174
    175
    176 -def _add_query_parameter(url, name, value):
    177    """Adds a query parameter to a url.
    178
    179    Replaces the current value if it already exists in the URL.
    180
    181    Args:
    182      url: string, url to add the query parameter to.
    183      name: string, query parameter name.
    184      value: string, query parameter value.
    185
    186    Returns:
    187      Updated query parameter. Does not update the url if value is None.
    188    """
    189    if value is None:
    190      return url
    191    else:
    192      parsed = list(urlparse.urlparse(url))
    193      q = dict(parse_qsl(parsed[4]))
    194      q[name] = value
    195      parsed[4] = urllib.urlencode(q)
    196      return urlparse.urlunparse(parsed)
    197