Skip to content

Commit

Permalink
Fix filter dumps (#1422)
Browse files Browse the repository at this point in the history
  • Loading branch information
haakonvt authored Oct 12, 2023
1 parent c54fbc6 commit 4cff041
Show file tree
Hide file tree
Showing 14 changed files with 55 additions and 34 deletions.
8 changes: 6 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ Changes are grouped as follows
- `Fixed` for any bug fixes.
- `Security` in case of vulnerabilities.

## [6.32.3] - 2023-10-06
## [6.32.4] - 2023-10-12
### Fixed
- Filters using e.g. metadata keys no longer dumps the key in camel case.

## [6.32.3] - 2023-10-12
### Added
- Ability to toggle the SDK debug logging on/off by setting `config.debug` property on a CogniteClient to True (enable) or False (disable).

Expand All @@ -30,7 +34,7 @@ Changes are grouped as follows
### Added
- Missing `unit_external_id` and `unit_quantity` fields on `TimeSeriesProperty`.

## [6.32.0] - 2023-10-10
## [6.32.0] - 2023-10-09
### Fixed
- Ref to openapi doc in Vision extract docstring
- Parameters to Vision models can be given as Python dict (updated doc accordingly).
Expand Down
4 changes: 1 addition & 3 deletions cognite/client/_api/datapoints_subscriptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
from typing import TYPE_CHECKING, Iterator, Sequence

from cognite.client._api_client import APIClient
from cognite.client._constants import (
DEFAULT_LIMIT_READ,
)
from cognite.client._constants import DEFAULT_LIMIT_READ
from cognite.client.data_classes.datapoints_subscriptions import (
DatapointSubscription,
DatapointSubscriptionBatch,
Expand Down
2 changes: 1 addition & 1 deletion cognite/client/_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from __future__ import annotations

__version__ = "6.32.3"
__version__ = "6.32.4"
__api_subversion__ = "V20220125"
5 changes: 5 additions & 0 deletions cognite/client/data_classes/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,11 @@ def dump(self, camel_case: bool = False) -> dict[str, Any]:
T_CogniteFilter = TypeVar("T_CogniteFilter", bound=CogniteFilter)


class NoCaseConversionPropertyList(list):
def as_reference(self) -> list[str]:
return list(self)


class EnumProperty(Enum):
@staticmethod
def _generate_next_value_(name: str, *_: Any) -> str:
Expand Down
5 changes: 3 additions & 2 deletions cognite/client/data_classes/assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
CogniteUpdate,
EnumProperty,
IdTransformerMixin,
NoCaseConversionPropertyList,
PropertySpec,
)
from cognite.client.data_classes.labels import Label, LabelDefinition, LabelFilter
Expand Down Expand Up @@ -889,7 +890,7 @@ class AssetProperty(EnumProperty):

@staticmethod
def metadata_key(key: str) -> list[str]:
return ["metadata", key]
return NoCaseConversionPropertyList(["metadata", key])


AssetPropertyLike: TypeAlias = Union[AssetProperty, str, List[str]]
Expand All @@ -907,7 +908,7 @@ class SortableAssetProperty(EnumProperty):

@staticmethod
def metadata_key(key: str) -> list[str]:
return ["metadata", key]
return NoCaseConversionPropertyList(["metadata", key])


SortableAssetPropertyLike: TypeAlias = Union[SortableAssetProperty, str, List[str]]
Expand Down
3 changes: 2 additions & 1 deletion cognite/client/data_classes/datapoints_subscriptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
CogniteResourceList,
CogniteUpdate,
EnumProperty,
NoCaseConversionPropertyList,
PropertySpec,
T_CogniteResource,
)
Expand Down Expand Up @@ -361,7 +362,7 @@ class DatapointSubscriptionList(CogniteResourceList[DatapointSubscription]):


def _metadata(key: str) -> list[str]:
return ["metadata", key]
return NoCaseConversionPropertyList(["metadata", key])


