esgvoc 0.2.1__py3-none-any.whl → 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of esgvoc might be problematic. Click here for more details.

Files changed (70) hide show
  1. esgvoc/__init__.py +3 -1
  2. esgvoc/api/__init__.py +23 -34
  3. esgvoc/api/_utils.py +28 -14
  4. esgvoc/api/data_descriptors/__init__.py +18 -12
  5. esgvoc/api/data_descriptors/activity.py +8 -45
  6. esgvoc/api/data_descriptors/area_label.py +6 -0
  7. esgvoc/api/data_descriptors/branded_suffix.py +5 -0
  8. esgvoc/api/data_descriptors/branded_variable.py +5 -0
  9. esgvoc/api/data_descriptors/consortium.py +16 -56
  10. esgvoc/api/data_descriptors/data_descriptor.py +106 -0
  11. esgvoc/api/data_descriptors/date.py +3 -46
  12. esgvoc/api/data_descriptors/directory_date.py +3 -46
  13. esgvoc/api/data_descriptors/experiment.py +19 -54
  14. esgvoc/api/data_descriptors/forcing_index.py +3 -45
  15. esgvoc/api/data_descriptors/frequency.py +6 -43
  16. esgvoc/api/data_descriptors/grid_label.py +6 -44
  17. esgvoc/api/data_descriptors/horizontal_label.py +6 -0
  18. esgvoc/api/data_descriptors/initialisation_index.py +3 -44
  19. esgvoc/api/data_descriptors/institution.py +11 -54
  20. esgvoc/api/data_descriptors/license.py +4 -44
  21. esgvoc/api/data_descriptors/mip_era.py +6 -44
  22. esgvoc/api/data_descriptors/model_component.py +7 -45
  23. esgvoc/api/data_descriptors/organisation.py +3 -40
  24. esgvoc/api/data_descriptors/physic_index.py +3 -45
  25. esgvoc/api/data_descriptors/product.py +4 -43
  26. esgvoc/api/data_descriptors/realisation_index.py +3 -44
  27. esgvoc/api/data_descriptors/realm.py +4 -42
  28. esgvoc/api/data_descriptors/resolution.py +6 -44
  29. esgvoc/api/data_descriptors/source.py +18 -53
  30. esgvoc/api/data_descriptors/source_type.py +3 -41
  31. esgvoc/api/data_descriptors/sub_experiment.py +3 -41
  32. esgvoc/api/data_descriptors/table.py +6 -48
  33. esgvoc/api/data_descriptors/temporal_label.py +6 -0
  34. esgvoc/api/data_descriptors/time_range.py +3 -27
  35. esgvoc/api/data_descriptors/variable.py +13 -71
  36. esgvoc/api/data_descriptors/variant_label.py +3 -47
  37. esgvoc/api/data_descriptors/vertical_label.py +5 -0
  38. esgvoc/api/projects.py +187 -171
  39. esgvoc/api/report.py +21 -12
  40. esgvoc/api/search.py +3 -1
  41. esgvoc/api/universe.py +44 -34
  42. esgvoc/apps/__init__.py +3 -4
  43. esgvoc/apps/drs/generator.py +166 -161
  44. esgvoc/apps/drs/report.py +222 -131
  45. esgvoc/apps/drs/validator.py +103 -105
  46. esgvoc/cli/drs.py +29 -19
  47. esgvoc/cli/get.py +26 -25
  48. esgvoc/cli/install.py +11 -8
  49. esgvoc/cli/main.py +0 -2
  50. esgvoc/cli/status.py +5 -5
  51. esgvoc/cli/valid.py +40 -40
  52. esgvoc/core/db/models/universe.py +3 -3
  53. esgvoc/core/db/project_ingestion.py +1 -1
  54. esgvoc/core/db/universe_ingestion.py +6 -5
  55. esgvoc/core/logging_handler.py +1 -1
  56. esgvoc/core/repo_fetcher.py +4 -3
  57. esgvoc/core/service/__init__.py +37 -5
  58. esgvoc/core/service/configuration/config_manager.py +188 -0
  59. esgvoc/core/service/configuration/setting.py +88 -0
  60. esgvoc/core/service/state.py +49 -32
  61. {esgvoc-0.2.1.dist-info → esgvoc-0.3.0.dist-info}/METADATA +34 -3
  62. esgvoc-0.3.0.dist-info/RECORD +78 -0
  63. esgvoc/cli/config.py +0 -82
  64. esgvoc/core/service/settings.py +0 -73
  65. esgvoc/core/service/settings.toml +0 -17
  66. esgvoc/core/service/settings_default.toml +0 -17
  67. esgvoc-0.2.1.dist-info/RECORD +0 -73
  68. {esgvoc-0.2.1.dist-info → esgvoc-0.3.0.dist-info}/WHEEL +0 -0
  69. {esgvoc-0.2.1.dist-info → esgvoc-0.3.0.dist-info}/entry_points.txt +0 -0
  70. {esgvoc-0.2.1.dist-info → esgvoc-0.3.0.dist-info}/licenses/LICENSE.txt +0 -0
