diff --git a/src/czml3/properties.py b/src/czml3/properties.py index 5a7779e..4cb298f 100644 --- a/src/czml3/properties.py +++ b/src/czml3/properties.py @@ -366,6 +366,7 @@ def checks(self): self.cartographicDegrees, self.cartographicRadians, self.cartesianVelocity, + self.reference, ) ) != 1 @@ -421,7 +422,9 @@ class ViewFrom(BaseCZMLObject, Interpolatable, Deletable): See `here `__ for it's definition.""" - cartesian: None | Cartesian3Value | list[float] | TimeIntervalCollection = Field() + cartesian: None | Cartesian3Value | list[float] | TimeIntervalCollection = Field( + default=None + ) """The offset specified as a three-dimensional Cartesian value [X, Y, Z]. See `here `__ for it's definition.""" reference: None | ReferenceValue | str | TimeIntervalCollection = Field( default=None @@ -442,6 +445,16 @@ def validate_reference(cls, r): return ReferenceValue(value=r) return r + @model_validator(mode="after") + def checks(self): + if self.delete: + return self + if self.cartesian is None and self.reference is None: + raise ValueError( + "ViewFrom must have either 'cartesian' or 'reference' specified" + ) + return self + class Billboard(BaseCZMLObject): """A billboard, or viewport-aligned image. The billboard is positioned in the scene by the position property. A billboard is sometimes called a marker. diff --git a/tests/test_properties.py b/tests/test_properties.py index 2c65d23..cf2ca3a 100644 --- a/tests/test_properties.py +++ b/tests/test_properties.py @@ -752,35 +752,21 @@ def test_position_cartographic_degrees(): def test_position_reference(): expected_result = """{ - "cartesian": [ - 0.0, - 0.0, - 0.0 - ], "reference": "this#satellite" }""" - pos = Position(cartesian=[0, 0, 0], reference="this#satellite") + pos = Position(reference="this#satellite") assert str(pos) == expected_result - pos = Position( - cartesian=[0, 0, 0], reference=ReferenceValue(value="this#satellite") - ) + pos = Position(reference=ReferenceValue(value="this#satellite")) assert str(pos) == expected_result def test_viewfrom_reference(): expected_result = """{ - "cartesian": [ - 1.0, - 1.0, - 1.0 - ], "reference": "this#satellite" }""" - v = ViewFrom(reference="this#satellite", cartesian=[1.0, 1.0, 1.0]) + v = ViewFrom(reference="this#satellite") assert str(v) == expected_result - v = ViewFrom( - reference=ReferenceValue(value="this#satellite"), cartesian=[1.0, 1.0, 1.0] - ) + v = ViewFrom(reference=ReferenceValue(value="this#satellite")) assert str(v) == expected_result @@ -808,7 +794,7 @@ def test_viewfrom_has_delete(): def test_viewfrom_no_values_raises_error(): with pytest.raises(ValidationError) as _: - ViewFrom() # type: ignore + ViewFrom() def test_single_interval_value(): @@ -1156,13 +1142,14 @@ def test_tileset(): def test_check_classes_with_references_ViewFrom(): assert ( - str(ViewFrom(cartesian=[0, 0, 0], reference="this#that")) + str(ViewFrom(reference="this#that")) + == """{ + "reference": "this#that" +}""" + ) + assert ( + str(ViewFrom(reference=ReferenceValue(value="this#that"))) == """{ - "cartesian": [ - 0.0, - 0.0, - 0.0 - ], "reference": "this#that" }""" ) @@ -1204,13 +1191,8 @@ def test_check_classes_with_references_ArcType(): def test_check_classes_with_references_Position(): assert ( - str(Position(cartesian=[0, 0, 0], reference="this#that")) + str(Position(reference="this#that")) == """{ - "cartesian": [ - 0.0, - 0.0, - 0.0 - ], "reference": "this#that" }""" ) @@ -1515,6 +1497,26 @@ def test_position_bad_cartesianVelocity(): Position(cartesianVelocity=[]) +def test_position_bad_multipleTypes(): + with pytest.raises(TypeError): + Position(cartesian=[0], reference=ReferenceValue(value="1#this")) + with pytest.raises(TypeError): + Position(cartographicRadians=[0], reference=ReferenceValue(value="1#this")) + with pytest.raises(TypeError): + Position(cartographicDegrees=[0], reference=ReferenceValue(value="1#this")) + with pytest.raises(TypeError): + Position(cartesianVelocity=[0], reference=ReferenceValue(value="1#this")) + + with pytest.raises(TypeError): + Position(cartesian=[0], reference="1#this") + with pytest.raises(TypeError): + Position(cartographicRadians=[0], reference="1#this") + with pytest.raises(TypeError): + Position(cartographicDegrees=[0], reference="1#this") + with pytest.raises(TypeError): + Position(cartesianVelocity=[0], reference="1#this") + + def test_no_values(): with pytest.raises(ValueError): Color(rgba=[])