class DatapointSubscriptionFilterProperties(EnumProperty):
Expand Down
3 changes: 2 additions & 1 deletion cognite/client/data_classes/documents.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
CogniteSort,
EnumProperty,
IdTransformerMixin,
NoCaseConversionPropertyList,
)
from cognite.client.data_classes.aggregations import UniqueResult
from cognite.client.data_classes.labels import Label, LabelDefinition
Expand Down Expand Up @@ -283,7 +284,7 @@ class SourceFileProperty(EnumProperty):

@staticmethod
def metadata_key(key: str) -> list[str]:
return ["sourceFile", "metadata", key]
return NoCaseConversionPropertyList(["sourceFile", "metadata", key])

def as_reference(self) -> list[str]:
return ["sourceFile", self.value]
Expand Down
5 changes: 3 additions & 2 deletions cognite/client/data_classes/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
CogniteUpdate,
EnumProperty,
IdTransformerMixin,
NoCaseConversionPropertyList,
PropertySpec,
)
from cognite.client.data_classes.shared import TimestampRange
Expand Down Expand Up @@ -271,7 +272,7 @@ class EventProperty(EnumProperty):

@staticmethod
def metadata_key(key: str) -> list[str]:
return ["metadata", key]
return NoCaseConversionPropertyList(["metadata", key])


EventPropertyLike: TypeAlias = Union[EventProperty, str, List[str]]
Expand All @@ -292,7 +293,7 @@ class SortableEventProperty(EnumProperty):

@staticmethod
def metadata_key(key: str) -> list[str]:
return ["metadata", key]
return NoCaseConversionPropertyList(["metadata", key])


SortableEventPropertyLike: TypeAlias = Union[SortableEventProperty, str, List[str]]
Expand Down
25 changes: 11 additions & 14 deletions cognite/client/data_classes/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from typing_extensions import TypeAlias

from cognite.client.data_classes._base import EnumProperty, Geometry
from cognite.client.data_classes._base import EnumProperty, Geometry, NoCaseConversionPropertyList
from cognite.client.data_classes.labels import Label
from cognite.client.utils._text import to_camel_case

Expand Down Expand Up @@ -35,35 +35,32 @@ class ParameterValue:

def _dump_filter_value(filter_value: FilterValueList | FilterValue) -> Any:
if isinstance(filter_value, PropertyReferenceValue):
return {
"property": filter_value.property.as_reference()
if isinstance(filter_value.property, EnumProperty)
else filter_value.property
}
if isinstance(filter_value.property, EnumProperty):
return {"property": filter_value.property.as_reference()}
return {"property": filter_value.property}

if isinstance(filter_value, ParameterValue):
return {"parameter": filter_value.parameter}
else:
return filter_value
return filter_value


def _load_filter_value(value: Any) -> FilterValue | FilterValueList:
if isinstance(value, Mapping) and len(value.keys()) == 1:
(value_key,) = value
((value_key, to_load),) = value.items()
if value_key == "property":
return PropertyReferenceValue(value[value_key])
return PropertyReferenceValue(to_load)
if value_key == "parameter":
return ParameterValue(value[value_key])
return ParameterValue(to_load)
return value


def _dump_property(property_: PropertyReference, camel_case: bool) -> list[str] | tuple[str, ...]:
if isinstance(property_, EnumProperty):
if isinstance(property_, (EnumProperty, NoCaseConversionPropertyList)):
return property_.as_reference()
elif isinstance(property_, str):
return [to_camel_case(property_) if camel_case else property_]
elif isinstance(property_, (list, tuple)):
output = [to_camel_case(p) if camel_case else p for p in property_]
return tuple(output) if isinstance(property_, tuple) else output
return type(property_)(map(to_camel_case, property_)) if camel_case else property_
else:
raise ValueError(f"Invalid property format {property_}")

Expand Down
5 changes: 3 additions & 2 deletions cognite/client/data_classes/sequences.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
CogniteUpdate,
EnumProperty,
IdTransformerMixin,
NoCaseConversionPropertyList,
PropertySpec,
)
from cognite.client.data_classes.shared import TimestampRange
Expand Down Expand Up @@ -493,7 +494,7 @@ class SequenceProperty(EnumProperty):