esgvoc/api/report.py CHANGED
@@ -1,7 +1,8 @@
1
- from pydantic import BaseModel, computed_field
2
1
  from abc import ABC, abstractmethod
3
2
  from typing import Any, Protocol
4
3
 
4
+ from pydantic import BaseModel, computed_field
5
+
5
6
  import esgvoc.core.constants as api_settings
6
7
  from esgvoc.core.db.models.mixins import TermKind
7
8
 
@@ -29,7 +30,11 @@ class ValidationError(BaseModel, ABC):
29
30
  """JSON specification of the term."""
30
31
  term_kind: TermKind
31
32
  """The kind of term."""
32
-
33
+ @computed_field # type: ignore
34
+ @property
35
+ def class_name(self) -> str:
36
+ """The class name of the issue for JSON serialization."""
37
+ return self.__class__.__name__
33
38
  @abstractmethod
34
39
  def accept(self, visitor: ValidationErrorVisitor) -> Any:
35
40
  """
@@ -46,13 +51,13 @@ class UniverseTermError(ValidationError):
46
51
  """
47
52
  A validation error on a term from the universe.
48
53
  """
49
-
54
+
50
55
  data_descriptor_id: str
51
56
  """The data descriptor that the term belongs."""
52
57
 
53
58
  def accept(self, visitor: ValidationErrorVisitor) -> Any:
54
59
  return visitor.visit_universe_term_error(self)
55
-
60
+
56
61
  def __str__(self) -> str:
57
62
  term_id = self.term[api_settings.TERM_ID_JSON_KEY]
58
63
  result = f"The term {term_id} from the data descriptor {self.data_descriptor_id} "+\
@@ -66,13 +71,13 @@ class ProjectTermError(ValidationError):
66
71
  """
67
72
  A validation error on a term from a project.
68
73
  """
69
-
74
+
70
75
  collection_id: str
71
76
  """The collection id that the term belongs"""
72
77
 
73
78
  def accept(self, visitor: ValidationErrorVisitor) -> Any:
74
79
  return visitor.visit_project_term_error(self)
75
-
80
+
76
81
  def __str__(self) -> str:
77
82
  term_id = self.term[api_settings.TERM_ID_JSON_KEY]
78
83
  result = f"The term {term_id} from the collection {self.collection_id} "+\
@@ -86,29 +91,33 @@ class ValidationReport(BaseModel):
86
91
  """
87
92
  Term validation report.
