structure saas with tools
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
# Copyright 2018 Google LLC
|
||||
#
|
||||
# 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
|
||||
#
|
||||
# https://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.
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,44 @@
|
||||
# Copyright (C) 2021 Google LLC
|
||||
#
|
||||
# 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 base64
|
||||
|
||||
|
||||
class BytesRule:
|
||||
"""A marshal between Python strings and protobuf bytes.
|
||||
|
||||
Note: this conversion is asymmetric because Python does have a bytes type.
|
||||
It is sometimes necessary to convert proto bytes fields to strings, e.g. for
|
||||
JSON encoding, marshalling a message to a dict. Because bytes fields can
|
||||
represent arbitrary data, bytes fields are base64 encoded when they need to
|
||||
be represented as strings.
|
||||
|
||||
It is necessary to have the conversion be bidirectional, i.e.
|
||||
my_message == MyMessage(MyMessage.to_dict(my_message))
|
||||
|
||||
To accomplish this, we need to intercept assignments from strings and
|
||||
base64 decode them back into bytes.
|
||||
"""
|
||||
|
||||
def to_python(self, value, *, absent: bool = None):
|
||||
return value
|
||||
|
||||
def to_proto(self, value):
|
||||
if isinstance(value, str):
|
||||
value = value.encode("utf-8")
|
||||
value += b"=" * (4 - len(value) % 4) # padding
|
||||
value = base64.urlsafe_b64decode(value)
|
||||
|
||||
return value
|
||||
@@ -0,0 +1,85 @@
|
||||
# Copyright 2018 Google LLC
|
||||
#
|
||||
# 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
|
||||
#
|
||||
# https://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.
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
from datetime import timezone
|
||||
|
||||
from google.protobuf import duration_pb2
|
||||
from google.protobuf import timestamp_pb2
|
||||
from proto import datetime_helpers, utils
|
||||
|
||||
|
||||
class TimestampRule:
|
||||
"""A marshal between Python datetimes and protobuf timestamps.
|
||||
|
||||
Note: Python datetimes are less precise than protobuf datetimes
|
||||
(microsecond vs. nanosecond level precision). If nanosecond-level
|
||||
precision matters, it is recommended to interact with the internal
|
||||
proto directly.
|
||||
"""
|
||||
|
||||
def to_python(
|
||||
self, value, *, absent: bool = None
|
||||
) -> datetime_helpers.DatetimeWithNanoseconds:
|
||||
if isinstance(value, timestamp_pb2.Timestamp):
|
||||
if absent:
|
||||
return None
|
||||
return datetime_helpers.DatetimeWithNanoseconds.from_timestamp_pb(value)
|
||||
return value
|
||||
|
||||
def to_proto(self, value) -> timestamp_pb2.Timestamp:
|
||||
if isinstance(value, datetime_helpers.DatetimeWithNanoseconds):
|
||||
return value.timestamp_pb()
|
||||
if isinstance(value, datetime):
|
||||
return timestamp_pb2.Timestamp(
|
||||
seconds=int(value.timestamp()),
|
||||
nanos=value.microsecond * 1000,
|
||||
)
|
||||
if isinstance(value, str):
|
||||
timestamp_value = timestamp_pb2.Timestamp()
|
||||
timestamp_value.FromJsonString(value=value)
|
||||
return timestamp_value
|
||||
return value
|
||||
|
||||
|
||||
class DurationRule:
|
||||
"""A marshal between Python timedeltas and protobuf durations.
|
||||
|
||||
Note: Python timedeltas are less precise than protobuf durations
|
||||
(microsecond vs. nanosecond level precision). If nanosecond-level
|
||||
precision matters, it is recommended to interact with the internal
|
||||
proto directly.
|
||||
"""
|
||||
|
||||
def to_python(self, value, *, absent: bool = None) -> timedelta:
|
||||
if isinstance(value, duration_pb2.Duration):
|
||||
return timedelta(
|
||||
days=value.seconds // 86400,
|
||||
seconds=value.seconds % 86400,
|
||||
microseconds=value.nanos // 1000,
|
||||
)
|
||||
return value
|
||||
|
||||
def to_proto(self, value) -> duration_pb2.Duration:
|
||||
if isinstance(value, timedelta):
|
||||
return duration_pb2.Duration(
|
||||
seconds=value.days * 86400 + value.seconds,
|
||||
nanos=value.microseconds * 1000,
|
||||
)
|
||||
if isinstance(value, str):
|
||||
duration_value = duration_pb2.Duration()
|
||||
duration_value.FromJsonString(value=value)
|
||||
return duration_value
|
||||
return value
|
||||
@@ -0,0 +1,59 @@
|
||||
# Copyright 2019 Google LLC
|
||||
#
|
||||
# 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
|
||||
#
|
||||
# https://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.
|
||||
|
||||
from typing import Type
|
||||
import enum
|
||||
import warnings
|
||||
|
||||
|
||||
class EnumRule:
|
||||
"""A marshal for converting between integer values and enum values."""
|
||||
|
||||
def __init__(self, enum_class: Type[enum.IntEnum]):
|
||||
self._enum = enum_class
|
||||
|
||||
def to_python(self, value, *, absent: bool = None):
|
||||
if isinstance(value, int) and not isinstance(value, self._enum):
|
||||
try:
|
||||
# Coerce the int on the wire to the enum value.
|
||||
return self._enum(value)
|
||||
except ValueError:
|
||||
# Since it is possible to add values to enums, we do
|
||||
# not want to flatly error on this.
|
||||
#
|
||||
# However, it is useful to make some noise about it so
|
||||
# the user realizes that an unexpected value came along.
|
||||
warnings.warn(
|
||||
"Unrecognized {name} enum value: {value}".format(
|
||||
name=self._enum.__name__,
|
||||
value=value,
|
||||
)
|
||||
)
|
||||
return value
|
||||
|
||||
def to_proto(self, value):
|
||||
# Accept enum values and coerce to the pure integer.
|
||||
# This is not strictly necessary (protocol buffers can take these
|
||||
# objects as they subclass int) but nevertheless seems like the
|
||||
# right thing to do.
|
||||
if isinstance(value, self._enum):
|
||||
return value.value
|
||||
|
||||
# If a string is provided that matches an enum value, coerce it
|
||||
# to the enum value.
|
||||
if isinstance(value, str):
|
||||
return self._enum[value].value
|
||||
|
||||
# We got a pure integer; pass it on.
|
||||
return value
|
||||
@@ -0,0 +1,36 @@
|
||||
# Copyright 2022 Google LLC
|
||||
#
|
||||
# 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
|
||||
#
|
||||
# https://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.
|
||||
|
||||
from google.protobuf import field_mask_pb2
|
||||
|
||||
|
||||
class FieldMaskRule:
|
||||
"""A marshal between FieldMask and strings.
|
||||
|
||||
See https://github.com/googleapis/proto-plus-python/issues/333
|
||||
and
|
||||
https://developers.google.com/protocol-buffers/docs/proto3#json
|
||||
for more details.
|
||||
"""
|
||||
|
||||
def to_python(self, value, *, absent: bool = None):
|
||||
return value
|
||||
|
||||
def to_proto(self, value):
|
||||
if isinstance(value, str):
|
||||
field_mask_value = field_mask_pb2.FieldMask()
|
||||
field_mask_value.FromJsonString(value=value)
|
||||
return field_mask_value
|
||||
|
||||
return value
|
||||
@@ -0,0 +1,53 @@
|
||||
# Copyright 2018 Google LLC
|
||||
#
|
||||
# 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
|
||||
#
|
||||
# https://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.
|
||||
|
||||
|
||||
class MessageRule:
|
||||
"""A marshal for converting between a descriptor and proto.Message."""
|
||||
|
||||
def __init__(self, descriptor: type, wrapper: type):
|
||||
self._descriptor = descriptor
|
||||
self._wrapper = wrapper
|
||||
|
||||
def to_python(self, value, *, absent: bool = None):
|
||||
if isinstance(value, self._descriptor):
|
||||
return self._wrapper.wrap(value)
|
||||
return value
|
||||
|
||||
def to_proto(self, value):
|
||||
if isinstance(value, self._wrapper):
|
||||
return self._wrapper.pb(value)
|
||||
if isinstance(value, dict) and not self.is_map:
|
||||
# We need to use the wrapper's marshaling to handle
|
||||
# potentially problematic nested messages.
|
||||
try:
|
||||
# Try the fast path first.
|
||||
return self._descriptor(**value)
|
||||
except (TypeError, ValueError, AttributeError) as ex:
|
||||
# If we have a TypeError, ValueError or AttributeError,
|
||||
# try the slow path in case the error
|
||||
# was:
|
||||
# - an int64/string issue.
|
||||
# - a missing key issue in case a key only exists with a `_` suffix.
|
||||
# See related issue: https://github.com/googleapis/python-api-core/issues/227.
|
||||
# - a missing key issue due to nested struct. See: https://github.com/googleapis/proto-plus-python/issues/424.
|
||||
# - a missing key issue due to nested duration. See: https://github.com/googleapis/google-cloud-python/issues/13350.
|
||||
return self._wrapper(value)._pb
|
||||
return value
|
||||
|
||||
@property
|
||||
def is_map(self):
|
||||
"""Return True if the descriptor is a map entry, False otherwise."""
|
||||
desc = self._descriptor.DESCRIPTOR
|
||||
return desc.has_options and desc.GetOptions().map_entry
|
||||
@@ -0,0 +1,71 @@
|
||||
# Copyright (C) 2021 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
from proto.primitives import ProtoType
|
||||
|
||||
|
||||
class StringyNumberRule:
|
||||
"""A marshal between certain numeric types and strings
|
||||
|
||||
This is a necessary hack to allow round trip conversion
|
||||
from messages to dicts back to messages.
|
||||
|
||||
See https://github.com/protocolbuffers/protobuf/issues/2679
|
||||
and
|
||||
https://developers.google.com/protocol-buffers/docs/proto3#json
|
||||
for more details.
|
||||
"""
|
||||
|
||||
def to_python(self, value, *, absent: bool = None):
|
||||
return value
|
||||
|
||||
def to_proto(self, value):
|
||||
if value is not None:
|
||||
return self._python_type(value)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
class Int64Rule(StringyNumberRule):
|
||||
_python_type = int
|
||||
_proto_type = ProtoType.INT64
|
||||
|
||||
|
||||
class UInt64Rule(StringyNumberRule):
|
||||
_python_type = int
|
||||
_proto_type = ProtoType.UINT64
|
||||
|
||||
|
||||
class SInt64Rule(StringyNumberRule):
|
||||
_python_type = int
|
||||
_proto_type = ProtoType.SINT64
|
||||
|
||||
|
||||
class Fixed64Rule(StringyNumberRule):
|
||||
_python_type = int
|
||||
_proto_type = ProtoType.FIXED64
|
||||
|
||||
|
||||
class SFixed64Rule(StringyNumberRule):
|
||||
_python_type = int
|
||||
_proto_type = ProtoType.SFIXED64
|
||||
|
||||
|
||||
STRINGY_NUMBER_RULES = [
|
||||
Int64Rule,
|
||||
UInt64Rule,
|
||||
SInt64Rule,
|
||||
Fixed64Rule,
|
||||
SFixed64Rule,
|
||||
]
|
||||
143
.venv/lib/python3.10/site-packages/proto/marshal/rules/struct.py
Normal file
143
.venv/lib/python3.10/site-packages/proto/marshal/rules/struct.py
Normal file
@@ -0,0 +1,143 @@
|
||||
# Copyright 2018 Google LLC
|
||||
#
|
||||
# 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
|
||||
#
|
||||
# https://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 collections.abc
|
||||
|
||||
from google.protobuf import struct_pb2
|
||||
|
||||
from proto.marshal.collections import maps
|
||||
from proto.marshal.collections import repeated
|
||||
|
||||
|
||||
class ValueRule:
|
||||
"""A rule to marshal between google.protobuf.Value and Python values."""
|
||||
|
||||
def __init__(self, *, marshal):
|
||||
self._marshal = marshal
|
||||
|
||||
def to_python(self, value, *, absent: bool = None):
|
||||
"""Coerce the given value to the appropriate Python type.
|
||||
|
||||
Note that both NullValue and absent fields return None.
|
||||
In order to disambiguate between these two options,
|
||||
use containment check,
|
||||
E.g.
|
||||
"value" in foo
|
||||
which is True for NullValue and False for an absent value.
|
||||
"""
|
||||
kind = value.WhichOneof("kind")
|
||||
if kind == "null_value" or absent:
|
||||
return None
|
||||
if kind == "bool_value":
|
||||
return bool(value.bool_value)
|
||||
if kind == "number_value":
|
||||
return float(value.number_value)
|
||||
if kind == "string_value":
|
||||
return str(value.string_value)
|
||||
if kind == "struct_value":
|
||||
return self._marshal.to_python(
|
||||
struct_pb2.Struct,
|
||||
value.struct_value,
|
||||
absent=False,
|
||||
)
|
||||
if kind == "list_value":
|
||||
return self._marshal.to_python(
|
||||
struct_pb2.ListValue,
|
||||
value.list_value,
|
||||
absent=False,
|
||||
)
|
||||
# If more variants are ever added, we want to fail loudly
|
||||
# instead of tacitly returning None.
|
||||
raise ValueError("Unexpected kind: %s" % kind) # pragma: NO COVER
|
||||
|
||||
def to_proto(self, value) -> struct_pb2.Value:
|
||||
"""Return a protobuf Value object representing this value."""
|
||||
if isinstance(value, struct_pb2.Value):
|
||||
return value
|
||||
if value is None:
|
||||
return struct_pb2.Value(null_value=0)
|
||||
if isinstance(value, bool):
|
||||
return struct_pb2.Value(bool_value=value)
|
||||
if isinstance(value, (int, float)):
|
||||
return struct_pb2.Value(number_value=float(value))
|
||||
if isinstance(value, str):
|
||||
return struct_pb2.Value(string_value=value)
|
||||
if isinstance(value, collections.abc.Sequence):
|
||||
return struct_pb2.Value(
|
||||
list_value=self._marshal.to_proto(struct_pb2.ListValue, value),
|
||||
)
|
||||
if isinstance(value, collections.abc.Mapping):
|
||||
return struct_pb2.Value(
|
||||
struct_value=self._marshal.to_proto(struct_pb2.Struct, value),
|
||||
)
|
||||
raise ValueError("Unable to coerce value: %r" % value)
|
||||
|
||||
|
||||
class ListValueRule:
|
||||
"""A rule translating google.protobuf.ListValue and list-like objects."""
|
||||
|
||||
def __init__(self, *, marshal):
|
||||
self._marshal = marshal
|
||||
|
||||
def to_python(self, value, *, absent: bool = None):
|
||||
"""Coerce the given value to a Python sequence."""
|
||||
return (
|
||||
None
|
||||
if absent
|
||||
else repeated.RepeatedComposite(value.values, marshal=self._marshal)
|
||||
)
|
||||
|
||||
def to_proto(self, value) -> struct_pb2.ListValue:
|
||||
# We got a proto, or else something we sent originally.
|
||||
# Preserve the instance we have.
|
||||
if isinstance(value, struct_pb2.ListValue):
|
||||
return value
|
||||
if isinstance(value, repeated.RepeatedComposite):
|
||||
return struct_pb2.ListValue(values=[v for v in value.pb])
|
||||
|
||||
# We got a list (or something list-like); convert it.
|
||||
return struct_pb2.ListValue(
|
||||
values=[self._marshal.to_proto(struct_pb2.Value, v) for v in value]
|
||||
)
|
||||
|
||||
|
||||
class StructRule:
|
||||
"""A rule translating google.protobuf.Struct and dict-like objects."""
|
||||
|
||||
def __init__(self, *, marshal):
|
||||
self._marshal = marshal
|
||||
|
||||
def to_python(self, value, *, absent: bool = None):
|
||||
"""Coerce the given value to a Python mapping."""
|
||||
return (
|
||||
None if absent else maps.MapComposite(value.fields, marshal=self._marshal)
|
||||
)
|
||||
|
||||
def to_proto(self, value) -> struct_pb2.Struct:
|
||||
# We got a proto, or else something we sent originally.
|
||||
# Preserve the instance we have.
|
||||
if isinstance(value, struct_pb2.Struct):
|
||||
return value
|
||||
if isinstance(value, maps.MapComposite):
|
||||
return struct_pb2.Struct(
|
||||
fields={k: v for k, v in value.pb.items()},
|
||||
)
|
||||
|
||||
# We got a dict (or something dict-like); convert it.
|
||||
answer = struct_pb2.Struct(
|
||||
fields={
|
||||
k: self._marshal.to_proto(struct_pb2.Value, v) for k, v in value.items()
|
||||
}
|
||||
)
|
||||
return answer
|
||||
@@ -0,0 +1,84 @@
|
||||
# Copyright 2018 Google LLC
|
||||
#
|
||||
# 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
|
||||
#
|
||||
# https://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.
|
||||
|
||||
from google.protobuf import wrappers_pb2
|
||||
|
||||
|
||||
class WrapperRule:
|
||||
"""A marshal for converting the protobuf wrapper classes to Python.
|
||||
|
||||
This class converts between ``google.protobuf.BoolValue``,
|
||||
``google.protobuf.StringValue``, and their siblings to the appropriate
|
||||
Python equivalents.
|
||||
|
||||
These are effectively similar to the protobuf primitives except
|
||||
that None becomes a possible value.
|
||||
"""
|
||||
|
||||
def to_python(self, value, *, absent: bool = None):
|
||||
if isinstance(value, self._proto_type):
|
||||
if absent:
|
||||
return None
|
||||
return value.value
|
||||
return value
|
||||
|
||||
def to_proto(self, value):
|
||||
if isinstance(value, self._python_type):
|
||||
return self._proto_type(value=value)
|
||||
return value
|
||||
|
||||
|
||||
class DoubleValueRule(WrapperRule):
|
||||
_proto_type = wrappers_pb2.DoubleValue
|
||||
_python_type = float
|
||||
|
||||
|
||||
class FloatValueRule(WrapperRule):
|
||||
_proto_type = wrappers_pb2.FloatValue
|
||||
_python_type = float
|
||||
|
||||
|
||||
class Int64ValueRule(WrapperRule):
|
||||
_proto_type = wrappers_pb2.Int64Value
|
||||
_python_type = int
|
||||
|
||||
|
||||
class UInt64ValueRule(WrapperRule):
|
||||
_proto_type = wrappers_pb2.UInt64Value
|
||||
_python_type = int
|
||||
|
||||
|
||||
class Int32ValueRule(WrapperRule):
|
||||
_proto_type = wrappers_pb2.Int32Value
|
||||
_python_type = int
|
||||
|
||||
|
||||
class UInt32ValueRule(WrapperRule):
|
||||
_proto_type = wrappers_pb2.UInt32Value
|
||||
_python_type = int
|
||||
|
||||
|
||||
class BoolValueRule(WrapperRule):
|
||||
_proto_type = wrappers_pb2.BoolValue
|
||||
_python_type = bool
|
||||
|
||||
|
||||
class StringValueRule(WrapperRule):
|
||||
_proto_type = wrappers_pb2.StringValue
|
||||
_python_type = str
|
||||
|
||||
|
||||
class BytesValueRule(WrapperRule):
|
||||
_proto_type = wrappers_pb2.BytesValue
|
||||
_python_type = bytes
|
||||
Reference in New Issue
Block a user