@staticmethod
def metadata_key(key: str) -> list[str]:
return ["metadata", key]
return NoCaseConversionPropertyList(["metadata", key])


class SortableSequenceProperty(EnumProperty):
Expand All @@ -507,7 +508,7 @@ class SortableSequenceProperty(EnumProperty):

@staticmethod
def metadata_key(key: str) -> list[str]:
return ["metadata", key]
return NoCaseConversionPropertyList(["metadata", key])


SortableSequencePropertyLike: TypeAlias = Union[SortableSequenceProperty, str, List[str]]
Expand Down
5 changes: 3 additions & 2 deletions cognite/client/data_classes/time_series.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
CogniteUpdate,
EnumProperty,
IdTransformerMixin,
NoCaseConversionPropertyList,
PropertySpec,
)
from cognite.client.data_classes.shared import TimestampRange
Expand Down Expand Up @@ -340,7 +341,7 @@ class TimeSeriesProperty(EnumProperty):

@staticmethod
def metadata_key(key: str) -> list[str]:
return ["metadata", key]
return NoCaseConversionPropertyList(["metadata", key])


class SortableTimeSeriesProperty(EnumProperty):
Expand All @@ -354,7 +355,7 @@ class SortableTimeSeriesProperty(EnumProperty):

@staticmethod
def metadata_key(key: str) -> list[str]:
return ["metadata", key]
return NoCaseConversionPropertyList(["metadata", key])


SortableTimeSeriesPropertyLike: TypeAlias = Union[SortableTimeSeriesProperty, str, List[str]]
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[tool.poetry]
name = "cognite-sdk"

version = "6.32.3"
version = "6.32.4"
description = "Cognite Python SDK"
readme = "README.md"
documentation = "https://cognite-sdk-python.readthedocs-hosted.com"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
from _pytest.mark import ParameterSet

import cognite.client.data_classes.filters as f
from cognite.client.data_classes._base import EnumProperty
from cognite.client.data_classes.filters import Filter
from tests.utils import all_subclasses


def load_and_dump_equals_data() -> Iterator[ParameterSet]:
Expand Down Expand Up @@ -97,9 +99,7 @@ def load_and_dump_equals_data() -> Iterator[ParameterSet]:
@pytest.mark.parametrize("raw_data", list(load_and_dump_equals_data()))
def test_load_and_dump_equals(raw_data: dict) -> None:
parsed = Filter.load(raw_data)

dumped = parsed.dump()

assert dumped == raw_data


Expand Down Expand Up @@ -163,3 +163,14 @@ def test_dump_filter(user_filter: Filter, expected: dict) -> None:
def test_unknown_filter_type() -> None:
with pytest.raises(ValueError, match="Unknown filter type: unknown"):
Filter.load({"unknown": {}})


@pytest.mark.parametrize("property_cls", filter(lambda cls: hasattr(cls, "metadata_key"), all_subclasses(EnumProperty)))
def test_user_given_metadata_keys_are_not_camel_cased(property_cls: type) -> None:
# Bug prior to 6.32.4 would dump user given keys in camelCase
flt = f.Equals(property_cls.metadata_key("key_foo_Bar_baz"), "value_foo Bar_baz") # type: ignore [attr-defined]
dumped = flt.dump(camel_case=True)["equals"]

# property may contain more (static) values, so we just verify the end:
assert dumped["property"][-2:] == ["metadata", "key_foo_Bar_baz"]
assert dumped["value"] == "value_foo Bar_baz"
2 changes: 1 addition & 1 deletion tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def all_subclasses(base: type) -> list[type]:
"""
return sorted(
filter(
lambda sub: str(sub).startswith("<class 'cognite.client"),
lambda sub: sub.__module__.startswith("cognite.client"),
set(base.__subclasses__()).union(s for c in base.__subclasses__() for s in all_subclasses(c)),
),
key=str,
Expand Down

0 comments on commit 4cff041

Please sign in to comment.