|
37 | 37 | from gapic.utils import RESERVED_NAMES |
38 | 38 |
|
39 | 39 |
|
40 | | -@dataclasses.dataclass(frozen=True) |
| 40 | +@dataclasses.dataclass(init=False, frozen=True) |
41 | 41 | class Address: |
42 | | - name: str = '' |
43 | | - module: str = '' |
44 | | - module_path: Tuple[int, ...] = dataclasses.field(default_factory=tuple) |
45 | | - package: Tuple[str, ...] = dataclasses.field(default_factory=tuple) |
46 | | - parent: Tuple[str, ...] = dataclasses.field(default_factory=tuple) |
47 | | - api_naming: naming.Naming = dataclasses.field( |
48 | | - default_factory=naming.NewNaming, |
| 42 | + # There are lots of addresses and for large APIs they take up a lot of memory. |
| 43 | + # See |
| 44 | + # https://stackoverflow.com/questions/50180735/how-can-dataclasses-be-made-to-work-better-with-slots |
| 45 | + # for the current workaround for using slots with dataclasses. |
| 46 | + # If this becomes a common pattern (i.e. we need to reduce memory even more) |
| 47 | + # it may be worthwhile to look at https://github.com/starhel/dataslots |
| 48 | + __slots__ = ( |
| 49 | + "name", |
| 50 | + "module", |
| 51 | + "module_path", |
| 52 | + "package", |
| 53 | + "parent", |
| 54 | + "api_naming", |
| 55 | + "collisions", |
| 56 | + "_cached_values", |
49 | 57 | ) |
50 | | - collisions: FrozenSet[str] = dataclasses.field(default_factory=frozenset) |
| 58 | + name: str |
| 59 | + module: str |
| 60 | + module_path: Tuple[int, ...] |
| 61 | + package: Tuple[str, ...] |
| 62 | + parent: Tuple[str, ...] |
| 63 | + api_naming: naming.Naming |
| 64 | + collisions: FrozenSet[str] |
| 65 | + |
| 66 | + def __init__( |
| 67 | + self, |
| 68 | + name="", |
| 69 | + module="", |
| 70 | + module_path=(), |
| 71 | + package=(), |
| 72 | + parent=(), |
| 73 | + api_naming=naming.NewNaming(), |
| 74 | + collisions=frozenset(), |
| 75 | + ): |
| 76 | + super().__init__() |
| 77 | + super().__setattr__("name", name) |
| 78 | + super().__setattr__("module", module) |
| 79 | + super().__setattr__("module_path", module_path) |
| 80 | + super().__setattr__("package", package) |
| 81 | + super().__setattr__("parent", parent) |
| 82 | + super().__setattr__("api_naming", api_naming) |
| 83 | + super().__setattr__("collisions", collisions) |
51 | 84 |
|
52 | 85 | def __eq__(self, other) -> bool: |
53 | | - return all([getattr(self, i) == getattr(other, i) for i |
54 | | - in ('name', 'module', 'module_path', 'package', 'parent')]) |
| 86 | + # Ignore collisions and api_naming. |
| 87 | + # Collisions are just a name disambiguation mechanism. |
| 88 | + return all( |
| 89 | + getattr(self, i) == getattr(other, i) |
| 90 | + for i in ('name', 'module', 'module_path', 'package', 'parent') |
| 91 | + ) |
55 | 92 |
|
56 | 93 | def __hash__(self): |
57 | 94 | # Do NOT include collisions; they are not relevant. |
@@ -111,6 +148,8 @@ def module_alias(self) -> str: |
111 | 148 | while still providing names that are fundamentally readable |
112 | 149 | to users (albeit looking auto-generated). |
113 | 150 | """ |
| 151 | + # Don't keep RESERVED_NAMES in self.collisions, |
| 152 | + # just combine the two when necessary. |
114 | 153 | if self.module in self.collisions | RESERVED_NAMES: |
115 | 154 | return '_'.join( |
116 | 155 | ( |
@@ -283,12 +322,23 @@ def with_context(self, *, collisions: FrozenSet[str]) -> 'Address': |
283 | 322 | return dataclasses.replace(self, collisions=collisions) |
284 | 323 |
|
285 | 324 |
|
286 | | -@dataclasses.dataclass(frozen=True) |
| 325 | +@dataclasses.dataclass(init=False, frozen=True) |
287 | 326 | class Metadata: |
288 | | - address: Address = dataclasses.field(default_factory=Address) |
289 | | - documentation: descriptor_pb2.SourceCodeInfo.Location = dataclasses.field( |
290 | | - default_factory=descriptor_pb2.SourceCodeInfo.Location, |
291 | | - ) |
| 327 | + # See the comment for Address that describes the hoops necessary for |
| 328 | + # __slots__ with dataclasses. |
| 329 | + __slots__ = ("address", "documentation") |
| 330 | + |
| 331 | + address: Address |
| 332 | + documentation: descriptor_pb2.SourceCodeInfo.Location |
| 333 | + |
| 334 | + def __init__( |
| 335 | + self, |
| 336 | + address=Address(), |
| 337 | + documentation=descriptor_pb2.SourceCodeInfo.Location() |
| 338 | + ): |
| 339 | + super().__init__() |
| 340 | + super().__setattr__("address", address) |
| 341 | + super().__setattr__("documentation", documentation) |
292 | 342 |
|
293 | 343 | @property |
294 | 344 | def doc(self): |
|
0 commit comments