Skip to content

Commit ebe0734

Browse files
Make deprecation transitive
1 parent b7dc7f4 commit ebe0734

File tree

6 files changed

+55
-15
lines changed

6 files changed

+55
-15
lines changed

pydsdl/_serializable/_array.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ def __init__(self, element_type: SerializableType, capacity: int):
2525
if not self.element_type.is_valid_aggregate(self):
2626
raise AggregationError("Specified element type of %r is not valid" % str(self))
2727

28+
@property
29+
def deprecated(self) -> bool:
30+
return self.element_type.deprecated
31+
2832
def is_valid_aggregate(self, aggregate: SerializableType) -> bool:
2933
# At the moment, arrays of arrays are not allowed, but this is ensured by the grammar definition.
3034
# This restriction will be lifted eventually. All that needs to be done is to update the grammar only.

pydsdl/_serializable/_composite.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class MalformedUnionError(TypeParameterError):
3939
pass
4040

4141

42-
class DeprecatedDependencyError(TypeParameterError):
42+
class DeprecatedDependencyError(AggregationError):
4343
pass
4444

4545

@@ -81,10 +81,8 @@ def __init__( # pylint: disable=too-many-arguments
8181
# Name check
8282
if not self._name:
8383
raise InvalidNameError("Composite type name cannot be empty")
84-
8584
if self.NAME_COMPONENT_SEPARATOR not in self._name:
8685
raise InvalidNameError("Root namespace is not specified")
87-
8886
if len(self._name) > self.MAX_NAME_LENGTH:
8987
# TODO
9088
# Notice that per the Specification, service request/response types are unnamed,
@@ -95,7 +93,6 @@ def __init__( # pylint: disable=too-many-arguments
9593
raise InvalidNameError(
9694
"Name is too long: %r is longer than %d characters" % (self._name, self.MAX_NAME_LENGTH)
9795
)
98-
9996
for component in self._name.split(self.NAME_COMPONENT_SEPARATOR):
10097
check_name(component)
10198

@@ -105,7 +102,6 @@ def __init__( # pylint: disable=too-many-arguments
105102
and (0 <= self._version.minor <= self.MAX_VERSION_NUMBER)
106103
and ((self._version.major + self._version.minor) > 0)
107104
)
108-
109105
if not version_valid:
110106
raise InvalidVersionError("Invalid version numbers: %s.%s" % (self._version.major, self._version.minor))
111107

@@ -132,14 +128,14 @@ def __init__( # pylint: disable=too-many-arguments
132128
# A deprecated type can be dependent on anything.
133129
if not self.deprecated:
134130
for a in self._attributes:
135-
t = a.data_type
136-
if isinstance(t, CompositeType):
137-
if t.deprecated:
138-
raise DeprecatedDependencyError(
139-
"A type cannot depend on deprecated types unless it is also deprecated."
140-
)
141-
142-
# Aggregation check. For example, types like utf8 and byte cannot be used outside of arrays.
131+
if a.data_type.deprecated:
132+
raise DeprecatedDependencyError(
133+
"A type cannot depend on deprecated types unless it is also deprecated."
134+
)
135+
136+
# Aggregation check. For example:
137+
# - Types like utf8 and byte cannot be used outside of arrays.
138+
# - A non-deprecated type cannot depend on a deprecated type.
143139
for a in self._attributes:
144140
if not a.data_type.is_valid_aggregate(self):
145141
raise AggregationError("Type of %r is not a valid field type for %s" % (str(a), self))
@@ -201,11 +197,15 @@ def bit_length_set(self) -> BitLengthSet:
201197
raise NotImplementedError
202198

203199
def is_valid_aggregate(self, aggregate: SerializableType) -> bool:
200+
if self.deprecated: # Deprecation consistency check: non-deprecated cannot depend on a deprecated type.
201+
if isinstance(aggregate, CompositeType) and not aggregate.deprecated:
202+
return False
203+
204204
return True
205205

206206
@property
207207
def deprecated(self) -> bool:
208-
"""Whether the definition is marked ``@deprecated``."""
208+
"""True if the definition is marked ``@deprecated``."""
209209
return self._deprecated
210210

211211
@property
@@ -615,6 +615,9 @@ def iterate_fields_with_offsets(
615615
base_offset = base_offset + self.delimiter_header_type.bit_length_set
616616
return self.inner_type.iterate_fields_with_offsets(base_offset)
617617

618+
def is_valid_aggregate(self, aggregate: SerializableType) -> bool:
619+
return self.inner_type.is_valid_aggregate(aggregate)
620+
618621
def __repr__(self) -> str:
619622
return "%s(inner=%r, extent=%r)" % (self.__class__.__name__, self.inner_type, self.extent)
620623

pydsdl/_serializable/_primitive.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ def __init__(self, bit_length: int, cast_mode: "PrimitiveType.CastMode"):
5151
def bit_length_set(self) -> BitLengthSet:
5252
return BitLengthSet(self.bit_length)
5353

54+
@property
55+
def deprecated(self) -> bool:
56+
"""Primitive types cannot be deprecated."""
57+
return False
58+
5459
def is_valid_aggregate(self, aggregate: SerializableType) -> bool:
5560
return True
5661

pydsdl/_serializable/_serializable.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,15 @@ def alignment_requirement(self) -> int:
6060
"""
6161
raise NotImplementedError
6262

63+
@property
64+
@abc.abstractmethod
65+
def deprecated(self) -> bool:
66+
"""
67+
Deprecation is transitive.
68+
This property is used to propagate deprecation information from the type to its aggregates.
69+
"""
70+
raise NotImplementedError
71+
6372
@abc.abstractmethod
6473
def is_valid_aggregate(self, aggregate: "SerializableType") -> bool:
6574
"""

pydsdl/_serializable/_void.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,15 @@ def __init__(self, bit_length: int):
2424
def bit_length_set(self) -> BitLengthSet:
2525
return BitLengthSet(self.bit_length)
2626

27+
@property
28+
def deprecated(self) -> bool:
29+
"""Void types cannot be deprecated."""
30+
return False
31+
2732
def is_valid_aggregate(self, aggregate: SerializableType) -> bool:
2833
from ._composite import StructureType, CompositeType
2934

30-
# Unions are not allowed to contain void types.
35+
# Unions are not allowed to contain void types. Only StructureType is allowed to do so.
3136
return isinstance(aggregate, CompositeType) and isinstance(aggregate.inner_type, StructureType)
3237

3338
@property

pydsdl/_test.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1710,6 +1710,20 @@ def _unittest_inconsistent_deprecation(wrkspc: Workspace) -> None:
17101710
[wrkspc.parse_new("ns/X.1.0.dsdl", "@deprecated\n@sealed")],
17111711
)
17121712

1713+
with raises(_error.InvalidDefinitionError, match="(?i).*depend.*deprecated.*"):
1714+
parse_definition(
1715+
wrkspc.parse_new(
1716+
"ns/C.1.0.dsdl",
1717+
dedent(
1718+
"""
1719+
X.1.0[<9] b # Ensure the deprecation property is transitive.
1720+
@sealed
1721+
"""
1722+
),
1723+
),
1724+
[wrkspc.parse_new("ns/X.1.0.dsdl", "@deprecated\n@sealed")],
1725+
)
1726+
17131727
parse_definition(
17141728
wrkspc.parse_new(
17151729
"ns/D.1.0.dsdl",

0 commit comments

Comments
 (0)