88
93
  """
94
+
89
95
  expression: str
90
96
  """The given expression."""
91
- errors: list[ValidationError]
97
+
98
+ errors: list[UniverseTermError|ProjectTermError]
92
99
  """The validation errors."""
100
+
93
101
  @computed_field # type: ignore
94
102
  @property
95
103
  def nb_errors(self) -> int:
96
104
  """The number of validation errors."""
97
105
  return len(self.errors) if self.errors else 0
106
+
98
107
  @computed_field # type: ignore
99
108
  @property
100
109
  def validated(self) -> bool:
101
110
  """The expression is validated or not."""
102
111
  return False if self.errors else True
103
-
104
-
112
+
105
113
  def __len__(self) -> int:
106
114
  return self.nb_errors
107
-
115
+
108
116
  def __bool__(self) -> bool:
109
117
  return self.validated
110
-
118
+
111
119
  def __str__(self) -> str:
112
120
  return f"'{self.expression}' has {self.nb_errors} error(s)"
121
+
113
122
  def __repr__(self) -> str:
114
- return self.__str__()
123
+ return self.__str__()
esgvoc/api/search.py CHANGED
@@ -1,5 +1,5 @@
1
+ from typing import Iterable
1
2
  from enum import Enum
2
-
3
3
  from pydantic import BaseModel
4
4
  from sqlalchemy import ColumnElement, func
5
5
  from sqlmodel import col
@@ -43,6 +43,8 @@ class SearchSettings(BaseModel):
43
43
  """Enable case sensitivity or not."""
44
44
  not_operator: bool = False
45
45
  """Give the opposite result like the NOT SQL operator."""
46
+ selected_term_fields: Iterable[str]|None = None
47
+ """Term fields to select"""
46
48
 
47
49
 
48
50
  def _create_str_comparison_expression(field: str,
esgvoc/api/universe.py CHANGED
@@ -1,10 +1,10 @@
1
- from typing import Sequence
1
+ from typing import Sequence, Iterable
2
2
 
3
3
  from esgvoc.api._utils import (get_universe_session,
4
4
  instantiate_pydantic_terms)
5
5
  from esgvoc.api.search import SearchSettings, _create_str_comparison_expression
6
- from esgvoc.core.db.models.universe import DataDescriptor, UTerm
7
- from pydantic import BaseModel
6
+ from esgvoc.api.data_descriptors.data_descriptor import DataDescriptor
7
+ from esgvoc.core.db.models.universe import UDataDescriptor, UTerm
8
8
  from sqlmodel import Session, select
9
9
 
10
10
 
@@ -16,7 +16,7 @@ def _find_terms_in_data_descriptor(data_descriptor_id: str,
16
16
  where_expression = _create_str_comparison_expression(field=UTerm.id,
17
17
  value=term_id,
18
18
  settings=settings)
19
- statement = select(UTerm).join(DataDescriptor).where(DataDescriptor.id==data_descriptor_id,
19
+ statement = select(UTerm).join(UDataDescriptor).where(UDataDescriptor.id==data_descriptor_id,
20
20
  where_expression)
21
21
  results = session.exec(statement)
22
22
  result = results.all()
@@ -26,7 +26,7 @@ def _find_terms_in_data_descriptor(data_descriptor_id: str,
26
26
  def find_terms_in_data_descriptor(data_descriptor_id: str,
27
27
  term_id: str,
28
28
  settings: SearchSettings|None = None) \
29
- -> list[BaseModel]:
29
+ -> list[DataDescriptor]:
30
30
  """
31
31
  Finds one or more terms in the given data descriptor based on the specified search settings.
32
32
  This function performs an exact match on the `data_descriptor_id` and
