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

Source Code for Module oauth2client.util

  1  #!/usr/bin/env python 
  2  # 
  3  # Copyright 2014 Google Inc. All rights reserved. 
  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__ = [ 
 21      'rafek@google.com (Rafe Kaplan)', 
 22      'guido@google.com (Guido van Rossum)', 
 23  ] 
 24   
 25  __all__ = [ 
 26      'positional', 
 27      'POSITIONAL_WARNING', 
 28      'POSITIONAL_EXCEPTION', 
 29      'POSITIONAL_IGNORE', 
 30  ] 
 31   
 32  import inspect 
 33  import logging 
 34  import sys 
 35  import types 
 36   
 37  import six 
 38  from six.moves import urllib 
 39   
 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, six.integer_types): 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 try: 156 is_string = isinstance(scopes, basestring) 157 except NameError: 158 is_string = isinstance(scopes, str) 159 if is_string: 160 return scopes 161 else: 162 return ' '.join(scopes)
163 164
165 -def dict_to_tuple_key(dictionary):
166 """Converts a dictionary to a tuple that can be used as an immutable key. 167 168 The resulting key is always sorted so that logically equivalent dictionaries 169 always produce an identical tuple for a key. 170 171 Args: 172 dictionary: the dictionary to use as the key. 173 174 Returns: 175 A tuple representing the dictionary in it's naturally sorted ordering. 176 """ 177 return tuple(sorted(dictionary.items()))
178 179
180 -def _add_query_parameter(url, name, value):
181 """Adds a query parameter to a url. 182 183 Replaces the current value if it already exists in the URL. 184 185 Args: 186 url: string, url to add the query parameter to. 187 name: string, query parameter name. 188 value: string, query parameter value. 189 190 Returns: 191 Updated query parameter. Does not update the url if value is None. 192 """ 193 if value is None: 194 return url 195 else: 196 parsed = list(urllib.parse.urlparse(url)) 197 q = dict(urllib.parse.parse_qsl(parsed[4])) 198 q[name] = value 199 parsed[4] = urllib.parse.urlencode(q) 200 return urllib.parse.urlunparse(parsed)
201