Skip to content

Commit

Permalink
Parking to move over to case-sensitive partition...
Browse files Browse the repository at this point in the history
  • Loading branch information
thirtytwobits committed Jun 27, 2024
1 parent 2c983b8 commit 4a6884b
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 75 deletions.
15 changes: 13 additions & 2 deletions pydsdl/_data_type_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ class MissingSerializationModeError(_error.InvalidDefinitionError):
pass


class DataTypeCollisionError(_error.InvalidDefinitionError):
"""
Raised when there are conflicting data type definitions.
"""

class DataTypeNameCollisionError(DataTypeCollisionError):
"""
Raised when type collisions are caused by naming conflicts.
"""


_logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -217,8 +228,8 @@ def resolve_versioned_data_type(self, name: str, version: _serializable.Version)
error_description += " Please make sure that you specified the directories correctly."
raise UndefinedDataTypeError(error_description)

if len(found) > 1: # pragma: no cover
raise _error.InternalError("Conflicting definitions: %r" % found)
if len(found) > 1:
raise DataTypeCollisionError("Conflicting definitions: %r" % found)

target_definition = found[0]
for visitor in self._definition_visitors:
Expand Down
83 changes: 16 additions & 67 deletions pydsdl/_namespace.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,6 @@ class RootNamespaceNameCollisionError(_error.InvalidDefinitionError):
"""


class DataTypeCollisionError(_error.InvalidDefinitionError):
"""
Raised when there are conflicting data type definitions.
"""


class DataTypeNameCollisionError(DataTypeCollisionError):
"""
Raised when there are conflicting data type names.
"""


class NestedRootNamespaceError(_error.InvalidDefinitionError):
"""
Nested root namespaces are not allowed. This exception is thrown when this rule is violated.
Expand Down Expand Up @@ -259,9 +247,6 @@ def _complete_read_function(

lookup_dsdl_definitions = _construct_dsdl_definitions_from_namespaces(lookup_directories_path_list)

# Check for collisions against the lookup definitions also.
_ensure_no_collisions(target_dsdl_definitions, lookup_dsdl_definitions)

_logger.debug("Lookup DSDL definitions are listed below:")
for x in lookup_dsdl_definitions:
_logger.debug(_LOG_LIST_ITEM_PREFIX + str(x))
Expand Down Expand Up @@ -385,44 +370,6 @@ def _construct_dsdl_definitions_from_namespaces(
return dsdl_file_sort([_dsdl_definition.DSDLDefinition(*p) for p in source_file_paths])


def _ensure_no_collisions(
target_definitions: List[DsdlFileBuildable],
lookup_definitions: List[DsdlFileBuildable],
) -> None:
for tg in target_definitions:
tg_full_namespace_period = tg.full_namespace.lower() + "."
tg_full_name_period = tg.full_name.lower() + "."
for lu in lookup_definitions:
lu_full_namespace_period = lu.full_namespace.lower() + "."
lu_full_name_period = lu.full_name.lower() + "."
# This is to allow the following messages to coexist happily:
# zubax/non_colliding/iceberg/Ice.0.1.dsdl
# zubax/non_colliding/IceB.0.1.dsdl
# The following is still not allowed:
# zubax/colliding/iceberg/Ice.0.1.dsdl
# zubax/colliding/Iceberg.0.1.dsdl
if tg.full_name != lu.full_name and tg.full_name.lower() == lu.full_name.lower():
raise DataTypeNameCollisionError(
"Full name of this definition differs from %s only by letter case, "
"which is not permitted" % lu.file_path,
path=tg.file_path,
)
if (tg_full_namespace_period).startswith(lu_full_name_period):
raise DataTypeNameCollisionError(
"The namespace of this type conflicts with %s" % lu.file_path, path=tg.file_path
)
if (lu_full_namespace_period).startswith(tg_full_name_period):
raise DataTypeNameCollisionError(
"This type conflicts with the namespace of %s" % lu.file_path, path=tg.file_path
)
if (
tg_full_name_period == lu_full_name_period
and tg.version == lu.version
and not tg.file_path.samefile(lu.file_path)
): # https://github.com/OpenCyphal/pydsdl/issues/94
raise DataTypeCollisionError("This type is redefined in %s" % lu.file_path, path=tg.file_path)


def _ensure_no_fixed_port_id_collisions(types: List[_serializable.CompositeType]) -> None:
for a in types:
for b in types:
Expand Down Expand Up @@ -864,20 +811,22 @@ def _unittest_read_files_empty_args() -> None:
assert len(transitive) == 0


def _unittest_ensure_no_collisions(temp_dsdl_factory) -> None: # type: ignore
from pytest import raises as expect_raises

# gratuitous coverage of the collision check where other tests don't cover some edge cases
def _unittest_ensure_no_namespace_name_collisions_or_nested_root_namespaces() -> None:
"""gratuitous coverage of the collision check where other tests don't cover some edge cases."""
_ensure_no_namespace_name_collisions_or_nested_root_namespaces([], False)

with expect_raises(DataTypeNameCollisionError):
_ensure_no_collisions(
[_dsdl_definition.DSDLDefinition(Path("a/b.1.0.dsdl"), Path("a"))],
[_dsdl_definition.DSDLDefinition(Path("a/B.1.0.dsdl"), Path("a"))],
)

with expect_raises(DataTypeNameCollisionError):
_ensure_no_collisions(
[_dsdl_definition.DSDLDefinition(Path("a/b/c.1.0.dsdl"), Path("a"))],
[_dsdl_definition.DSDLDefinition(Path("a/b.1.0.dsdl"), Path("a"))],
)
def _unittest_issue_104(temp_dsdl_factory) -> None: # type: ignore
"""demonstrate that removing _ensure_no_collisions is okay"""

thing_1_0 = Path("a/b/thing.1.0.dsdl")
thing_type_1_0 = Path("a/b/thing/thingtype.1.0.dsdl")

file_at_root = temp_dsdl_factory.new_file(Path("a/Nothing.1.0.dsdl"), "@sealed\n")
thing_file = temp_dsdl_factory.new_file(thing_1_0, "@sealed\na.b.thing.thingtype.1.0 thing\n")
_ = temp_dsdl_factory.new_file(thing_type_1_0, "@sealed\n")

direct, transitive = read_files(thing_file, file_at_root.parent, file_at_root.parent)

assert len(direct) == 1
assert len(transitive) == 1
12 changes: 6 additions & 6 deletions pydsdl/_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from pathlib import Path
from textwrap import dedent
import pytest # This is only safe to import in test files!
from . import _data_type_builder
from . import _expression
from . import _error
from . import _parser
Expand Down Expand Up @@ -1095,7 +1096,7 @@ def print_handler(d: Path, line: int, text: str) -> None:
"""
),
)
with raises(_namespace.DataTypeNameCollisionError):
with raises(_namespace.FixedPortIDCollisionError):
_namespace.read_namespace(
wrkspc.directory / "zubax",
[
Expand All @@ -1104,7 +1105,7 @@ def print_handler(d: Path, line: int, text: str) -> None:
)

# Do again to test single lookup-directory override
with raises(_namespace.DataTypeNameCollisionError):
with raises(_namespace.FixedPortIDCollisionError):
_namespace.read_namespace(wrkspc.directory / "zubax", wrkspc.directory / "zubax")

try:
Expand All @@ -1119,7 +1120,7 @@ def print_handler(d: Path, line: int, text: str) -> None:
"""
),
)
with raises(_namespace.DataTypeNameCollisionError, match=".*letter case.*"):
with raises(_data_type_builder.DataTypeNameCollisionError, match=".*letter case.*"):
_namespace.read_namespace(
wrkspc.directory / "zubax",
[
Expand Down Expand Up @@ -1264,8 +1265,7 @@ def _unittest_parse_namespace_versioning(wrkspc: Workspace) -> None:
),
)

with raises(_namespace.DataTypeCollisionError):
_namespace.read_namespace((wrkspc.directory / "ns"), [])
_namespace.read_namespace((wrkspc.directory / "ns"), [])

wrkspc.drop("ns/Spartans.30.2.dsdl")

Expand Down Expand Up @@ -1613,7 +1613,7 @@ def _unittest_issue94(wrkspc: Workspace) -> None:
wrkspc.new("outer_b/ns/Foo.1.0.dsdl", "@sealed") # Conflict!
wrkspc.new("outer_a/ns/Bar.1.0.dsdl", "Foo.1.0 fo\n@sealed") # Which Foo.1.0?

with raises(_namespace.DataTypeCollisionError):
with raises(_data_type_builder.DataTypeCollisionError):
_namespace.read_namespace(
wrkspc.directory / "outer_a" / "ns",
[wrkspc.directory / "outer_b" / "ns"],
Expand Down

0 comments on commit 4a6884b

Please sign in to comment.