diff --git a/gcloud/_helpers.py b/gcloud/_helpers.py index 342474481ea9..b78404224b37 100644 --- a/gcloud/_helpers.py +++ b/gcloud/_helpers.py @@ -19,23 +19,20 @@ import calendar import datetime import os -import six +from threading import local as Local import socket -try: - from threading import local as Local -except ImportError: # pragma: NO COVER (who doesn't have it?) - class Local(object): - """Placeholder for non-threaded applications.""" - +import six from six.moves.http_client import HTTPConnection # pylint: disable=F0401 +from gcloud.environment_vars import PROJECT + +# pylint: disable=wrong-import-position try: from google.appengine.api import app_identity except ImportError: app_identity = None - -from gcloud.environment_vars import PROJECT +# pylint: enable=wrong-import-position _NOW = datetime.datetime.utcnow # To be replaced by tests. @@ -297,7 +294,7 @@ def _to_bytes(value, encoding='ascii'): try: - from pytz import UTC # pylint: disable=unused-import + from pytz import UTC # pylint: disable=unused-import,wrong-import-position except ImportError: UTC = _UTC() # Singleton instance to be used throughout. diff --git a/gcloud/bigquery/dataset.py b/gcloud/bigquery/dataset.py index 82d60c6dfec2..d1ba43bcdca7 100644 --- a/gcloud/bigquery/dataset.py +++ b/gcloud/bigquery/dataset.py @@ -60,10 +60,13 @@ class Dataset(object): :param access_grants: roles granted to entities for this dataset """ + _access_grants = None + def __init__(self, name, client, access_grants=()): self.name = name self._client = client self._properties = {} + # Let the @property do validation. self.access_grants = access_grants @property @@ -283,7 +286,8 @@ def _require_client(self, client): client = self._client return client - def _parse_access_grants(self, access): + @staticmethod + def _parse_access_grants(access): """Parse a resource fragment into a set of access grants. :type access: list of mappings diff --git a/gcloud/bigquery/job.py b/gcloud/bigquery/job.py index 751e352e0ee7..4dd2dd8cda52 100644 --- a/gcloud/bigquery/job.py +++ b/gcloud/bigquery/job.py @@ -444,10 +444,14 @@ class LoadTableFromStorageJob(_AsyncJob): :type schema: list of :class:`gcloud.bigquery.table.SchemaField` :param schema: The job's schema """ + + _schema = None + def __init__(self, name, destination, source_uris, client, schema=()): super(LoadTableFromStorageJob, self).__init__(name, client) self.destination = destination self.source_uris = source_uris + # Let the @property do validation. self.schema = schema self._configuration = _LoadConfiguration() diff --git a/gcloud/bigquery/table.py b/gcloud/bigquery/table.py index 510f86b87cf8..45e74cebe2d3 100644 --- a/gcloud/bigquery/table.py +++ b/gcloud/bigquery/table.py @@ -72,10 +72,13 @@ class Table(object): :param schema: The table's schema """ + _schema = None + def __init__(self, name, dataset, schema=()): self.name = name self._dataset = dataset self._properties = {} + # Let the @property do validation. self.schema = schema @property diff --git a/gcloud/client.py b/gcloud/client.py index 3d7c718d0915..81a2486039fa 100644 --- a/gcloud/client.py +++ b/gcloud/client.py @@ -31,9 +31,6 @@ class _ClientFactoryMixin(object): This class is virtual. """ - def __init__(self, *args, **kwargs): - raise NotImplementedError('_ClientFactoryMixin is a virtual class') - @classmethod def from_service_account_json(cls, json_credentials_path, *args, **kwargs): """Factory to retrieve JSON credentials while creating client. diff --git a/gcloud/credentials.py b/gcloud/credentials.py index 56eca8fc6612..bfe892633aec 100644 --- a/gcloud/credentials.py +++ b/gcloud/credentials.py @@ -26,21 +26,22 @@ from oauth2client.client import _get_application_default_credential_from_file from oauth2client import crypt from oauth2client import service_account - -try: - from google.appengine.api import app_identity -except ImportError: - app_identity = None - try: from oauth2client.appengine import AppAssertionCredentials as _GAECreds except ImportError: class _GAECreds(object): """Dummy class if not in App Engine environment.""" +# pylint: disable=wrong-import-position +try: + from google.appengine.api import app_identity +except ImportError: + app_identity = None + from gcloud._helpers import UTC from gcloud._helpers import _NOW from gcloud._helpers import _microseconds_from_datetime +# pylint: enable=wrong-import-position def get_credentials(): diff --git a/gcloud/datastore/entity.py b/gcloud/datastore/entity.py index dfcfe6be1070..6b88f28cfbd7 100644 --- a/gcloud/datastore/entity.py +++ b/gcloud/datastore/entity.py @@ -92,7 +92,7 @@ def __eq__(self, other): :returns: True if the entities compare equal, else False. """ if not isinstance(other, Entity): - return NotImplemented + return False return (self.key == other.key and super(Entity, self).__eq__(other)) @@ -106,7 +106,7 @@ def __ne__(self, other): :rtype: boolean :returns: False if the entities compare equal, else True. """ - return not self == other + return not self.__eq__(other) @property def kind(self): diff --git a/gcloud/datastore/key.py b/gcloud/datastore/key.py index 14d61cfff9d3..b8033a012632 100644 --- a/gcloud/datastore/key.py +++ b/gcloud/datastore/key.py @@ -79,7 +79,7 @@ def __eq__(self, other): :returns: True if the keys compare equal, else False. """ if not isinstance(other, Key): - return NotImplemented + return False if self.is_partial or other.is_partial: return False @@ -99,7 +99,7 @@ def __ne__(self, other): :rtype: boolean :returns: False if the keys compare equal, else True. """ - return not self == other + return not self.__eq__(other) def __hash__(self): """Hash a keys for use in a dictionary lookp. diff --git a/gcloud/datastore/test_client.py b/gcloud/datastore/test_client.py index 4ca44dd84437..6890e4d0e665 100644 --- a/gcloud/datastore/test_client.py +++ b/gcloud/datastore/test_client.py @@ -677,6 +677,7 @@ def test_delete_multi_no_keys(self): client = self._makeOne(credentials=creds) result = client.delete_multi([]) self.assertEqual(result, None) + self.assertEqual(len(client.connection._commit_cw), 0) def test_delete_multi_no_batch(self): from gcloud.datastore.test_batch import _CommitResult diff --git a/gcloud/search/document.py b/gcloud/search/document.py index 5e7164c7995b..94f122b933c8 100644 --- a/gcloud/search/document.py +++ b/gcloud/search/document.py @@ -182,7 +182,8 @@ def from_api_repr(cls, resource, index): document._parse_fields_resource(resource) return document - def _parse_value_resource(self, resource): + @staticmethod + def _parse_value_resource(resource): """Helper for _parse_fields_resource""" if 'stringValue' in resource: string_format = resource.get('stringFormat') @@ -245,7 +246,8 @@ def _require_client(self, client): client = self.index._client return client - def _build_value_resource(self, value): + @staticmethod + def _build_value_resource(value): """Helper for _build_fields_resource""" result = {} if value.value_type == 'string': diff --git a/gcloud/storage/_helpers.py b/gcloud/storage/_helpers.py index 8b340df9c1a6..062a8fa205cb 100644 --- a/gcloud/storage/_helpers.py +++ b/gcloud/storage/_helpers.py @@ -17,9 +17,10 @@ These are *not* part of the API. """ -from Crypto.Hash import MD5 import base64 +from Crypto.Hash import MD5 + class _PropertyMixin(object): """Abstract mixin for cloud storage classes with associated propertties. diff --git a/gcloud/storage/batch.py b/gcloud/storage/batch.py index 94e3269c9de4..185df116ec35 100644 --- a/gcloud/storage/batch.py +++ b/gcloud/storage/batch.py @@ -20,10 +20,10 @@ from email.mime.application import MIMEApplication from email.mime.multipart import MIMEMultipart from email.parser import Parser -import httplib2 import io import json +import httplib2 import six from gcloud.exceptions import make_exception diff --git a/gcloud/storage/test__helpers.py b/gcloud/storage/test__helpers.py index e9bca19032d0..2399e4921f3f 100644 --- a/gcloud/storage/test__helpers.py +++ b/gcloud/storage/test__helpers.py @@ -28,6 +28,8 @@ def _derivedClass(self, path=None): class Derived(self._getTargetClass()): + client = None + @property def path(self): return path diff --git a/gcloud/streaming/transfer.py b/gcloud/streaming/transfer.py index 5f8e630cee04..48b8bad53488 100644 --- a/gcloud/streaming/transfer.py +++ b/gcloud/streaming/transfer.py @@ -52,6 +52,9 @@ class _Transfer(object): :type num_retries: integer :param num_retries: how many retries should the transfer attempt """ + + _num_retries = None + def __init__(self, stream, close_stream=False, chunksize=_DEFAULT_CHUNKSIZE, auto_transfer=True, http=None, num_retries=5): @@ -61,7 +64,7 @@ def __init__(self, stream, close_stream=False, self._stream = stream self._url = None - # Let the @property do validation + # Let the @property do validation. self.num_retries = num_retries self.auto_transfer = auto_transfer @@ -385,7 +388,8 @@ def _normalize_start_end(self, start, end=None): start = max(0, start + self.total_size) return start, self.total_size - 1 - def _set_range_header(self, request, start, end=None): + @staticmethod + def _set_range_header(request, start, end=None): """Update the 'Range' header in a request to match a byte range. :type request: :class:`gcloud.streaming.http_wrapper.Request` @@ -915,7 +919,8 @@ def refresh_upload_state(self): else: raise HttpError.from_response(refresh_response) - def _get_range_header(self, response): + @staticmethod + def _get_range_header(response): """Return a 'Range' header from a response. :type response: :class:`gcloud.streaming.http_wrapper.Response` @@ -975,7 +980,8 @@ def initialize_upload(self, http_request, http): else: return http_response - def _last_byte(self, range_header): + @staticmethod + def _last_byte(range_header): """Parse the last byte from a 'Range' header. :type range_header: string diff --git a/gcloud/test_client.py b/gcloud/test_client.py index 0ae2ef62e88f..3caa9d1fd251 100644 --- a/gcloud/test_client.py +++ b/gcloud/test_client.py @@ -21,11 +21,9 @@ def _getTargetClass(self): from gcloud.client import _ClientFactoryMixin return _ClientFactoryMixin - def _makeOne(self, *args, **kw): - return self._getTargetClass()(*args, **kw) - def test_virtual(self): - self.assertRaises(NotImplementedError, self._makeOne) + klass = self._getTargetClass() + self.assertFalse('__init__' in klass.__dict__) class TestClient(unittest2.TestCase): diff --git a/gcloud/test_exceptions.py b/gcloud/test_exceptions.py index d42f8ebef900..bef2541b5375 100644 --- a/gcloud/test_exceptions.py +++ b/gcloud/test_exceptions.py @@ -21,8 +21,8 @@ def _getTargetClass(self): from gcloud.exceptions import GCloudError return GCloudError - def _makeOne(self, *args): - return self._getTargetClass()(*args) + def _makeOne(self, message, errors=()): + return self._getTargetClass()(message, errors=errors) def test_ctor_defaults(self): e = self._makeOne('Testing') diff --git a/pylintrc_default b/pylintrc_default index 11c7b3a77768..27c4b5db9f2d 100644 --- a/pylintrc_default +++ b/pylintrc_default @@ -80,6 +80,11 @@ load-plugins=pylint.extensions.check_docs # @_lazy_property_deco # def dataset_id(): # ... +# - redefined-variable-type: This error is overzealous and complains at e.g. +# if some_prop: +# return int(value) +# else: +# return float(value) disable = maybe-no-member, no-member, @@ -88,6 +93,7 @@ disable = similarities, star-args, method-hidden, + redefined-variable-type, [REPORTS] diff --git a/run_pylint.py b/run_pylint.py index 267fa504e778..1ba6f0601015 100644 --- a/run_pylint.py +++ b/run_pylint.py @@ -51,6 +51,8 @@ 'too-many-locals', 'too-many-public-methods', 'unbalanced-tuple-unpacking', + 'arguments-differ', + 'assignment-from-no-return', ] TEST_RC_ADDITIONS = { 'MESSAGES CONTROL': { diff --git a/system_tests/storage.py b/system_tests/storage.py index 685412a7b83c..dcf02d72e1d7 100644 --- a/system_tests/storage.py +++ b/system_tests/storage.py @@ -12,11 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -import httplib2 import os -import six import tempfile import time + +import httplib2 +import six import unittest2 from gcloud import _helpers diff --git a/tox.ini b/tox.ini index 147dd6e36ae9..e92ace71f129 100644 --- a/tox.ini +++ b/tox.ini @@ -75,8 +75,7 @@ commands = python run_pylint.py deps = pep8 - -ehg+https://bitbucket.org/logilab/pylint@33e334be064c#egg=pylint - logilab-common<=0.63.0 # Hack for pylint upstream + pylint unittest2 protobuf==3.0.0-alpha-1 passenv = {[testenv:system-tests]passenv}