Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(270)

Unified Diff: third_party/gsutil/third_party/apitools/apitools/base/py/extra_types.py

Issue 1377933002: [catapult] - Copy Telemetry's gsutilz over to third_party. (Closed) Base URL: https://github.com/catapult-project/catapult.git@master
Patch Set: Rename to gsutil. Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/gsutil/third_party/apitools/apitools/base/py/extra_types.py
diff --git a/third_party/gsutil/third_party/apitools/apitools/base/py/extra_types.py b/third_party/gsutil/third_party/apitools/apitools/base/py/extra_types.py
new file mode 100755
index 0000000000000000000000000000000000000000..68fc7160fe94bcf4f9ac130f5fec5882ea079ed3
--- /dev/null
+++ b/third_party/gsutil/third_party/apitools/apitools/base/py/extra_types.py
@@ -0,0 +1,294 @@
+#!/usr/bin/env python
+"""Extra types understood by apitools.
+
+This file will be replaced by a .proto file when we switch to proto2
+from protorpc.
+"""
+
+import collections
+import datetime
+import json
+import numbers
+
+from protorpc import message_types
+from protorpc import messages
+from protorpc import protojson
+import six
+
+from apitools.base.py import encoding
+from apitools.base.py import exceptions
+from apitools.base.py import util
+
+__all__ = [
+ 'DateField',
+ 'DateTimeMessage',
+ 'JsonArray',
+ 'JsonObject',
+ 'JsonValue',
+ 'JsonProtoEncoder',
+ 'JsonProtoDecoder',
+]
+
+# We import from protorpc.
+# pylint:disable=invalid-name
+DateTimeMessage = message_types.DateTimeMessage
+# pylint:enable=invalid-name
+
+
+class DateField(messages.Field):
+
+ """Field definition for Date values."""
+
+ # We insert our own metaclass here to avoid letting ProtoRPC
+ # register this as the default field type for strings.
+ # * since ProtoRPC does this via metaclasses, we don't have any
+ # choice but to use one ourselves
+ # * since a subclass's metaclass must inherit from its superclass's
+ # metaclass, we're forced to have this hard-to-read inheritance.
+ #
+ # pylint: disable=invalid-name
+ class __metaclass__(messages.Field.__metaclass__):
+
+ def __init__(cls, name, bases, dct):
+ super(messages.Field.__metaclass__, cls).__init__(name, bases, dct)
+ # pylint: enable=invalid-name
+
+ VARIANTS = frozenset([messages.Variant.STRING])
+ DEFAULT_VARIANT = messages.Variant.STRING
+ type = datetime.date
+
+
+def _ValidateJsonValue(json_value):
+ entries = [(f, json_value.get_assigned_value(f.name))
+ for f in json_value.all_fields()]
+ assigned_entries = [(f, value)
+ for f, value in entries if value is not None]
+ if len(assigned_entries) != 1:
+ raise exceptions.InvalidDataError(
+ 'Malformed JsonValue: %s' % json_value)
+
+
+def _JsonValueToPythonValue(json_value):
+ """Convert the given JsonValue to a json string."""
+ util.Typecheck(json_value, JsonValue)
+ _ValidateJsonValue(json_value)
+ if json_value.is_null:
+ return None
+ entries = [(f, json_value.get_assigned_value(f.name))
+ for f in json_value.all_fields()]
+ assigned_entries = [(f, value)
+ for f, value in entries if value is not None]
+ field, value = assigned_entries[0]
+ if not isinstance(field, messages.MessageField):
+ return value
+ elif field.message_type is JsonObject:
+ return _JsonObjectToPythonValue(value)
+ elif field.message_type is JsonArray:
+ return _JsonArrayToPythonValue(value)
+
+
+def _JsonObjectToPythonValue(json_value):
+ util.Typecheck(json_value, JsonObject)
+ return dict([(prop.key, _JsonValueToPythonValue(prop.value)) for prop
+ in json_value.properties])
+
+
+def _JsonArrayToPythonValue(json_value):
+ util.Typecheck(json_value, JsonArray)
+ return [_JsonValueToPythonValue(e) for e in json_value.entries]
+
+
+_MAXINT64 = 2 << 63 - 1
+_MININT64 = -(2 << 63)
+
+
+def _PythonValueToJsonValue(py_value):
+ """Convert the given python value to a JsonValue."""
+ if py_value is None:
+ return JsonValue(is_null=True)
+ if isinstance(py_value, bool):
+ return JsonValue(boolean_value=py_value)
+ if isinstance(py_value, six.string_types):
+ return JsonValue(string_value=py_value)
+ if isinstance(py_value, numbers.Number):
+ if isinstance(py_value, six.integer_types):
+ if _MININT64 < py_value < _MAXINT64:
+ return JsonValue(integer_value=py_value)
+ return JsonValue(double_value=float(py_value))
+ if isinstance(py_value, dict):
+ return JsonValue(object_value=_PythonValueToJsonObject(py_value))
+ if isinstance(py_value, collections.Iterable):
+ return JsonValue(array_value=_PythonValueToJsonArray(py_value))
+ raise exceptions.InvalidDataError(
+ 'Cannot convert "%s" to JsonValue' % py_value)
+
+
+def _PythonValueToJsonObject(py_value):
+ util.Typecheck(py_value, dict)
+ return JsonObject(
+ properties=[
+ JsonObject.Property(key=key, value=_PythonValueToJsonValue(value))
+ for key, value in py_value.items()])
+
+
+def _PythonValueToJsonArray(py_value):
+ return JsonArray(entries=list(map(_PythonValueToJsonValue, py_value)))
+
+
+class JsonValue(messages.Message):
+
+ """Any valid JSON value."""
+ # Is this JSON object `null`?
+ is_null = messages.BooleanField(1, default=False)
+
+ # Exactly one of the following is provided if is_null is False; none
+ # should be provided if is_null is True.
+ boolean_value = messages.BooleanField(2)
+ string_value = messages.StringField(3)
+ # We keep two numeric fields to keep int64 round-trips exact.
+ double_value = messages.FloatField(4, variant=messages.Variant.DOUBLE)
+ integer_value = messages.IntegerField(5, variant=messages.Variant.INT64)
+ # Compound types
+ object_value = messages.MessageField('JsonObject', 6)
+ array_value = messages.MessageField('JsonArray', 7)
+
+
+class JsonObject(messages.Message):
+
+ """A JSON object value.
+
+ Messages:
+ Property: A property of a JsonObject.
+
+ Fields:
+ properties: A list of properties of a JsonObject.
+ """
+
+ class Property(messages.Message):
+
+ """A property of a JSON object.
+
+ Fields:
+ key: Name of the property.
+ value: A JsonValue attribute.
+ """
+ key = messages.StringField(1)
+ value = messages.MessageField(JsonValue, 2)
+
+ properties = messages.MessageField(Property, 1, repeated=True)
+
+
+class JsonArray(messages.Message):
+
+ """A JSON array value."""
+ entries = messages.MessageField(JsonValue, 1, repeated=True)
+
+
+_JSON_PROTO_TO_PYTHON_MAP = {
+ JsonArray: _JsonArrayToPythonValue,
+ JsonObject: _JsonObjectToPythonValue,
+ JsonValue: _JsonValueToPythonValue,
+}
+_JSON_PROTO_TYPES = tuple(_JSON_PROTO_TO_PYTHON_MAP.keys())
+
+
+def _JsonProtoToPythonValue(json_proto):
+ util.Typecheck(json_proto, _JSON_PROTO_TYPES)
+ return _JSON_PROTO_TO_PYTHON_MAP[type(json_proto)](json_proto)
+
+
+def _PythonValueToJsonProto(py_value):
+ if isinstance(py_value, dict):
+ return _PythonValueToJsonObject(py_value)
+ if (isinstance(py_value, collections.Iterable) and
+ not isinstance(py_value, six.string_types)):
+ return _PythonValueToJsonArray(py_value)
+ return _PythonValueToJsonValue(py_value)
+
+
+def _JsonProtoToJson(json_proto, unused_encoder=None):
+ return json.dumps(_JsonProtoToPythonValue(json_proto))
+
+
+def _JsonToJsonProto(json_data, unused_decoder=None):
+ return _PythonValueToJsonProto(json.loads(json_data))
+
+
+def _JsonToJsonValue(json_data, unused_decoder=None):
+ result = _PythonValueToJsonProto(json.loads(json_data))
+ if isinstance(result, JsonValue):
+ return result
+ elif isinstance(result, JsonObject):
+ return JsonValue(object_value=result)
+ elif isinstance(result, JsonArray):
+ return JsonValue(array_value=result)
+ else:
+ raise exceptions.InvalidDataError(
+ 'Malformed JsonValue: %s' % json_data)
+
+
+# pylint:disable=invalid-name
+JsonProtoEncoder = _JsonProtoToJson
+JsonProtoDecoder = _JsonToJsonProto
+# pylint:enable=invalid-name
+encoding.RegisterCustomMessageCodec(
+ encoder=JsonProtoEncoder, decoder=_JsonToJsonValue)(JsonValue)
+encoding.RegisterCustomMessageCodec(
+ encoder=JsonProtoEncoder, decoder=JsonProtoDecoder)(JsonObject)
+encoding.RegisterCustomMessageCodec(
+ encoder=JsonProtoEncoder, decoder=JsonProtoDecoder)(JsonArray)
+
+
+def _EncodeDateTimeField(field, value):
+ result = protojson.ProtoJson().encode_field(field, value)
+ return encoding.CodecResult(value=result, complete=True)
+
+
+def _DecodeDateTimeField(unused_field, value):
+ result = protojson.ProtoJson().decode_field(
+ message_types.DateTimeField(1), value)
+ return encoding.CodecResult(value=result, complete=True)
+
+
+encoding.RegisterFieldTypeCodec(_EncodeDateTimeField, _DecodeDateTimeField)(
+ message_types.DateTimeField)
+
+
+def _EncodeInt64Field(field, value):
+ """Handle the special case of int64 as a string."""
+ capabilities = [
+ messages.Variant.INT64,
+ messages.Variant.UINT64,
+ ]
+ if field.variant not in capabilities:
+ return encoding.CodecResult(value=value, complete=False)
+
+ if field.repeated:
+ result = [str(x) for x in value]
+ else:
+ result = str(value)
+ return encoding.CodecResult(value=result, complete=True)
+
+
+def _DecodeInt64Field(unused_field, value):
+ # Don't need to do anything special, they're decoded just fine
+ return encoding.CodecResult(value=value, complete=False)
+
+encoding.RegisterFieldTypeCodec(_EncodeInt64Field, _DecodeInt64Field)(
+ messages.IntegerField)
+
+
+def _EncodeDateField(field, value):
+ """Encoder for datetime.date objects."""
+ if field.repeated:
+ result = [d.isoformat() for d in value]
+ else:
+ result = value.isoformat()
+ return encoding.CodecResult(value=result, complete=True)
+
+
+def _DecodeDateField(unused_field, value):
+ date = datetime.datetime.strptime(value, '%Y-%m-%d').date()
+ return encoding.CodecResult(value=date, complete=True)
+
+encoding.RegisterFieldTypeCodec(_EncodeDateField, _DecodeDateField)(DateField)

Powered by Google App Engine
This is Rietveld 408576698