Skip to content

Commit 494b838

Browse files
committed
Removing HTTP request in _PropertyMixin.properties.
Also removing dead code: - _PropertyMixin.CUSTOM_PROPERTY_ACCESSORS (and subclasses use of this) - _PropertyMixin._get_property (only consumer of CUSTOM_PROPERTY_ACCESSORS)
1 parent ef1a3da commit 494b838

File tree

6 files changed

+74
-162
lines changed

6 files changed

+74
-162
lines changed

gcloud/storage/_helpers.py

Lines changed: 2 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,10 @@ class _PropertyMixin(object):
2525
"""Abstract mixin for cloud storage classes with associated propertties.
2626
2727
Non-abstract subclasses should implement:
28-
- CUSTOM_PROPERTY_ACCESSORS
2928
- connection
3029
- path
3130
"""
3231

33-
CUSTOM_PROPERTY_ACCESSORS = None
34-
"""Mapping of field name -> accessor for fields w/ custom accessors.
35-
36-
Expected to be set by subclasses. Fields in this mapping will cause
37-
:meth:`_get_property()` to raise a KeyError with a message to use the
38-
relevant accessor methods.
39-
"""
40-
4132
@property
4233
def connection(self):
4334
"""Abstract getter for the connection to use."""
@@ -64,12 +55,11 @@ def __init__(self, name=None, properties=None):
6455

6556
@property
6657
def properties(self):
67-
"""Ensure properties are loaded, and return a copy.
58+
"""Return a copy of properties.
6859
6960
:rtype: dict
61+
:returns: Copy of properties.
7062
"""
71-
if not self._properties:
72-
self._reload_properties()
7363
return self._properties.copy()
7464

7565
@property
@@ -131,30 +121,6 @@ def _patch_properties(self, properties):
131121
query_params={'projection': 'full'})
132122
return self
133123

134-
def _get_property(self, field, default=None):
135-
"""Return the value of a field from the server-side representation.
136-
137-
If you request a field that isn't available, and that field can
138-
be retrieved by refreshing data from Cloud Storage, this method
139-
will reload the data using :func:`_PropertyMixin._reload_properties`.
140-
141-
:type field: string
142-
:param field: A particular field to retrieve from properties.
143-
144-
:type default: anything
145-
:param default: The value to return if the field provided wasn't found.
146-
147-
:rtype: anything
148-
:returns: value of the specific field, or the default if not found.
149-
"""
150-
# Raise for fields which have custom accessors.
151-
custom = self.CUSTOM_PROPERTY_ACCESSORS.get(field)
152-
if custom is not None:
153-
message = "Use '%s' or related methods instead." % custom
154-
raise KeyError((field, message))
155-
156-
return self.properties.get(field, default)
157-
158124

159125
class _PropertyBatch(object):
160126
"""Context manager: Batch updates to object's ``_patch_properties``

gcloud/storage/blob.py

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -52,29 +52,6 @@ class Blob(_PropertyMixin):
5252
:param properties: All the other data provided by Cloud Storage.
5353
"""
5454

55-
CUSTOM_PROPERTY_ACCESSORS = {
56-
'acl': 'acl',
57-
'cacheControl': 'cache_control',
58-
'contentDisposition': 'content_disposition',
59-
'contentEncoding': 'content_encoding',
60-
'contentLanguage': 'content_language',
61-
'contentType': 'content_type',
62-
'componentCount': 'component_count',
63-
'etag': 'etag',
64-
'generation': 'generation',
65-
'id': 'id',
66-
'mediaLink': 'media_link',
67-
'metageneration': 'metageneration',
68-
'name': 'name',
69-
'owner': 'owner',
70-
'selfLink': 'self_link',
71-
'size': 'size',
72-
'storageClass': 'storage_class',
73-
'timeDeleted': 'time_deleted',
74-
'updated': 'updated',
75-
}
76-
"""Map field name -> accessor for fields w/ custom accessors."""
77-
7855
CHUNK_SIZE = 1024 * 1024 # 1 MB.
7956
"""The size of a chunk of data whenever iterating (1 MB).
8057

