Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit de13e3b

Browse files
Helen KoikeJon Wayne Parrott
Helen Koike
authored and
Jon Wayne Parrott
committed
Remove oauth2client._helpers dependency (googleapis#493)
1 parent bc33595 commit de13e3b

File tree

9 files changed

+379
-40
lines changed

9 files changed

+379
-40
lines changed

googleapiclient/_helpers.py

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
# Copyright 2015 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Helper functions for commonly used utilities."""
16+
17+
import functools
18+
import inspect
19+
import logging
20+
import warnings
21+
22+
import six
23+
from six.moves import urllib
24+
25+
26+
logger = logging.getLogger(__name__)
27+
28+
POSITIONAL_WARNING = 'WARNING'
29+
POSITIONAL_EXCEPTION = 'EXCEPTION'
30+
POSITIONAL_IGNORE = 'IGNORE'
31+
POSITIONAL_SET = frozenset([POSITIONAL_WARNING, POSITIONAL_EXCEPTION,
32+
POSITIONAL_IGNORE])
33+
34+
positional_parameters_enforcement = POSITIONAL_WARNING
35+
36+
_SYM_LINK_MESSAGE = 'File: {0}: Is a symbolic link.'
37+
_IS_DIR_MESSAGE = '{0}: Is a directory'
38+
_MISSING_FILE_MESSAGE = 'Cannot access {0}: No such file or directory'
39+
40+
41+
def positional(max_positional_args):
42+
"""A decorator to declare that only the first N arguments my be positional.
43+
44+
This decorator makes it easy to support Python 3 style keyword-only
45+
parameters. For example, in Python 3 it is possible to write::
46+
47+
def fn(pos1, *, kwonly1=None, kwonly1=None):
48+
...
49+
50+
All named parameters after ``*`` must be a keyword::
51+
52+
fn(10, 'kw1', 'kw2') # Raises exception.
53+
fn(10, kwonly1='kw1') # Ok.
54+
55+
Example
56+
^^^^^^^
57+
58+
To define a function like above, do::
59+
60+
@positional(1)
61+
def fn(pos1, kwonly1=None, kwonly2=None):
62+
...
63+
64+
If no default value is provided to a keyword argument, it becomes a
65+
required keyword argument::
66+
67+
@positional(0)
68+
def fn(required_kw):
69+
...
70+
71+
This must be called with the keyword parameter::
72+
73+
fn() # Raises exception.
74+
fn(10) # Raises exception.
75+
fn(required_kw=10) # Ok.
76+
77+
When defining instance or class methods always remember to account for
78+
``self`` and ``cls``::
79+
80+
class MyClass(object):
81+
82+
@positional(2)
83+
def my_method(self, pos1, kwonly1=None):
84+
...
85+
86+
@classmethod
87+
@positional(2)
88+
def my_method(cls, pos1, kwonly1=None):
89+
...
90+
91+
The positional decorator behavior is controlled by
92+
``_helpers.positional_parameters_enforcement``, which may be set to
93+
``POSITIONAL_EXCEPTION``, ``POSITIONAL_WARNING`` or
94+
``POSITIONAL_IGNORE`` to raise an exception, log a warning, or do
95+
nothing, respectively, if a declaration is violated.
96+
97+
Args:
98+
max_positional_arguments: Maximum number of positional arguments. All
99+
parameters after the this index must be
100+
keyword only.
101+
102+
Returns:
103+
A decorator that prevents using arguments after max_positional_args
104+
from being used as positional parameters.
105+
106+
Raises:
107+
TypeError: if a key-word only argument is provided as a positional
108+
parameter, but only if
109+
_helpers.positional_parameters_enforcement is set to
110+
POSITIONAL_EXCEPTION.
111+
"""
112+
113+
def positional_decorator(wrapped):
114+
@functools.wraps(wrapped)
115+
def positional_wrapper(*args, **kwargs):
116+
if len(args) > max_positional_args:
117+
plural_s = ''
118+
if max_positional_args != 1:
119+
plural_s = 's'
120+
message = ('{function}() takes at most {args_max} positional '
121+
'argument{plural} ({args_given} given)'.format(
122+
function=wrapped.__name__,
123+
args_max=max_positional_args,
124+
args_given=len(args),
125+
plural=plural_s))
126+
if positional_parameters_enforcement == POSITIONAL_EXCEPTION:
127+
raise TypeError(message)
128+
elif positional_parameters_enforcement == POSITIONAL_WARNING:
129+
logger.warning(message)
130+
return wrapped(*args, **kwargs)
131+
return positional_wrapper
132+
133+
if isinstance(max_positional_args, six.integer_types):
134+
return positional_decorator
135+
else:
136+
args, _, _, defaults = inspect.getargspec(max_positional_args)
137+
return positional(len(args) - len(defaults))(max_positional_args)
138+
139+
140+
def parse_unique_urlencoded(content):
141+
"""Parses unique key-value parameters from urlencoded content.
142+
143+
Args:
144+
content: string, URL-encoded key-value pairs.
145+
146+
Returns:
147+
dict, The key-value pairs from ``content``.
148+
149+
Raises:
150+
ValueError: if one of the keys is repeated.
151+
"""
152+
urlencoded_params = urllib.parse.parse_qs(content)
153+
params = {}
154+
for key, value in six.iteritems(urlencoded_params):
155+
if len(value) != 1:
156+
msg = ('URL-encoded content contains a repeated value:'
157+
'%s -> %s' % (key, ', '.join(value)))
158+
raise ValueError(msg)
159+
params[key] = value[0]
160+
return params
161+
162+
163+
def update_query_params(uri, params):
164+
"""Updates a URI with new query parameters.
165+
166+
If a given key from ``params`` is repeated in the ``uri``, then
167+
the URI will be considered invalid and an error will occur.
168+
169+
If the URI is valid, then each value from ``params`` will
170+
replace the corresponding value in the query parameters (if
171+
it exists).
172+
173+
Args:
174+
uri: string, A valid URI, with potential existing query parameters.
175+
params: dict, A dictionary of query parameters.
176+
177+
Returns:
178+
The same URI but with the new query parameters added.
179+
"""
180+
parts = urllib.parse.urlparse(uri)
181+
query_params = parse_unique_urlencoded(parts.query)
182+
query_params.update(params)
183+
new_query = urllib.parse.urlencode(query_params)
184+
new_parts = parts._replace(query=new_query)
185+
return urllib.parse.urlunparse(new_parts)
186+
187+
188+
def _add_query_parameter(url, name, value):
189+
"""Adds a query parameter to a url.
190+
191+
Replaces the current value if it already exists in the URL.
192+
193+
Args:
194+
url: string, url to add the query parameter to.
195+
name: string, query parameter name.
196+
value: string, query parameter value.
197+
198+
Returns:
199+
Updated query parameter. Does not update the url if value is None.
200+
"""
201+
if value is None:
202+
return url
203+
else:
204+
return update_query_params(url, {name: value})

googleapiclient/channel.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,9 @@
6161
import uuid
6262

6363
from googleapiclient import errors
64+
from googleapiclient import _helpers as util
6465
import six
6566

66-
# Oauth2client < 3 has the positional helper in 'util', >= 3 has it
67-
# in '_helpers'.
68-
try:
69-
from oauth2client import util
70-
except ImportError:
71-
from oauth2client import _helpers as util
72-
7367

7468
# The unix time epoch starts at midnight 1970.
7569
EPOCH = datetime.datetime.utcfromtimestamp(0)

googleapiclient/discovery.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,8 @@
7373
from googleapiclient.model import RawModel
7474
from googleapiclient.schema import Schemas
7575

76-
# Oauth2client < 3 has the positional helper in 'util', >= 3 has it
77-
# in '_helpers'.
78-
try:
79-
from oauth2client.util import _add_query_parameter
80-
from oauth2client.util import positional
81-
except ImportError:
82-
from oauth2client._helpers import _add_query_parameter
83-
from oauth2client._helpers import positional
76+
from googleapiclient._helpers import _add_query_parameter
77+
from googleapiclient._helpers import positional
8478

8579

8680
# The client library requires a version of httplib2 that supports RETRIES.

googleapiclient/errors.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,7 @@
2323

2424
import json
2525

26-
# Oauth2client < 3 has the positional helper in 'util', >= 3 has it
27-
# in '_helpers'.
28-
try:
29-
from oauth2client import util
30-
except ImportError:
31-
from oauth2client import _helpers as util
26+
from googleapiclient import _helpers as util
3227

3328

3429
class Error(Exception):

googleapiclient/http.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,7 @@
5555
from email.mime.nonmultipart import MIMENonMultipart
5656
from email.parser import FeedParser
5757

58-
# Oauth2client < 3 has the positional helper in 'util', >= 3 has it
59-
# in '_helpers'.
60-
try:
61-
from oauth2client import util
62-
except ImportError:
63-
from oauth2client import _helpers as util
58+
from googleapiclient import _helpers as util
6459

6560
from googleapiclient import _auth
6661
from googleapiclient.errors import BatchError

googleapiclient/sample_tools.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,13 @@
2727

2828
from googleapiclient import discovery
2929
from googleapiclient.http import build_http
30-
from oauth2client import client
31-
from oauth2client import file
32-
from oauth2client import tools
30+
31+
try:
32+
from oauth2client import client
33+
from oauth2client import file
34+
from oauth2client import tools
35+
except ImportError:
36+
raise ImportError('googleapiclient.sample_tools requires oauth2client. Please install oauth2client and try again.')
3337

3438

3539
def init(argv, name, version, doc, filename, scope=None, parents=[], discovery_filename=None):

googleapiclient/schema.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,7 @@
6565

6666
import copy
6767

68-
# Oauth2client < 3 has the positional helper in 'util', >= 3 has it
69-
# in '_helpers'.
70-
try:
71-
from oauth2client import util
72-
except ImportError:
73-
from oauth2client import _helpers as util
68+
from googleapiclient import _helpers as util
7469

7570

7671
class Schemas(object):

0 commit comments

Comments
 (0)