Skip to content

Commit

Permalink
Merge pull request #5 from ccpgames/feature/adding-struct
Browse files Browse the repository at this point in the history
Version 5.2.0 - Support for Structs
  • Loading branch information
CCP-Zeulix authored Sep 23, 2024
2 parents c17b15a + 0c69a0f commit 85ee496
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 7 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [5.2.0] - 2024-09-23

### Added

- Support for the `google.protobuf.Struct` message



## [5.0.0] - 2024-04-15

Expand Down
2 changes: 1 addition & 1 deletion protoplasm/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = '5.0.1'
__version__ = '5.2.0'

__author__ = 'Thordur Matthiasson <[email protected]>'
__license__ = 'MIT License'
Expand Down
19 changes: 19 additions & 0 deletions protoplasm/casting/dictators/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
'LongDictator',
'DurationDictator',
'AnyDictator',
'StructDictator',
]
import datetime
import base64
Expand Down Expand Up @@ -309,3 +310,21 @@ def from_dict_value(cls, proto_value: collections.OrderedDict,
dc_cls = castutils.import_dataclass_by_proto(proto_class)

return dict_to_dataclass(dc_cls, proto_value)


class StructDictator:
@classmethod
def to_dict_value(cls, dc_value: Dict[str, Any],
field: dataclasses.Field, parent: DataclassBase) -> Dict[str, Any]:
if dc_value is None:
return {}

return dc_value

@classmethod
def from_dict_value(cls, proto_value: Dict[str, Any],
field: dataclasses.Field, parent_type: Type[DataclassBase]) -> Optional[Dict[str, Any]]:
if proto_value is None:
return {}

return proto_value
2 changes: 1 addition & 1 deletion requirements-unittesting.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
neobuilder >=5.0, <6
neobuilder >=5.2.0-rc.1, <6
8 changes: 4 additions & 4 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
ccptools >= 1.1, <2

protobuf >=4.25.3, <5
grpcio >=1.62.1, <2
grpcio-tools >=1.62.1, <2
googleapis-common-protos >=1.63.0, <2
protobuf >=5.28.2, <6
grpcio >=1.66.1, <2
grpcio-tools >=1.66.1, <2
googleapis-common-protos >=1.65, <2
10 changes: 10 additions & 0 deletions tests/res/proto/sandbox/test/googlestruct.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
syntax = "proto3";

package sandbox.test;

import "google/protobuf/struct.proto";


message StructMessage {
google.protobuf.Struct my_struct = 1;
}
60 changes: 59 additions & 1 deletion tests/test_dictator.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@
BUILD_ROOT = os.path.join(HERE, 'res', 'build')



class ProtoToDictTest(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
# Remove old stuff...

build_package = os.path.join(BUILD_ROOT, 'sandbox')
if os.path.exists(build_package):
shutil.rmtree(build_package)
Expand Down Expand Up @@ -215,6 +215,36 @@ def test_proto_enums_to_dict(self):

self.assertEqual(expected2, dictator.proto_to_dict(p2))

def test_proto_struct_to_dict(self):
from sandbox.test import googlestruct_pb2

expected_a = {
'my_bool': True,
'my_float': 4.2,
'my_null': None,
'my_dict': {'foo': 'bar', 'you': 'tube'},
'my_list': [1.0, 3.0, 5.0, 8.0],
'my_string': 'I am String, hear me spell!',
'my_int': 42.0
}

expected_b = {
'my_struct': expected_a
}

proto_struct = googlestruct_pb2.StructMessage()
proto_struct.my_struct['my_string'] = 'I am String, hear me spell!'
proto_struct.my_struct['my_int'] = 42
proto_struct.my_struct['my_float'] = 4.2
proto_struct.my_struct['my_null'] = None
proto_struct.my_struct['my_bool'] = True
proto_struct.my_struct['my_list'] = [1, 3, 5, 8]
proto_struct.my_struct['my_dict'] = {'foo': 'bar', 'you': 'tube'}

self.assertEqual(expected_a, dictator.proto_to_dict(proto_struct.my_struct))

self.assertEqual(expected_b, dictator.proto_to_dict(proto_struct))


class DataclassToDictTest(unittest.TestCase):
@classmethod
Expand Down Expand Up @@ -423,3 +453,31 @@ def test_dataclass_enums_to_dict(self):
'default': 0}}

self.assertEqual(expected2, dictator.dataclass_to_dict(dc2))

def test_proto_struct_to_dict(self):
from sandbox.test.googlestruct_dc import StructMessage
expected_a = {
'my_bool': True,
'my_float': 4.2,
'my_null': None,
'my_dict': {'foo': 'bar', 'you': 'tube'},
'my_list': [1.0, 3.0, 5.0, 8.0],
'my_string': 'I am String, hear me spell!',
'my_int': 42.0
}

expected_b = {
'my_struct': expected_a
}

struct_dc = StructMessage(my_struct={
'my_bool': True,
'my_float': 4.2,
'my_null': None,
'my_dict': {'foo': 'bar', 'you': 'tube'},
'my_list': [1.0, 3.0, 5.0, 8.0],
'my_string': 'I am String, hear me spell!',
'my_int': 42.0
})

self.assertEqual(expected_b, dictator.dataclass_to_dict(struct_dc))
53 changes: 53 additions & 0 deletions tests/test_objectifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -663,3 +663,56 @@ def test_enum_dict_to_dataclass(self):
'default': 0}}

self.assertEqual(p_expect2, objectifier.dict_to_dataclass(enums_dc.WithInternalEnum, dict_data2))

def test_struct_dict_to_proto(self):
from sandbox.test import googlestruct_pb2

the_dict = {
'my_struct': {
'my_bool': True,
'my_float': 4.2,
'my_null': None,
'my_dict': {'foo': 'bar', 'you': 'tube'},
'my_list': [1.0, 3.0, 5.0, 8.0],
'my_string': 'I am String, hear me spell!',
'my_int': 42.0
}
}

expected_pb = googlestruct_pb2.StructMessage()
expected_pb.my_struct['my_string'] = 'I am String, hear me spell!'
expected_pb.my_struct['my_int'] = 42
expected_pb.my_struct['my_float'] = 4.2
expected_pb.my_struct['my_null'] = None
expected_pb.my_struct['my_bool'] = True
expected_pb.my_struct['my_list'] = [1, 3, 5, 8]
expected_pb.my_struct['my_dict'] = {'foo': 'bar', 'you': 'tube'}

self.assertEqual(expected_pb, objectifier.dict_to_proto(googlestruct_pb2.StructMessage, the_dict))

def test_struct_dict_to_dataclass(self):
from sandbox.test.googlestruct_dc import StructMessage

the_dict = {
'my_struct': {
'my_bool': True,
'my_float': 4.2,
'my_null': None,
'my_dict': {'foo': 'bar', 'you': 'tube'},
'my_list': [1.0, 3.0, 5.0, 8.0],
'my_string': 'I am String, hear me spell!',
'my_int': 42.0
}
}

struct_dc = StructMessage(my_struct={
'my_bool': True,
'my_float': 4.2,
'my_null': None,
'my_dict': {'foo': 'bar', 'you': 'tube'},
'my_list': [1.0, 3.0, 5.0, 8.0],
'my_string': 'I am String, hear me spell!',
'my_int': 42.0
})

self.assertEqual(struct_dc, objectifier.dict_to_dataclass(StructMessage, the_dict))

0 comments on commit 85ee496

Please sign in to comment.