Skip to content

Commit bbde43b

Browse files
Compile well known types (#51)
* Remove lib * Add internal lib * Store the well-known types in an internal lib, not exposed to the generated files * Avoid circular imports
1 parent 3f047d8 commit bbde43b

File tree

18 files changed

+80
-3583
lines changed

18 files changed

+80
-3583
lines changed

src/betterproto2/__init__.py

Lines changed: 13 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,98 +1364,24 @@ def which_one_of(message: Message, group_name: str) -> Tuple[str, Optional[Any]]
13641364
return field_name, value
13651365

13661366

1367-
# Circular import workaround: google.protobuf depends on base classes defined above.
1368-
from .lib.google.protobuf import ( # noqa
1369-
BoolValue,
1370-
BytesValue,
1371-
DoubleValue,
1372-
Duration,
1373-
EnumValue,
1374-
FloatValue,
1375-
Int32Value,
1376-
Int64Value,
1377-
StringValue,
1378-
Timestamp,
1379-
UInt32Value,
1380-
UInt64Value,
1381-
)
1382-
1383-
1384-
class _Duration(Duration):
1385-
@classmethod
1386-
def from_timedelta(cls, delta: timedelta, *, _1_microsecond: timedelta = timedelta(microseconds=1)) -> "_Duration":
1387-
total_ms = delta // _1_microsecond
1388-
seconds = int(total_ms / 1e6)
1389-
nanos = int((total_ms % 1e6) * 1e3)
1390-
return cls(seconds, nanos)
1391-
1392-
def to_timedelta(self) -> timedelta:
1393-
return timedelta(seconds=self.seconds, microseconds=self.nanos / 1e3)
1394-
1395-
@staticmethod
1396-
def delta_to_json(delta: timedelta) -> str:
1397-
parts = str(delta.total_seconds()).split(".")
1398-
if len(parts) > 1:
1399-
while len(parts[1]) not in (3, 6, 9):
1400-
parts[1] = f"{parts[1]}0"
1401-
return f"{'.'.join(parts)}s"
1402-
1403-
1404-
class _Timestamp(Timestamp):
1405-
@classmethod
1406-
def from_datetime(cls, dt: datetime) -> "_Timestamp":
1407-
# manual epoch offset calulation to avoid rounding errors,
1408-
# to support negative timestamps (before 1970) and skirt
1409-
# around datetime bugs (apparently 0 isn't a year in [0, 9999]??)
1410-
offset = dt - DATETIME_ZERO
1411-
# below is the same as timedelta.total_seconds() but without dividing by 1e6
1412-
# so we end up with microseconds as integers instead of seconds as float
1413-
offset_us = (offset.days * 24 * 60 * 60 + offset.seconds) * 10**6 + offset.microseconds
1414-
seconds, us = divmod(offset_us, 10**6)
1415-
return cls(seconds, us * 1000)
1416-
1417-
def to_datetime(self) -> datetime:
1418-
# datetime.fromtimestamp() expects a timestamp in seconds, not microseconds
1419-
# if we pass it as a floating point number, we will run into rounding errors
1420-
# see also #407
1421-
offset = timedelta(seconds=self.seconds, microseconds=self.nanos // 1000)
1422-
return DATETIME_ZERO + offset
1423-
1424-
@staticmethod
1425-
def timestamp_to_json(dt: datetime) -> str:
1426-
nanos = dt.microsecond * 1e3
1427-
if dt.tzinfo is not None:
1428-
# change timezone aware datetime objects to utc
1429-
dt = dt.astimezone(timezone.utc)
1430-
copy = dt.replace(microsecond=0, tzinfo=None)
1431-
result = copy.isoformat()
1432-
if (nanos % 1e9) == 0:
1433-
# If there are 0 fractional digits, the fractional
1434-
# point '.' should be omitted when serializing.
1435-
return f"{result}Z"
1436-
if (nanos % 1e6) == 0:
1437-
# Serialize 3 fractional digits.
1438-
return f"{result}.{int(nanos // 1e6) :03d}Z"
1439-
if (nanos % 1e3) == 0:
1440-
# Serialize 6 fractional digits.
1441-
return f"{result}.{int(nanos // 1e3) :06d}Z"
1442-
# Serialize 9 fractional digits.
1443-
return f"{result}.{nanos:09d}"
1367+
# Avoid circular imports
1368+
from .internal_lib.google import protobuf as internal_lib_protobuf
1369+
from .internal_lib.google.protobuf import Duration as _Duration, Timestamp as _Timestamp
14441370

14451371

14461372
def _get_wrapper(proto_type: str) -> Type:
14471373
"""Get the wrapper message class for a wrapped type."""
14481374

14491375
# TODO: include ListValue and NullValue?
14501376
return {
1451-
TYPE_BOOL: BoolValue,
1452-
TYPE_BYTES: BytesValue,
1453-
TYPE_DOUBLE: DoubleValue,
1454-
TYPE_FLOAT: FloatValue,
1455-
TYPE_ENUM: EnumValue,
1456-
TYPE_INT32: Int32Value,
1457-
TYPE_INT64: Int64Value,
1458-
TYPE_STRING: StringValue,
1459-
TYPE_UINT32: UInt32Value,
1460-
TYPE_UINT64: UInt64Value,
1377+
TYPE_BOOL: internal_lib_protobuf.BoolValue,
1378+
TYPE_BYTES: internal_lib_protobuf.BytesValue,
1379+
TYPE_DOUBLE: internal_lib_protobuf.DoubleValue,
1380+
TYPE_FLOAT: internal_lib_protobuf.FloatValue,
1381+
TYPE_ENUM: internal_lib_protobuf.EnumValue,
1382+
TYPE_INT32: internal_lib_protobuf.Int32Value,
1383+
TYPE_INT64: internal_lib_protobuf.Int64Value,
1384+
TYPE_STRING: internal_lib_protobuf.StringValue,
1385+
TYPE_UINT32: internal_lib_protobuf.UInt32Value,
1386+
TYPE_UINT64: internal_lib_protobuf.UInt64Value,
14611387
}[proto_type]

src/betterproto2/lib/std/google/protobuf/__init__.py renamed to src/betterproto2/internal_lib/google/protobuf/__init__.py

Lines changed: 61 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/betterproto2/lib/google/protobuf/__init__.py

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/betterproto2/lib/google/protobuf/compiler/__init__.py

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/betterproto2/lib/pydantic/__init__.py

Whitespace-only changes.

src/betterproto2/lib/pydantic/google/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)