Skip to content

Commit

Permalink
Do not crash on extranous urn components (#1693)
Browse files Browse the repository at this point in the history
Store the unexpected components inside 'unexpected', e.g.,
urn:miot-spec-v2:service:device-information:00007801:yeelink-sw1:1:0000C809
spotted for `yeelink.switch.sw1`.
  • Loading branch information
rytilahti committed Jan 26, 2023
1 parent 131a555 commit 86eaf9e
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 6 deletions.
16 changes: 15 additions & 1 deletion miio/devtools/simulators/miotsimulator.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import asyncio
import json
import logging
import random
from collections import defaultdict
Expand Down Expand Up @@ -271,7 +272,20 @@ def miot_simulator(file, model):
dev = SimulatedDeviceModel.parse_raw(data)
else:
cloud = MiotCloud()
dev = SimulatedDeviceModel.parse_obj(cloud.get_model_schema(model))
try:
schema = cloud.get_model_schema(model)
except Exception as ex:
_LOGGER.error("Unable to get schema: %s" % ex)
return
try:
dev = SimulatedDeviceModel.parse_obj(schema)
except Exception as ex:
# this is far from optimal, but considering this is a developer tool it can be fixed later
fn = f"/tmp/pythonmiio_unparseable_{model}.json" # nosec
with open(fn, "w") as f:
json.dump(schema, f, indent=4)
_LOGGER.error("Unable to parse the schema, see %s: %s", fn, ex)
return

loop = asyncio.get_event_loop()
random.seed(1) # nosec
Expand Down
15 changes: 12 additions & 3 deletions miio/miot_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,19 @@


class URN(BaseModel):
"""Parsed type URN."""
"""Parsed type URN.
The expected format is urn:<namespace>:<type>:<name>:<id>:<model>:<version>.
All extraneous parts are stored inside *unexpected*.
"""

namespace: str
type: str
name: str
internal_id: str
model: str
version: int
unexpected: Optional[List[str]]

parent_urn: Optional["URN"] = Field(None, repr=False)

Expand All @@ -38,7 +43,7 @@ def validate(cls, v):
if not isinstance(v, str) or ":" not in v:
raise TypeError("invalid type")

_, namespace, type, name, id_, model, version = v.split(":")
_, namespace, type, name, id_, model, version, *unexpected = v.split(":")

return cls(
namespace=namespace,
Expand All @@ -47,12 +52,16 @@ def validate(cls, v):
internal_id=id_,
model=model,
version=version,
unexpected=unexpected if unexpected else None,
)

@property
def urn_string(self) -> str:
"""Return string presentation of the URN."""
return f"urn:{self.namespace}:{self.type}:{self.name}:{self.internal_id}:{self.model}:{self.version}"
urn = f"urn:{self.namespace}:{self.type}:{self.name}:{self.internal_id}:{self.model}:{self.version}"
if self.unexpected is not None:
urn = f"{urn}:{':'.join(self.unexpected)}"
return urn

def __repr__(self):
return f"<URN {self.urn_string} parent:{self.parent_urn}>"
Expand Down
22 changes: 20 additions & 2 deletions miio/tests/test_miot_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,26 @@ def test_action():
assert act.plain_name == "dummy-action"


def test_urn():
@pytest.mark.parametrize(
("urn_string", "unexpected"),
[
pytest.param(
"urn:namespace:type:name:41414141:dummy.model:1", None, id="regular_urn"
),
pytest.param(
"urn:namespace:type:name:41414141:dummy.model:1:unexpected",
["unexpected"],
id="unexpected_component",
),
pytest.param(
"urn:namespace:type:name:41414141:dummy.model:1:unexpected:unexpected2",
["unexpected", "unexpected2"],
id="multiple_unexpected_components",
),
],
)
def test_urn(urn_string, unexpected):
"""Test the parsing of URN strings."""
urn_string = "urn:namespace:type:name:41414141:dummy.model:1"
example_urn = f'{{"urn": "{urn_string}"}}' # noqa: B028

class Wrapper(BaseModel):
Expand All @@ -134,6 +151,7 @@ class Wrapper(BaseModel):
assert urn.internal_id == "41414141"
assert urn.model == "dummy.model"
assert urn.version == 1
assert urn.unexpected == unexpected

# Check that the serialization works
assert urn.urn_string == urn_string
Expand Down

0 comments on commit 86eaf9e

Please sign in to comment.