Skip to content
This repository was archived by the owner on Apr 1, 2026. It is now read-only.

Commit 7e34d3c

Browse files
committed
Added template directory + changed unit tests to pytest
1 parent 7251258 commit 7e34d3c

5 files changed

Lines changed: 148 additions & 115 deletions

File tree

gapic_templates/README.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
GAPIC Templates
2+
===============
3+
4+
This directory is intended for inserting handwritten files
5+
into autogenerated directories (see `owlbot.py`). In particular,
6+
it is needed for inserting the definition of `OneofMessage` into
7+
`google/cloud/bigtable/admin_v2/types` to prevent circular import
8+
issues with having something in that directory import from
9+
`google/cloud/bigtable/admin_v2/overlay`.

google/cloud/bigtable/admin_v2/overlay/types/oneof_message.py renamed to gapic_templates/admin_v2/types/oneof_message.py.j2

File renamed without changes.

google/cloud/bigtable/admin_v2/types/table.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919

2020
import proto # type: ignore
2121

22-
from google.cloud.bigtable.admin_v2.types import types, oneof_message
22+
from google.cloud.bigtable.admin_v2.types import types
23+
from google.cloud.bigtable.admin_v2.types import oneof_message
2324
from google.protobuf import duration_pb2 # type: ignore
2425
from google.protobuf import timestamp_pb2 # type: ignore
2526
from google.rpc import status_pb2 # type: ignore

owlbot.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@
2020
from typing import List, Optional
2121

2222
import synthtool as s
23-
from synthtool import gcp
23+
from synthtool import gcp, _tracked_paths
2424
from synthtool.languages import python
25+
from synthtool.sources import templates
2526

2627
common = gcp.CommonTemplates()
2728

