Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
jeffkpayne committed Oct 12, 2017
2 parents 6d82f99 + e1a2483 commit 3708a15
Show file tree
Hide file tree
Showing 20 changed files with 1,415 additions and 184 deletions.
3 changes: 2 additions & 1 deletion core/google/api/core/gapic_v1/method.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

from google.api.core import page_iterator
from google.api.core import timeout
from google.api.core.helpers import general_helpers
from google.api.core.helpers import grpc_helpers

_PY_VERSION = platform.python_version()
Expand Down Expand Up @@ -252,7 +253,7 @@ def get_topic(name, timeout=None):
if metadata is not None:
metadata = _prepare_metadata(metadata)

return six.wraps(func)(
return general_helpers.wraps(func)(
_GapicCallable(func, default_retry, default_timeout, metadata))


Expand Down
32 changes: 32 additions & 0 deletions core/google/api/core/helpers/general_helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Copyright 2017 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Helpers for general Python functionality."""

import functools

import six


# functools.partial objects lack several attributes present on real function
# objects. In Python 2 wraps fails on this so use a restricted set instead.
_PARTIAL_VALID_ASSIGNMENTS = ('__doc__',)


def wraps(wrapped):
"""A functools.wraps helper that handles partial objects on Python 2."""
if isinstance(wrapped, functools.partial):
return six.wraps(wrapped, assigned=_PARTIAL_VALID_ASSIGNMENTS)
else:
return six.wraps(wrapped)
3 changes: 2 additions & 1 deletion core/google/api/core/helpers/grpc_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import six

from google.api.core import exceptions
from google.api.core.helpers import general_helpers
import google.auth
import google.auth.transport.grpc
import google.auth.transport.requests
Expand Down Expand Up @@ -63,7 +64,7 @@ def _wrap_stream_errors(callable_):
"""
_patch_callable_name(callable_)

@six.wraps(callable_)
@general_helpers.wraps(callable_)
def error_remapped_callable(*args, **kwargs):
try:
result = callable_(*args, **kwargs)
Expand Down
3 changes: 2 additions & 1 deletion core/google/api/core/retry.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ def check_if_exists():

from google.api.core import exceptions
from google.api.core.helpers import datetime_helpers
from google.api.core.helpers import general_helpers

_LOGGER = logging.getLogger(__name__)
_DEFAULT_INITIAL_DELAY = 1.0 # seconds
Expand Down Expand Up @@ -244,7 +245,7 @@ def __call__(self, func, on_error=None):
Callable: A callable that will invoke ``func`` with retry
behavior.
"""
@six.wraps(func)
@general_helpers.wraps(func)
def retry_wrapped_func(*args, **kwargs):
"""A wrapper that calls target function with retry."""
target = functools.partial(func, *args, **kwargs)
Expand Down
5 changes: 3 additions & 2 deletions core/google/api/core/timeout.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ def is_thing_ready(timeout=None):
import six

from google.api.core.helpers import datetime_helpers
from google.api.core.helpers import general_helpers

_DEFAULT_INITIAL_TIMEOUT = 5.0 # seconds
_DEFAULT_MAXIMUM_TIMEOUT = 30.0 # seconds
Expand Down Expand Up @@ -92,7 +93,7 @@ def __call__(self, func):
Returns:
Callable: The wrapped function.
"""
@six.wraps(func)
@general_helpers.wraps(func)
def func_with_timeout(*args, **kwargs):
"""Wrapped function that adds timeout."""
kwargs['timeout'] = self._timeout
Expand Down Expand Up @@ -198,7 +199,7 @@ def __call__(self, func):
timeouts = _exponential_timeout_generator(
self._initial, self._maximum, self._multiplier, self._deadline)

@six.wraps(func)
@general_helpers.wraps(func)
def func_with_timeout(*args, **kwargs):
"""Wrapped function that adds timeout."""
kwargs['timeout'] = next(timeouts)
Expand Down
43 changes: 43 additions & 0 deletions core/tests/unit/api_core/helpers/test_general_helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Copyright 2017, Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import functools

from google.api.core.helpers import general_helpers


def test_wraps_normal_func():

def func():
return 42

@general_helpers.wraps(func)
def replacement():
return func()

assert replacement() == 42


def test_wraps_partial():

def func():
return 42

partial = functools.partial(func)

@general_helpers.wraps(partial)
def replacement():
return func()

assert replacement() == 42
2 changes: 1 addition & 1 deletion docs/language/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ returns a :class:`~.language_v1.types.AnalyzeEntitiesResponse`.
>>> document = language.types.Document(
... content='Michelangelo Caravaggio, Italian painter, is '
... 'known for "The Calling of Saint Matthew".',
... type=language.enums.Type.PLAIN_TEXT,
... type=language.enums.Document.Type.PLAIN_TEXT,
... )
>>> response = client.analyze_entities(
... document=document,
Expand Down
3 changes: 3 additions & 0 deletions spanner/.coveragerc
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
[run]
branch = True
omit =
*/gapic/*.py
*/proto/*.py

[report]
fail_under = 100
Expand Down
1 change: 1 addition & 0 deletions spanner/nox.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def unit_tests(session, python_version):
'py.test',
'--quiet',
'--cov=google.cloud.spanner',
'--cov=google.cloud.spanner_v1',
'--cov=tests.unit',
'--cov-append',
'--cov-config=.coveragerc',
Expand Down
17 changes: 15 additions & 2 deletions storage/google/cloud/storage/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ def client(self):
"""Abstract getter for the object client."""
raise NotImplementedError

@property
def user_project(self):
"""Abstract getter for the object user_project."""
raise NotImplementedError

def _require_client(self, client):
"""Check client or verify over-ride.
Expand Down Expand Up @@ -94,6 +99,8 @@ def reload(self, client=None):
# Pass only '?projection=noAcl' here because 'acl' and related
# are handled via custom endpoints.
query_params = {'projection': 'noAcl'}
if self.user_project is not None:
query_params['userProject'] = self.user_project
api_response = client._connection.api_request(
method='GET', path=self.path, query_params=query_params,
_target_object=self)
Expand Down Expand Up @@ -140,13 +147,16 @@ def patch(self, client=None):
client = self._require_client(client)
# Pass '?projection=full' here because 'PATCH' documented not
# to work properly w/ 'noAcl'.
query_params = {'projection': 'full'}
if self.user_project is not None:
query_params['userProject'] = self.user_project
update_properties = {key: self._properties[key]
for key in self._changes}

# Make the API call.
api_response = client._connection.api_request(
method='PATCH', path=self.path, data=update_properties,
query_params={'projection': 'full'}, _target_object=self)
query_params=query_params, _target_object=self)
self._set_properties(api_response)

def update(self, client=None):
Expand All @@ -160,9 +170,12 @@ def update(self, client=None):
``client`` stored on the current object.
"""
client = self._require_client(client)
query_params = {'projection': 'full'}
if self.user_project is not None:
query_params['userProject'] = self.user_project
api_response = client._connection.api_request(
method='PUT', path=self.path, data=self._properties,
query_params={'projection': 'full'}, _target_object=self)
query_params=query_params, _target_object=self)
self._set_properties(api_response)


Expand Down
25 changes: 24 additions & 1 deletion storage/google/cloud/storage/acl.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ class ACL(object):
# as properties).
reload_path = None
save_path = None
user_project = None

def __init__(self):
self.entities = {}
Expand Down Expand Up @@ -405,10 +406,18 @@ def reload(self, client=None):
"""
path = self.reload_path
client = self._require_client(client)
query_params = {}

if self.user_project is not None:
query_params['userProject'] = self.user_project

self.entities.clear()

found = client._connection.api_request(method='GET', path=path)
found = client._connection.api_request(
method='GET',
path=path,
query_params=query_params,
)
self.loaded = True
for entry in found.get('items', ()):
self.add_entity(self.entity_from_dict(entry))
Expand All @@ -435,8 +444,12 @@ def _save(self, acl, predefined, client):
acl = []
query_params[self._PREDEFINED_QUERY_PARAM] = predefined

if self.user_project is not None:
query_params['userProject'] = self.user_project

path = self.save_path
client = self._require_client(client)

result = client._connection.api_request(
method='PATCH',
path=path,
Expand Down Expand Up @@ -532,6 +545,11 @@ def save_path(self):
"""Compute the path for PATCH API requests for this ACL."""
return self.bucket.path

@property
def user_project(self):
"""Compute the user project charged for API requests for this ACL."""
return self.bucket.user_project


class DefaultObjectACL(BucketACL):
"""A class representing the default object ACL for a bucket."""
Expand Down Expand Up @@ -565,3 +583,8 @@ def reload_path(self):
def save_path(self):
"""Compute the path for PATCH API requests for this ACL."""
return self.blob.path

@property
def user_project(self):
"""Compute the user project charged for API requests for this ACL."""
return self.blob.user_project
Loading

0 comments on commit 3708a15

Please sign in to comment.