gcloud/storage/bucket.py

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -86,26 +86,6 @@ class Bucket(_PropertyMixin):
8686
_MAX_OBJECTS_FOR_BUCKET_DELETE = 256
8787
"""Maximum number of existing objects allowed in Bucket.delete()."""
8888

89-
CUSTOM_PROPERTY_ACCESSORS = {
90-
'acl': 'acl',
91-
'cors': 'get_cors()',
92-
'defaultObjectAcl': 'get_default_object_acl()',
93-
'etag': 'etag',
94-
'id': 'id',
95-
'lifecycle': 'get_lifecycle()',
96-
'location': 'location',
97-
'logging': 'get_logging()',
98-
'metageneration': 'metageneration',
99-
'name': 'name',
100-
'owner': 'owner',
101-
'projectNumber': 'project_number',
102-
'selfLink': 'self_link',
103-
'storageClass': 'storage_class',
104-
'timeCreated': 'time_created',
105-
'versioning': 'versioning_enabled',
106-
}
107-
"""Map field name -> accessor for fields w/ custom accessors."""
108-
10989
# ACL rules are lazily retrieved.
11090
_acl = _default_object_acl = None
11191

@@ -590,6 +570,7 @@ def get_logging(self):
590570
:returns: a dict w/ keys, ``logBucket`` and ``logObjectPrefix``
591571
(if logging is enabled), or None (if not).
592572
"""
573+
self._reload_properties()
593574
info = self.properties.get('logging')
594575
if info is not None:
595576
return info.copy()

gcloud/storage/test__helpers.py

Lines changed: 6 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,9 @@ def _getTargetClass(self):
2424
def _makeOne(self, *args, **kw):
2525
return self._getTargetClass()(*args, **kw)
2626

27-
def _derivedClass(self, connection=None, path=None, **custom_fields):
27+
def _derivedClass(self, connection=None, path=None):
2828

2929
class Derived(self._getTargetClass()):
30-
CUSTOM_PROPERTY_ACCESSORS = custom_fields
3130

3231
@property
3332
def connection(self):
@@ -39,18 +38,14 @@ def path(self):
3938

4039
return Derived
4140

42-
def test_connetction_is_abstract(self):
41+
def test_connection_is_abstract(self):
4342
mixin = self._makeOne()
4443
self.assertRaises(NotImplementedError, lambda: mixin.connection)
4544

4645
def test_path_is_abstract(self):
4746
mixin = self._makeOne()
4847
self.assertRaises(NotImplementedError, lambda: mixin.path)
4948

50-
def test_properties_eager(self):
51-
derived = self._derivedClass()(properties={'extant': False})
52-
self.assertEqual(derived.properties, {'extant': False})
53-
5449
def test_batch(self):
5550
connection = _Connection({'foo': 'Qux', 'bar': 'Baz'})
5651
derived = self._derivedClass(connection, '/path')()
@@ -65,9 +60,11 @@ def test_batch(self):
6560
self.assertEqual(kw[0]['data'], {'foo': 'Qux', 'bar': 'Baz'})
6661
self.assertEqual(kw[0]['query_params'], {'projection': 'full'})
6762

68-
def test_properties_lazy(self):
63+
def test_properties_no_fetch(self):
6964
connection = _Connection({'foo': 'Foo'})
7065
derived = self._derivedClass(connection, '/path')()
66+
self.assertEqual(derived.properties, {})
67+
derived._reload_properties()
7168
self.assertEqual(derived.properties, {'foo': 'Foo'})
7269
kw = connection._requested
7370
self.assertEqual(len(kw), 1)
@@ -86,40 +83,6 @@ def test__reload_properties(self):
8683
self.assertEqual(kw[0]['path'], '/path')
8784
self.assertEqual(kw[0]['query_params'], {'projection': 'noAcl'})
8885

89-
def test__get_property_eager_hit(self):
90-
derived = self._derivedClass()(properties={'foo': 'Foo'})
91-
self.assertEqual(derived._get_property('foo'), 'Foo')
92-
93-
def test__get_property_eager_miss_w_default(self):
94-
connection = _Connection({'foo': 'Foo'})
95-
derived = self._derivedClass(connection, '/path')()
96-
default = object()
97-
self.assertTrue(derived._get_property('nonesuch', default) is default)
98-
kw = connection._requested
99-
self.assertEqual(len(kw), 1)
100-
self.assertEqual(kw[0]['method'], 'GET')
101-
self.assertEqual(kw[0]['path'], '/path')
102-
self.assertEqual(kw[0]['query_params'], {'projection': 'noAcl'})
103-
104-
def test__get_property_lazy_hit(self):
105-
connection = _Connection({'foo': 'Foo'})
106-
derived = self._derivedClass(connection, '/path')()
107-
self.assertTrue(derived._get_property('nonesuch') is None)
108-
kw = connection._requested
109-
self.assertEqual(len(kw), 1)
110-
self.assertEqual(kw[0]['method'], 'GET')
111-
self.assertEqual(kw[0]['path'], '/path')
112-
self.assertEqual(kw[0]['query_params'], {'projection': 'noAcl'})
113-
114-
def test__get_property_w_custom_field(self):
115-
derived = self._derivedClass(foo='get_foo')()
116-
try:
117-
derived._get_property('foo')
118-
except KeyError as e:
119-
self.assertTrue('get_foo' in str(e))
120-
else: # pragma: NO COVER
121-
self.assert_('KeyError not raised')
122-
12386
def test__patch_properties(self):
12487
connection = _Connection({'foo': 'Foo'})
12588
derived = self._derivedClass(connection, '/path')()
@@ -141,11 +104,10 @@ def _getTargetClass(self):
141104
def _makeOne(self, wrapped):
142105
return self._getTargetClass()(wrapped)
143106

144-
def _makeWrapped(self, connection=None, path=None, **custom_fields):
107+
def _makeWrapped(self, connection=None, path=None):
145108
from gcloud.storage._helpers import _PropertyMixin
146109

147110
class Wrapped(_PropertyMixin):
148-
CUSTOM_PROPERTY_ACCESSORS = custom_fields
149111

150112
@property
151113
def connection(self):

gcloud/storage/test_bucket.py

Lines changed: 59 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,7 @@ def test_get_cors_lazy(self):
617617
after = {'cors': [CORS_ENTRY]}
618618
connection = _Connection(after)
619619
bucket = self._makeOne(connection, NAME)
620+
bucket._reload_properties() # XXX
620621
entries = bucket.get_cors()
621622
self.assertEqual(len(entries), 1)
622623
self.assertEqual(entries[0]['maxAgeSeconds'],
@@ -709,6 +710,7 @@ def test_get_lifecycle_lazy(self):
709710
after = {'lifecycle': {'rule': [LC_RULE]}}
710711
connection = _Connection(after)
711712
bucket = self._makeOne(connection, NAME)
713+
bucket._reload_properties() # XXX
712714
entries = bucket.get_lifecycle()
713715
self.assertEqual(len(entries), 1)
714716
self.assertEqual(entries[0]['action']['type'], 'Delete')
@@ -760,30 +762,22 @@ def test_location_setter(self):
760762
self.assertEqual(kw[0]['data'], {'location': 'AS'})
761763
self.assertEqual(kw[0]['query_params'], {'projection': 'full'})
762764

763-
def test_get_logging_eager_w_prefix(self):
765+
def test_get_logging_w_prefix(self):
764766
NAME = 'name'
765767
LOG_BUCKET = 'logs'
766768
LOG_PREFIX = 'pfx'
767769
before = {
768-
'logging': {'logBucket': LOG_BUCKET,
769-
'logObjectPrefix': LOG_PREFIX}}
770-
connection = _Connection()
771-
bucket = self._makeOne(connection, NAME, before)
772-
info = bucket.get_logging()
773-
self.assertEqual(info['logBucket'], LOG_BUCKET)
774-
self.assertEqual(info['logObjectPrefix'], LOG_PREFIX)
775-
kw = connection._requested
776-
self.assertEqual(len(kw), 0)
777-
778-
def test_get_logging_lazy_wo_prefix(self):
779-
NAME = 'name'
780-
LOG_BUCKET = 'logs'
781-
after = {'logging': {'logBucket': LOG_BUCKET}}
782-
connection = _Connection(after)
770+
'logging': {
771+
'logBucket': LOG_BUCKET,
772+
'logObjectPrefix': LOG_PREFIX,
773+
},
774+
}
775+
resp_to_reload = before
776+
connection = _Connection(resp_to_reload)
783777
bucket = self._makeOne(connection, NAME)
784778
info = bucket.get_logging()
785779
self.assertEqual(info['logBucket'], LOG_BUCKET)
786-
self.assertEqual(info.get('logObjectPrefix'), None)
780+
self.assertEqual(info['logObjectPrefix'], LOG_PREFIX)
787781
kw = connection._requested
788782
self.assertEqual(len(kw), 1)
789783
self.assertEqual(kw[0]['method'], 'GET')
@@ -794,57 +788,85 @@ def test_enable_logging_defaults(self):
794788
NAME = 'name'
795789
LOG_BUCKET = 'logs'
796790
before = {'logging': None}
797-
after = {'logging': {'logBucket': LOG_BUCKET, 'logObjectPrefix': ''}}
798-
connection = _Connection(after)
791+
resp_to_reload = before
792+
resp_to_enable_logging = {
793+
'logging': {'logBucket': LOG_BUCKET, 'logObjectPrefix': ''},
794+
}
795+
connection = _Connection(resp_to_reload, resp_to_enable_logging,
796+
resp_to_enable_logging) # XXX
799797
bucket = self._makeOne(connection, NAME, before)
800798
self.assertTrue(bucket.get_logging() is None)
801799
bucket.enable_logging(LOG_BUCKET)
802800
info = bucket.get_logging()
803801
self.assertEqual(info['logBucket'], LOG_BUCKET)
804802
self.assertEqual(info['logObjectPrefix'], '')
805803
kw = connection._requested
806-
self.assertEqual(len(kw), 1)
807-
self.assertEqual(kw[0]['method'], 'PATCH')
804+
self.assertEqual(len(kw), 3)
805+
self.assertEqual(kw[0]['method'], 'GET')
808806
self.assertEqual(kw[0]['path'], '/b/%s' % NAME)
809-
self.assertEqual(kw[0]['data'], after)
810-
self.assertEqual(kw[0]['query_params'], {'projection': 'full'})
807+
self.assertEqual(kw[0]['query_params'], {'projection': 'noAcl'})
808+
self.assertEqual(kw[1]['method'], 'PATCH')
809+
self.assertEqual(kw[1]['path'], '/b/%s' % NAME)
810+
self.assertEqual(kw[1]['data'], resp_to_enable_logging)
811+
self.assertEqual(kw[1]['query_params'], {'projection': 'full'})
812+
self.assertEqual(kw[2]['method'], 'GET')
813+
self.assertEqual(kw[2]['path'], '/b/%s' % NAME)
814+
self.assertEqual(kw[2]['query_params'], {'projection': 'noAcl'})
811815

812816
def test_enable_logging_explicit(self):
813817
NAME = 'name'
814818
LOG_BUCKET = 'logs'
815819
LOG_PFX = 'pfx'
816820
before = {'logging': None}
817-
after = {
818-
'logging': {'logBucket': LOG_BUCKET, 'logObjectPrefix': LOG_PFX}}
819-
connection = _Connection(after)
821+
resp_to_reload = before
822+
resp_to_enable_logging = {
823+
'logging': {'logBucket': LOG_BUCKET, 'logObjectPrefix': LOG_PFX},
824+
}
825+
connection = _Connection(resp_to_reload,
826+
resp_to_enable_logging,
827+
resp_to_enable_logging) # XXX
820828
bucket = self._makeOne(connection, NAME, before)
821829
self.assertTrue(bucket.get_logging() is None)
822830
bucket.enable_logging(LOG_BUCKET, LOG_PFX)
823831
info = bucket.get_logging()
824832
self.assertEqual(info['logBucket'], LOG_BUCKET)
825833
self.assertEqual(info['logObjectPrefix'], LOG_PFX)
826834
kw = connection._requested
827-
self.assertEqual(len(kw), 1)
828-
self.assertEqual(kw[0]['method'], 'PATCH')
835+
self.assertEqual(len(kw), 3)
836+
self.assertEqual(kw[0]['method'], 'GET')
829837
self.assertEqual(kw[0]['path'], '/b/%s' % NAME)
830-
self.assertEqual(kw[0]['data'], after)
831-
self.assertEqual(kw[0]['query_params'], {'projection': 'full'})
838+
self.assertEqual(kw[0]['query_params'], {'projection': 'noAcl'})
839+
self.assertEqual(kw[1]['method'], 'PATCH')
840+
self.assertEqual(kw[1]['path'], '/b/%s' % NAME)
841+
self.assertEqual(kw[1]['data'], resp_to_enable_logging)
842+
self.assertEqual(kw[1]['query_params'], {'projection': 'full'})
843+
self.assertEqual(kw[2]['method'], 'GET')
844+
self.assertEqual(kw[2]['path'], '/b/%s' % NAME)
845+
self.assertEqual(kw[2]['query_params'], {'projection': 'noAcl'})
832846

833847
def test_disable_logging(self):
834848
NAME = 'name'
835849
before = {'logging': {'logBucket': 'logs', 'logObjectPrefix': 'pfx'}}
836-
after = {'logging': None}
837-
connection = _Connection(after)
850+
resp_to_reload = before
851+
resp_to_disable_logging = {'logging': None}
852+
connection = _Connection(resp_to_reload, resp_to_disable_logging,
853+
resp_to_disable_logging) # XXX
838854
bucket = self._makeOne(connection, NAME, before)
839855
self.assertTrue(bucket.get_logging() is not None)
840856
bucket.disable_logging()
841857
self.assertTrue(bucket.get_logging() is None)
842858
kw = connection._requested
843-
self.assertEqual(len(kw), 1)
844-
self.assertEqual(kw[0]['method'], 'PATCH')
859+
self.assertEqual(len(kw), 3)
860+
self.assertEqual(kw[0]['method'], 'GET')
845861
self.assertEqual(kw[0]['path'], '/b/%s' % NAME)
846-
self.assertEqual(kw[0]['data'], {'logging': None})
847-
self.assertEqual(kw[0]['query_params'], {'projection': 'full'})
862+
self.assertEqual(kw[0]['query_params'], {'projection': 'noAcl'})
863+
self.assertEqual(kw[1]['method'], 'PATCH')
864+
self.assertEqual(kw[1]['path'], '/b/%s' % NAME)
865+
self.assertEqual(kw[1]['data'], {'logging': None})
866+
self.assertEqual(kw[1]['query_params'], {'projection': 'full'})
867+
self.assertEqual(kw[2]['method'], 'GET')
868+
self.assertEqual(kw[2]['path'], '/b/%s' % NAME)
869+
self.assertEqual(kw[2]['query_params'], {'projection': 'noAcl'})
848870

849871
def test_metageneration(self):
850872
METAGENERATION = 42
@@ -888,6 +910,7 @@ def test_versioning_enabled_getter_missing(self):
888910
NAME = 'name'
889911
connection = _Connection({})
890912
bucket = self._makeOne(connection, NAME)
913+
bucket._reload_properties() # XXX
891914
self.assertEqual(bucket.versioning_enabled, False)
892915
kw = connection._requested
893916
self.assertEqual(len(kw), 1)

0 commit comments

Comments
 (0)