-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Toniof 352 support typespecifiers #354
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very good and exhaustive work, thanks!
In addition to my comments and suggests abovebelow:
- Please include a description of type specifiers and their usages into
DataStore
's class documentation. Refer to that doc from the methods that have atype_specifier
argument are return type specifiers. - We also need to get right when to raise DataStoreError and when ValuError. Note, I often see that when you raise a ValueError, you include a type name in the message rather than the argument's name. Please make sure you include the argument names. ValueErrors are mainly developer errors.
test/core/store/test_descriptor.py
Outdated
try: | ||
descriptor_dict = dict(data_id='xyz', type_id='tsr') | ||
DatasetDescriptor.from_dict(descriptor_dict) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
try: | |
descriptor_dict = dict(data_id='xyz', type_id='tsr') | |
DatasetDescriptor.from_dict(descriptor_dict) | |
with self.assertRaises(ValueError) as cm: | |
descriptor_dict = dict(data_id='xyz', type_id='tsr') | |
DatasetDescriptor.from_dict(descriptor_dict) | |
self.assertEqual('...', f'{cm.exception}') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can change that, but I'd like to point out that this is not part of the pull request.
xcube/core/store/descriptor.py
Outdated
raise ValueError(f'TypeId must be compatible with "geodataframe" type id, was {type_id}') | ||
def _assert_type_specifier(self, type_specifier: str): | ||
if not TYPE_SPECIFIER_GEODATAFRAME.is_compatible(type_specifier): | ||
raise ValueError(f'TypeSpecifier must be compatible with "geodataframe" type specifier, ' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
raise ValueError(f'TypeSpecifier must be compatible with "geodataframe" type specifier, ' | |
raise ValueError(f'type_specifier must be compatible with "geodataframe" type specifier, ' |
xcube/core/store/descriptor.py
Outdated
raise ValueError(f'TypeId must be compatible with "mldataset" type id, was {type_id}') | ||
def _assert_type_specifier(self, type_specifier: str): | ||
if not TYPE_SPECIFIER_MULTILEVEL_DATASET.is_compatible(type_specifier): | ||
raise ValueError(f'TypeSpecifier must be compatible with "mldataset" type specifier, was {type_specifier}') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
raise ValueError(f'TypeSpecifier must be compatible with "mldataset" type specifier, was {type_specifier}') | |
raise ValueError(f'type_specifier must be compatible with "mldataset" type specifier, was {type_specifier}') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TypeSpecifier
is not the argument's name, it is type_specifier
.
xcube/core/store/stores/memory.py
Outdated
if type_specifier: | ||
data_type_specifier = get_type_specifier(self._data_dict[data_id]) | ||
if not data_type_specifier.is_compatible(type_specifier): | ||
raise ValueError(f'Data resource "{data_id}" is not available as type {type_specifier}. ' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
raise ValueError(f'Data resource "{data_id}" is not available as type {type_specifier}. ' | |
raise ValueError(f'Data resource "{data_id}" is not compatible with type specifier "{type_specifier}". ' |
xcube/core/store/store.py
Outdated
If a store implementation supports only a single data type, it should verify that *type_id* is either None | ||
or equal to that single data type. | ||
If a store implementation supports only a single data type, it should verify that *type_specifier* | ||
is either None or equal to that single data type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is either None or equal to that single data type. | |
is either None or compatible with the supported data type. |
xcube/core/store/store.py
Outdated
""" | ||
Get the descriptor for the data resource given by *data_id*. | ||
|
||
Raises if *data_id* does not exist in this store. | ||
Raises a DataStoreError if *data_id* does not exist in this store |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Raises a DataStoreError if *data_id* does not exist in this store | |
Raises a :class:DataStoreError if *data_id* does not exist in this store |
Not clear yet when we raise class:DataStoreError and when ValueError. For example in some modules, we raise ValueError if type_specifier
is not compatible. That doesn't seem consistent to me.
xcube/core/store/store.py
Outdated
""" | ||
Get the tuple of data type specifiers that are supported for the given *data_id*. | ||
In case the type specifier allows one ore more flags, they are listed in brackets | ||
following the specifier's name, e.g., dataset[CUBE, MULTILEVEL]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
following the specifier's name, e.g., dataset[CUBE, MULTILEVEL]. | |
following the specifier's name, e.g., "dataset[cube,multilevel]". |
xcube/core/store/store.py
Outdated
If *type_specifier* is omitted, all data resource identifiers are returned. | ||
|
||
If a store implementation supports only a single data type, it should verify that *type_specifier* | ||
is either None or equal to that single data type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is either None or equal to that single data type. | |
is either None or compatible with the supported data type. |
test/core/store/test_descriptor.py
Outdated
@@ -17,7 +17,7 @@ def test_from_dict_no_data_id(self): | |||
except ValueError: | |||
pass | |||
|
|||
def test_from_dict_wrong_type_id(self): | |||
def test_from_dict_wrong_type_specifier(self): | |||
try: | |||
descriptor_dict = dict(data_id='xyz', type_id='tsr') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
descriptor_dict = dict(data_id='xyz', type_id='tsr') | |
descriptor_dict = dict(data_id='xyz', type_specifier='tsr') |
xcube/core/store/store.py
Outdated
|
||
:param type_specifier: If given, only data identifiers that are available as this type are returned. If this is | ||
omitted, all available data identifiers are returned |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
omitted, all available data identifiers are returned | |
omitted, all available data identifiers are returned. |
xcube/core/store/store.py
Outdated
|
||
:param type_specifier: If given, only data identifiers that are available as this type are returned. If this is | ||
omitted, all available data identifiers are returned | ||
:param include_titles: If true, the store will attempt to also provide a title |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:param include_titles: If true, the store will attempt to also provide a title | |
:param include_titles: If true, the store will attempt to also provide a title. |
xcube/core/store/typespecifier.py
Outdated
""" | ||
A type id denotes a type of data. It is used to group similar types of data and discern different types of data. | ||
It can be used by stores to state what types of data can be read from and/or written to them. | ||
A type specifier denotes a type of data. It is used to group similar types of data and discern |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A type specifier denotes a type of data. It is used to group similar types of data and discern | |
A type specifier denotes a type of data. It is used to group similar types of data and distinguish between |
I think this is clearer (hopefully I interpreted the intended meaning of "discern" correctly enough for a successful rephrasing...).
xcube/core/store/stores/memory.py
Outdated
def describe_data(self, data_id: str) -> DataDescriptor: | ||
if not data_id in self._data_dict: | ||
return False | ||
if type_specifier: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if type_specifier: | |
if type_specifier is not None: |
There are a few things (other than None) that may evaluate to False in this test, so I prefer an explicit None check. Admittedly it's unlikely that we'd be using e.g. 0 or the empty string as a type specifier, but if something like that is passed by mistake I think it's preferable to process it here (probably producing False or an error) rather than falling through to returning True.
xcube/core/store/stores/memory.py
Outdated
self._assert_valid_data_id(data_id) | ||
if type_specifier: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if type_specifier: | |
if type_specifier is not None: |
See previous comment.
docs/source/storeconv.md
Outdated
|
||
`<type_specifier>:<format_identifier>:<storage_identifier>` | ||
|
||
`<type_specifier>` MUST be a valid string that specifies a data type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the definition of "valid" in this context?
docs/source/storeconv.md
Outdated
`<type_specifier>:<format_identifier>:<storage_identifier>` | ||
|
||
`<type_specifier>` MUST be a valid string that specifies a data type. | ||
In case the type specifier has flags, the flags MUST be given in brackets, in alphabetic order, without spaces (e.g., `dataset[cube,multilevel]`). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In case the type specifier has flags, the flags MUST be given in brackets, in alphabetic order, without spaces (e.g., `dataset[cube,multilevel]`). | |
In case the type specifier has flags, the flags MUST be given in square brackets, in alphabetic order, separated by single commas, without spaces (e.g., `dataset[cube,multilevel]`). |
docs/source/storeconv.md
Outdated
|
||
`<type_specifier>` MUST be a valid string that specifies a data type. | ||
In case the type specifier has flags, the flags MUST be given in brackets, in alphabetic order, without spaces (e.g., `dataset[cube,multilevel]`). | ||
Note that `*` is a valid value in case that any type is supported. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that `*` is a valid value in case that any type is supported. | |
Note that `*` is a special value indicating that any type is supported. |
docs/source/storeconv.md
Outdated
|
||
`<type_specifier>:<format_identifier>:<storage_identifier>` | ||
|
||
`<type_specifier>` MUST be a valid string that specifies a data type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
`<type_specifier>` MUST be a valid string that specifies a data type. | |
`<type_specifier>` is a string that specifies a data type. Its intention and format is described below. |
docs/source/storeconv.md
Outdated
|
||
`<type_specifier>` MUST be a valid string that specifies a data type. | ||
In case the type specifier has flags, the flags MUST be given in brackets, in alphabetic order, without spaces (e.g., `dataset[cube,multilevel]`). | ||
Note that `*` is a valid value in case that any type is supported. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We want users to "note" everything in this doc. It is a (our) convention. So we define what things means and how they are used.
docs/source/storeconv.md
Outdated
`<type_specifier>:<format_identifier>:<storage_identifier>` | ||
|
||
`<type_specifier>` MUST be a valid string that specifies a data type. | ||
In case the type specifier has flags, the flags MUST be given in brackets, in alphabetic order, without spaces (e.g., `dataset[cube,multilevel]`). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In case the type specifier has flags, the flags MUST be given in brackets...
This is our convention and we have to tell users about the usage and the general syntax of type specifiers. How can a user know if their specifier has flags or not, if it is not explained what these flags are and how they are used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Provide a clear and unambiguous syntax descroiption (Backus Naur) and some explained examples.
xcube/core/store/descriptor.py
Outdated
raise ValueError(f'TypeId must be compatible with "dataset" type id, was {type_id}') | ||
def _assert_type_specifier(self, type_specifier: str): | ||
if not TYPE_SPECIFIER_DATASET.is_compatible(type_specifier): | ||
raise ValueError(f'TypeSpecifier must be compatible with "dataset" type specifier, was {type_specifier}') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
raise ValueError(f'TypeSpecifier must be compatible with "dataset" type specifier, was {type_specifier}') | |
raise ValueError(f'type_specifier must be compatible with "dataset" type specifier, was "{type_specifier}"') |
xcube/core/store/store.py
Outdated
obtain in-memory representations. A data resource may be available as different types. Therefore, many functions | ||
allow to specify the data type using a TypeSpecifier. A type specifier consists of a name and an arbitrary set of | ||
flags, given in brackets. These flags are used to define characteristics of a type, e.g., the type specifier | ||
dataset[cube] denotes a dataset which also meets the requirements of a cube. A dataset specified by |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dataset[cube] denotes a dataset which also meets the requirements of a cube. A dataset specified by | |
"dataset[cube]" denotes a dataset which also meets the requirements of a cube. A dataset specified by |
xcube/core/store/store.py
Outdated
allow to specify the data type using a TypeSpecifier. A type specifier consists of a name and an arbitrary set of | ||
flags, given in brackets. These flags are used to define characteristics of a type, e.g., the type specifier | ||
dataset[cube] denotes a dataset which also meets the requirements of a cube. A dataset specified by | ||
dataset[cube, multilevel] is a cube and has multiple levels. A type specifier with a flag is compatible to a type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dataset[cube, multilevel] is a cube and has multiple levels. A type specifier with a flag is compatible to a type | |
"dataset[cube, multilevel]" is a cube and has multiple levels. A type specifier with a flag is compatible to a type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah!
Solves #352