@@ -39,8 +39,8 @@ def find_terms_in_data_descriptor(data_descriptor_id: str,
39
39
  returns an empty list.
40
40
 
41
41
  Behavior based on search type:
42
- - `EXACT` and absence of `settings`: returns zero or one Pydantic term instance in the list.
43
- - `REGEX`, `LIKE`, `STARTS_WITH` and `ENDS_WITH`: returns zero, one or more Pydantic term \
42
+ - `EXACT` and absence of `settings`: returns zero or one term instance in the list.
43
+ - `REGEX`, `LIKE`, `STARTS_WITH` and `ENDS_WITH`: returns zero, one or more term \
44
44
  instances in the list.
45
45
 
46
46
  :param data_descriptor_id: A data descriptor id
@@ -49,13 +49,13 @@ def find_terms_in_data_descriptor(data_descriptor_id: str,
49
49
  :type term_id: str
50
50
  :param settings: The search settings
51
51
  :type settings: SearchSettings|None
52
- :returns: A list of Pydantic model term instances. Returns an empty list if no matches are found.
53
- :rtype: list[BaseModel]
52
+ :returns: A list of term instances. Returns an empty list if no matches are found.
53
+ :rtype: list[DataDescriptor]
54
54
  """
55
- result: list[BaseModel] = list()
55
+ result: list[DataDescriptor] = list()
56
56
  with get_universe_session() as session:
57
57
  terms = _find_terms_in_data_descriptor(data_descriptor_id, term_id, session, settings)
58
- instantiate_pydantic_terms(terms, result)
58
+ instantiate_pydantic_terms(terms, result, settings.selected_term_fields if settings else None)
59
59
  return result
60
60
 
61
61
 
@@ -72,7 +72,7 @@ def _find_terms_in_universe(term_id: str,
72
72
 
73
73
  def find_terms_in_universe(term_id: str,
74
74
  settings: SearchSettings|None = None) \
75
- -> list[BaseModel]:
75
+ -> list[DataDescriptor]:
76
76
  """
77
77
  Finds one or more terms of the universe.
78
78
  The given `term_id` is searched according to the search type specified in
@@ -86,36 +86,38 @@ def find_terms_in_universe(term_id: str,
86
86
  :type term_id: str
87
87
  :param settings: The search settings
88
88
  :type settings: SearchSettings|None
89
- :returns: A list of Pydantic term instances. Returns an empty list if no matches are found.
90
- :rtype: list[BaseModel]
89
+ :returns: A list of term instances. Returns an empty list if no matches are found.
90
+ :rtype: list[DataDescriptor]
91
91
  """
92
- result: list[BaseModel] = list()
92
+ result: list[DataDescriptor] = list()
93
93
  with get_universe_session() as session:
94
94
  terms = _find_terms_in_universe(term_id, session, settings)
95
- instantiate_pydantic_terms(terms, result)
95
+ instantiate_pydantic_terms(terms, result, settings.selected_term_fields if settings else None)
96
96
  return result
97
97
 
98
98
 
99
- def _get_all_terms_in_data_descriptor(data_descriptor: DataDescriptor) -> list[BaseModel]:
100
- result: list[BaseModel] = list()
101
- instantiate_pydantic_terms(data_descriptor.terms, result)
99
+ def _get_all_terms_in_data_descriptor(data_descriptor: UDataDescriptor,
100
+ selected_term_fields: Iterable[str]|None) -> list[DataDescriptor]:
101
+ result: list[DataDescriptor] = list()
102
+ instantiate_pydantic_terms(data_descriptor.terms, result, selected_term_fields)
102
103
  return result
103
104
 
104
105
 
105
106
  def _find_data_descriptors_in_universe(data_descriptor_id: str,
106
107
  session: Session,
107
- settings: SearchSettings|None) -> Sequence[DataDescriptor]:
108
- where_expression = _create_str_comparison_expression(field=DataDescriptor.id,
108
+ settings: SearchSettings|None) -> Sequence[UDataDescriptor]:
109
+ where_expression = _create_str_comparison_expression(field=UDataDescriptor.id,
109
110
  value=data_descriptor_id,
110
111
  settings=settings)
111
- statement = select(DataDescriptor).where(where_expression)
112
+ statement = select(UDataDescriptor).where(where_expression)
112
113
  results = session.exec(statement)
113
114
  result = results.all()
114
115
  return result
115
116
 
116
117
 
117
- def get_all_terms_in_data_descriptor(data_descriptor_id: str) \
118
- -> list[BaseModel]:
118
+ def get_all_terms_in_data_descriptor(data_descriptor_id: str,
119
+ selected_term_fields: Iterable[str]|None = None) \
120
+ -> list[DataDescriptor]:
119
121
  """
120
122
  Gets all the terms of the given data descriptor.
121
123
  This function performs an exact match on the `data_descriptor_id` and does **not** search
@@ -124,8 +126,11 @@ def get_all_terms_in_data_descriptor(data_descriptor_id: str) \
124
126
 
125
127
  :param data_descriptor_id: A data descriptor id
126
128
  :type data_descriptor_id: str
127
- :returns: a list of Pydantic term instances. Returns an empty list if no matches are found.
128
- :rtype: list[BaseModel]
129
+ :param selected_term_fields: A list of term fields to select or `None`. If `None`, all the \
130
+ fields of the terms are returned.
131
+ :type selected_term_fields: Iterable[str]|None
132
+ :returns: a list of term instances. Returns an empty list if no matches are found.
133
+ :rtype: list[DataDescriptor]
129
134
  """
130
135
  with get_universe_session() as session:
131
136
  data_descriptors = _find_data_descriptors_in_universe(data_descriptor_id,
@@ -133,7 +138,7 @@ def get_all_terms_in_data_descriptor(data_descriptor_id: str) \
133
138
  None)
134
139
  if data_descriptors:
135
140
  data_descriptor = data_descriptors[0]
136
- result = _get_all_terms_in_data_descriptor(data_descriptor)
141
+ result = _get_all_terms_in_data_descriptor(data_descriptor, selected_term_fields)
137
142
  else:
138
143
  result = list()
139
144
  return result
@@ -173,8 +178,8 @@ def find_data_descriptors_in_universe(data_descriptor_id: str,
173
178
  return result
174
179
 
175
180
 
176
- def _get_all_data_descriptors_in_universe(session: Session) -> Sequence[DataDescriptor]:
177
- statement = select(DataDescriptor)
181
+ def _get_all_data_descriptors_in_universe(session: Session) -> Sequence[UDataDescriptor]:
182
+ statement = select(UDataDescriptor)
178
183
  data_descriptors = session.exec(statement)
179
184
  result = data_descriptors.all()
180
185
  return result
@@ -195,23 +200,28 @@ def get_all_data_descriptors_in_universe() -> list[str]:
195
200
  return result
196
201
 
197
202
 
198
- def get_all_terms_in_universe() -> list[BaseModel]:
203
+ def get_all_terms_in_universe(selected_term_fields: Iterable[str]|None = None) -> list[DataDescriptor]:
199
204
  """
200
205
  Gets all the terms of the universe.
201
206
  Terms are unique within a data descriptor but may have some synonyms in the universe.
202
207
 
203
- :returns: A list of Pydantic term instances.
204
- :rtype: list[BaseModel]
208
+ :param selected_term_fields: A list of term fields to select or `None`. If `None`, all the \
209
+ fields of the terms are returned.
210
+ :type selected_term_fields: Iterable[str]|None
211
+ :returns: A list of term instances.
212
+ :rtype: list[DataDescriptor]
205
213
  """
206
214
  result = list()
207
215
  with get_universe_session() as session:
208
216
  data_descriptors = _get_all_data_descriptors_in_universe(session)
209
217
  for data_descriptor in data_descriptors:
210
218
  # Term may have some synonyms within the whole universe.
211
- terms = _get_all_terms_in_data_descriptor(data_descriptor)
219
+ terms = _get_all_terms_in_data_descriptor(data_descriptor, selected_term_fields)
212
220
  result.extend(terms)
213
221
  return result
214
222
 
215
223
 
216
224
  if __name__ == "__main__":
217
- print(find_terms_in_data_descriptor('institution', 'ipsl'))
225
+ settings = SearchSettings()
226
+ settings.selected_term_fields = ('id',)
227
+ print(find_terms_in_data_descriptor('institution', 'ipsl', settings))
esgvoc/apps/__init__.py CHANGED
@@ -1,7 +1,6 @@
1
1
 
2
- from esgvoc.apps.drs.validator import DrsValidator
3
- from esgvoc.apps.drs.report import DrsValidationReport
4
2
  from esgvoc.apps.drs.generator import DrsGenerator
5
- from esgvoc.apps.drs.report import DrsGeneratorReport
3
+ from esgvoc.apps.drs.report import DrsGenerationReport, DrsValidationReport
4
+ from esgvoc.apps.drs.validator import DrsValidator
6
5
 
7
- __all__ = ["DrsValidator", "DrsValidationReport", "DrsGenerator", "DrsGeneratorReport"]
6
+ __all__ = ["DrsValidator", "DrsValidationReport", "DrsGenerator", "DrsGenerationReport"]