@@ -238,11 +239,26 @@ def add_overlay_to_init_py(init_py_location, import_statements):
238239
"""
239240
)
240241

242+
# Oneofs work:
243+
244+
# Move the definition of a oneof message into the autogenerated types
245+
# directory. This is needed to prevent circular import issues in admin_v2/overlay.
246+
# This can also be used to insert other files into other autogenerated directories.
247+
gapic_templates = templates.TemplateGroup("gapic_templates")
248+
_tracked_paths.add(gapic_templates.dir)
249+
gapic_templated_files = gapic_templates.render()
250+
s.move(
251+
gapic_templated_files,
252+
destination="google/cloud/bigtable",
253+
excludes=["README.rst"],
254+
)
255+
241256
# Add the oneof_message import into table.py for GcRule
242257
s.replace(
243258
"google/cloud/bigtable/admin_v2/types/table.py",
244-
r"from google\.cloud\.bigtable\.admin_v2\.types import types",
245-
"from google.cloud.bigtable.admin_v2.types import types, oneof_message",
259+
r"^(from google\.cloud\.bigtable\.admin_v2\.types import .+)$",
260+
r"""\1
261+
from google.cloud.bigtable.admin_v2.types import oneof_message""",
246262
)
247263

248264
# Re-subclass GcRule in table.py

tests/unit/admin_overlay/test_oneof_message.py

Lines changed: 118 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818

1919
import my_oneof_message
2020

21-
import unittest
21+
import pytest
22+
2223

2324
# The following proto bytestring was constructed running printproto in
2425
# text-to-binary mode on the following textproto for GcRule:
@@ -37,120 +38,126 @@
3738
INITIAL_VALUE = 123
3839
FINAL_VALUE = 456
3940

41+
@pytest.fixture
42+
def default_msg():
43+
return my_oneof_message.MyOneofMessage()
4044

41-
class TestGenericOneofMessage(unittest.TestCase):
42-
def setUp(self):
43-
self.default_msg = my_oneof_message.MyOneofMessage()
44-
self.foo_msg = my_oneof_message.MyOneofMessage(foo=INITIAL_VALUE)
45-
46-
def test_setattr_oneof_no_conflict(self):
47-
self.default_msg.foo = INITIAL_VALUE
48-
self.default_msg.baz = INITIAL_VALUE
49-
self.assertEqual(self.default_msg.foo, INITIAL_VALUE)
50-
self.assertEqual(self.default_msg.baz, INITIAL_VALUE)
51-
self.assertFalse(self.default_msg.bar)
52-
53-
def test_setattr_oneof_conflict(self):
54-
with self.assertRaises(ValueError):
55-
self.foo_msg.bar = INITIAL_VALUE
56-
self.assertEqual(self.foo_msg.foo, INITIAL_VALUE)
57-
self.assertFalse(self.foo_msg.bar)
58-
59-
self.default_msg.bar = INITIAL_VALUE
60-
with self.assertRaises(ValueError):
61-
self.default_msg.foo = INITIAL_VALUE
62-
self.assertEqual(self.default_msg.bar, INITIAL_VALUE)
63-
self.assertFalse(self.default_msg.foo)
64-
65-
def test_setattr_oneof_same_oneof_field(self):
66-
self.foo_msg.foo = FINAL_VALUE
67-
self.assertEqual(self.foo_msg.foo, FINAL_VALUE)
68-
self.assertFalse(self.foo_msg.bar)
69-
70-
self.default_msg.foo = INITIAL_VALUE
71-
self.default_msg.foo = FINAL_VALUE
72-
self.assertEqual(self.default_msg.foo, FINAL_VALUE)
73-
74-
def test_setattr_oneof_delattr(self):
75-
del self.foo_msg.foo
76-
self.foo_msg.bar = INITIAL_VALUE
77-
self.assertEqual(self.foo_msg.bar, INITIAL_VALUE)
78-
self.assertFalse(self.foo_msg.foo)
79-
80-
def test_init_oneof_conflict(self):
81-
with self.assertRaises(ValueError):
82-
my_oneof_message.MyOneofMessage(foo=INITIAL_VALUE, bar=INITIAL_VALUE)
83-
84-
with self.assertRaises(ValueError):
85-
my_oneof_message.MyOneofMessage(
86-
{
87-
"foo": INITIAL_VALUE,
88-
"bar": INITIAL_VALUE,
89-
}
90-
)
91-
92-
with self.assertRaises(ValueError):
93-
my_oneof_message.MyOneofMessage(self.foo_msg._pb, bar=INITIAL_VALUE)
94-
95-
with self.assertRaises(ValueError):
96-
my_oneof_message.MyOneofMessage(self.foo_msg, bar=INITIAL_VALUE)
97-
98-
def test_init_oneof_no_conflict(self):
99-
msg = my_oneof_message.MyOneofMessage(foo=INITIAL_VALUE, baz=INITIAL_VALUE)
100-
self.assertEqual(msg.foo, INITIAL_VALUE)
101-
self.assertEqual(msg.baz, INITIAL_VALUE)
102-
self.assertFalse(msg.bar)
103-
104-
msg = my_oneof_message.MyOneofMessage(
105-
{
106-
"foo": INITIAL_VALUE,
107-
"baz": INITIAL_VALUE,
108-
}
109-
)
110-
self.assertEqual(msg.foo, INITIAL_VALUE)
111-
self.assertEqual(msg.baz, INITIAL_VALUE)
112-
self.assertFalse(msg.bar)
113-
114-
msg = my_oneof_message.MyOneofMessage(self.foo_msg, baz=INITIAL_VALUE)
115-
self.assertEqual(msg.foo, INITIAL_VALUE)
116-
self.assertEqual(msg.baz, INITIAL_VALUE)
117-
self.assertFalse(msg.bar)
118-
119-
msg = my_oneof_message.MyOneofMessage(self.foo_msg._pb, baz=INITIAL_VALUE)
120-
self.assertEqual(msg.foo, INITIAL_VALUE)
121-
self.assertEqual(msg.baz, INITIAL_VALUE)
122-
self.assertFalse(msg.bar)
123-
124-
def test_init_kwargs_override_same_field_oneof(self):
125-
# Kwargs take precedence over mapping, and this should be OK
126-
msg = my_oneof_message.MyOneofMessage(
127-
{
128-
"foo": INITIAL_VALUE,
129-
},
130-
foo=FINAL_VALUE,
131-
)
132-
self.assertEqual(msg.foo, FINAL_VALUE)
13345

134-
msg = my_oneof_message.MyOneofMessage(self.foo_msg, foo=FINAL_VALUE)
135-
self.assertEqual(msg.foo, FINAL_VALUE)
46+
@pytest.fixture
47+
def foo_msg():
48+
return my_oneof_message.MyOneofMessage(foo=INITIAL_VALUE)
13649

137-
msg = my_oneof_message.MyOneofMessage(self.foo_msg._pb, foo=FINAL_VALUE)
138-
self.assertEqual(msg.foo, FINAL_VALUE)
13950

51+
def test_oneof_message_setattr_oneof_no_conflict(default_msg):
52+
default_msg.foo = INITIAL_VALUE
53+
default_msg.baz = INITIAL_VALUE
54+
assert default_msg.foo == INITIAL_VALUE
55+
assert default_msg.baz == INITIAL_VALUE
56+
assert not default_msg.bar
57+
58+
59+
def test_oneof_message_setattr_conflict(default_msg, foo_msg):
60+
with pytest.raises(ValueError):
61+
foo_msg.bar = INITIAL_VALUE
62+
assert foo_msg.foo == INITIAL_VALUE
63+
assert not foo_msg.bar
64+
65+
default_msg.bar = INITIAL_VALUE
66+
with pytest.raises(ValueError):
67+
default_msg.foo = INITIAL_VALUE
68+
assert default_msg.bar == INITIAL_VALUE
69+
assert not default_msg.foo
14070

141-
class TestGcRule(unittest.TestCase):
142-
def test_serialize_deserialize(self):
143-
test = GcRule(
144-
intersection=GcRule.Intersection(
145-
rules=[
146-
GcRule(max_num_versions=1234),
147-
GcRule(max_age=duration_pb2.Duration(seconds=12345)),
148-
]
149-
)
150-
)
151-
self.assertEqual(GcRule.serialize(test), GCRULE_RAW_PROTO_BYTESTRING)
152-
self.assertEqual(GcRule.deserialize(GCRULE_RAW_PROTO_BYTESTRING), test)
15371

72+
def test_oneof_message_setattr_oneof_same_oneof_field(default_msg, foo_msg):
73+
foo_msg.foo = FINAL_VALUE
74+
assert foo_msg.foo == FINAL_VALUE
75+
assert not foo_msg.bar
15476

155-
if __name__ == "__main__":
156-
unittest.main()
77+
default_msg.bar = INITIAL_VALUE
78+
default_msg.bar = FINAL_VALUE
79+
assert default_msg.bar == FINAL_VALUE
80+
assert not default_msg.foo
81+
82+
83+
def test_oneof_message_setattr_oneof_delattr(foo_msg):
84+
del foo_msg.foo
85+
foo_msg.bar = INITIAL_VALUE
86+
assert foo_msg.bar == INITIAL_VALUE
87+
assert not foo_msg.foo
88+
89+
90+
def test_oneof_message_init_oneof_conflict(foo_msg):
91+
with pytest.raises(ValueError):
92+
my_oneof_message.MyOneofMessage(foo=INITIAL_VALUE, bar=INITIAL_VALUE)
93+
94+
with pytest.raises(ValueError):
95+
my_oneof_message.MyOneofMessage(
96+
{
97+
"foo": INITIAL_VALUE,
98+
"bar": INITIAL_VALUE,
99+
}
100+
)
101+
102+
with pytest.raises(ValueError):
103+
my_oneof_message.MyOneofMessage(foo_msg._pb, bar=INITIAL_VALUE)
104+
105+
with pytest.raises(ValueError):
106+
my_oneof_message.MyOneofMessage(foo_msg, bar=INITIAL_VALUE)
107+
108+
109+
def test_oneof_message_init_oneof_no_conflict(foo_msg):
110+
msg = my_oneof_message.MyOneofMessage(foo=INITIAL_VALUE, baz=INITIAL_VALUE)
111+
assert msg.foo == INITIAL_VALUE
112+
assert msg.baz == INITIAL_VALUE
113+
assert not msg.bar
114+
115+
msg = my_oneof_message.MyOneofMessage(
116+
{
117+
"foo": INITIAL_VALUE,
118+
"baz": INITIAL_VALUE,
119+
}
120+
)
121+
assert msg.foo == INITIAL_VALUE
122+
assert msg.baz == INITIAL_VALUE
123+
assert not msg.bar
124+
125+
msg = my_oneof_message.MyOneofMessage(foo_msg, baz=INITIAL_VALUE)
126+
assert msg.foo == INITIAL_VALUE
127+
assert msg.baz == INITIAL_VALUE
128+
assert not msg.bar
129+
130+
msg = my_oneof_message.MyOneofMessage(foo_msg._pb, baz=INITIAL_VALUE)
131+
assert msg.foo == INITIAL_VALUE
132+
assert msg.baz == INITIAL_VALUE
133+
assert not msg.bar
134+
135+
136+
def test_oneof_message_init_kwargs_override_same_field_oneof(foo_msg):
137+
# Kwargs take precedence over mapping, and this should be OK
138+
msg = my_oneof_message.MyOneofMessage(
139+
{
140+
"foo": INITIAL_VALUE,
141+
},
142+
foo=FINAL_VALUE,
143+
)
144+
assert msg.foo == FINAL_VALUE
145+
146+
msg = my_oneof_message.MyOneofMessage(foo_msg, foo=FINAL_VALUE)
147+
assert msg.foo == FINAL_VALUE
148+
149+
msg = my_oneof_message.MyOneofMessage(foo_msg._pb, foo=FINAL_VALUE)
150+
assert msg.foo == FINAL_VALUE
151+
152+
153+
def test_gcrule_serialize_deserialize():
154+
test = GcRule(
155+
intersection=GcRule.Intersection(
156+
rules=[
157+
GcRule(max_num_versions=1234),
158+
GcRule(max_age=duration_pb2.Duration(seconds=12345)),
159+
]
160+
)
161+
)
162+
assert GcRule.serialize(test) == GCRULE_RAW_PROTO_BYTESTRING
163+
assert GcRule.deserialize(GCRULE_RAW_PROTO_BYTESTRING) == test

0 commit comments

Comments
 (0)