esgvoc 0.4.0__py3-none-any.whl → 1.0.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 (73) hide show
  1. esgvoc/__init__.py +1 -1
  2. esgvoc/api/data_descriptors/__init__.py +50 -28
  3. esgvoc/api/data_descriptors/activity.py +3 -3
  4. esgvoc/api/data_descriptors/area_label.py +16 -1
  5. esgvoc/api/data_descriptors/branded_suffix.py +20 -0
  6. esgvoc/api/data_descriptors/branded_variable.py +12 -0
  7. esgvoc/api/data_descriptors/consortium.py +14 -13
  8. esgvoc/api/data_descriptors/contact.py +5 -0
  9. esgvoc/api/data_descriptors/conventions.py +6 -0
  10. esgvoc/api/data_descriptors/creation_date.py +5 -0
  11. esgvoc/api/data_descriptors/data_descriptor.py +14 -9
  12. esgvoc/api/data_descriptors/data_specs_version.py +5 -0
  13. esgvoc/api/data_descriptors/date.py +1 -1
  14. esgvoc/api/data_descriptors/directory_date.py +1 -1
  15. esgvoc/api/data_descriptors/experiment.py +13 -11
  16. esgvoc/api/data_descriptors/forcing_index.py +1 -1
  17. esgvoc/api/data_descriptors/frequency.py +3 -3
  18. esgvoc/api/data_descriptors/further_info_url.py +5 -0
  19. esgvoc/api/data_descriptors/grid_label.py +2 -2
  20. esgvoc/api/data_descriptors/horizontal_label.py +15 -1
  21. esgvoc/api/data_descriptors/initialisation_index.py +1 -1
  22. esgvoc/api/data_descriptors/institution.py +8 -5
  23. esgvoc/api/data_descriptors/known_branded_variable.py +23 -0
  24. esgvoc/api/data_descriptors/license.py +3 -3
  25. esgvoc/api/data_descriptors/mip_era.py +1 -1
  26. esgvoc/api/data_descriptors/model_component.py +1 -1
  27. esgvoc/api/data_descriptors/obs_type.py +5 -0
  28. esgvoc/api/data_descriptors/organisation.py +1 -1
  29. esgvoc/api/data_descriptors/physic_index.py +1 -1
  30. esgvoc/api/data_descriptors/product.py +2 -2
  31. esgvoc/api/data_descriptors/publication_status.py +5 -0
  32. esgvoc/api/data_descriptors/realisation_index.py +1 -1
  33. esgvoc/api/data_descriptors/realm.py +1 -1
  34. esgvoc/api/data_descriptors/region.py +5 -0
  35. esgvoc/api/data_descriptors/resolution.py +3 -3
  36. esgvoc/api/data_descriptors/source.py +9 -5
  37. esgvoc/api/data_descriptors/source_type.py +1 -1
  38. esgvoc/api/data_descriptors/table.py +3 -2
  39. esgvoc/api/data_descriptors/temporal_label.py +15 -1
  40. esgvoc/api/data_descriptors/time_range.py +4 -3
  41. esgvoc/api/data_descriptors/title.py +5 -0
  42. esgvoc/api/data_descriptors/tracking_id.py +5 -0
  43. esgvoc/api/data_descriptors/variable.py +25 -12
  44. esgvoc/api/data_descriptors/variant_label.py +3 -3
  45. esgvoc/api/data_descriptors/vertical_label.py +14 -0
  46. esgvoc/api/project_specs.py +117 -2
  47. esgvoc/api/projects.py +242 -279
  48. esgvoc/api/search.py +30 -3
  49. esgvoc/api/universe.py +42 -27
  50. esgvoc/apps/jsg/cmip6_template.json +74 -0
  51. esgvoc/apps/jsg/cmip6plus_template.json +74 -0
  52. esgvoc/apps/jsg/json_schema_generator.py +185 -0
  53. esgvoc/cli/config.py +500 -0
  54. esgvoc/cli/find.py +138 -0
  55. esgvoc/cli/get.py +43 -38
  56. esgvoc/cli/main.py +10 -3
  57. esgvoc/cli/status.py +27 -18
  58. esgvoc/cli/valid.py +10 -15
  59. esgvoc/core/db/models/project.py +11 -11
  60. esgvoc/core/db/models/universe.py +3 -3
  61. esgvoc/core/db/project_ingestion.py +40 -40
  62. esgvoc/core/db/universe_ingestion.py +36 -33
  63. esgvoc/core/logging_handler.py +24 -2
  64. esgvoc/core/repo_fetcher.py +61 -59
  65. esgvoc/core/service/data_merger.py +47 -34
  66. esgvoc/core/service/state.py +107 -83
  67. {esgvoc-0.4.0.dist-info → esgvoc-1.0.0.dist-info}/METADATA +7 -20
  68. esgvoc-1.0.0.dist-info/RECORD +95 -0
  69. esgvoc/core/logging.conf +0 -21
  70. esgvoc-0.4.0.dist-info/RECORD +0 -80
  71. {esgvoc-0.4.0.dist-info → esgvoc-1.0.0.dist-info}/WHEEL +0 -0
  72. {esgvoc-0.4.0.dist-info → esgvoc-1.0.0.dist-info}/entry_points.txt +0 -0
  73. {esgvoc-0.4.0.dist-info → esgvoc-1.0.0.dist-info}/licenses/LICENSE.txt +0 -0
@@ -2,5 +2,19 @@ from esgvoc.api.data_descriptors.data_descriptor import PlainTermDataDescriptor
2
2
 
3
3
 
4
4
  class TemporalLabel(PlainTermDataDescriptor):
5
+ """
6
+ Temporal sampling label.
7
+
8
+ This label provides information about the temporal sampling of a given dataset.
9
+ For a list of allowed values, see
10
+ [TODO think about how to cross-reference to somewhere where people can look up the allowed values,
11
+ e.g. some summary of the values in https://github.com/WCRP-CMIP/WCRP-universe/tree/esgvoc/temporal_label.]
12
+
13
+ This label is used as the temporal component of a branded variable's suffix
14
+ (see :py:class:`BrandedSuffix`).
15
+ By definition, the temporal label must be consistent with the branded suffix.
16
+ Temporal labels must not contain the separator used when constructing the branded suffix.
17
+ """
18
+
5
19
  description: str
6
- label: str
20
+ label: str
@@ -1,4 +1,5 @@
1
- from esgvoc.api.data_descriptors.data_descriptor import CompositeTermDataDescriptor
1
+ from esgvoc.api.data_descriptors.data_descriptor import PatternTermDataDescriptor
2
2
 
3
- class TimeRange(CompositeTermDataDescriptor):
4
- description: str
3
+
4
+ class TimeRange(PatternTermDataDescriptor):
5
+ description: str
@@ -0,0 +1,5 @@
1
+ from esgvoc.api.data_descriptors.data_descriptor import PatternTermDataDescriptor
2
+
3
+
4
+ class Title(PatternTermDataDescriptor):
5
+ pass
@@ -0,0 +1,5 @@
1
+ from esgvoc.api.data_descriptors.data_descriptor import PatternTermDataDescriptor
2
+
3
+
4
+ class TrackingId(PatternTermDataDescriptor):
5
+ description: str
@@ -1,19 +1,32 @@
1
1
  from pydantic import Field
2
+
2
3
  from esgvoc.api.data_descriptors.data_descriptor import PlainTermDataDescriptor
3
4
 
4
5
 
5
6
  class Variable(PlainTermDataDescriptor):
6
7
  """
7
- A variable refers to a specific type of climate-related quantity or measurement that is \
8
- simulated and stored in a data file. These variables represent key physical, chemical, or \
9
- biological properties of the Earth system and are outputs from climate models.
10
- Each variable captures a different aspect of the climate system, such as temperature, \
11
- precipitation, sea level, radiation, or atmospheric composition.
12
- Examples of Variables: tas: Near-surface air temperature (often measured at 2 meters above \
13
- the surface) pr: Precipitation psl: Sea level pressure zg: Geopotential height rlut: \
14
- Top-of-atmosphere longwave radiation siconc: Sea ice concentration co2: Atmospheric CO2 concentration
8
+ A climate-related quantity or measurement.
9
+
10
+ These quantities represent key physical, chemical or biological properties of the Earth system
11
+ and can be the result of direct observation of the climate system or simulations.
12
+ Variables cover a range of aspects of the climate system,
13
+ such as temperature, precipitation, sea level, radiation, or atmospheric composition.
14
+ Some examples of variables that have been used in CMIP:
15
+
16
+ - *tas*: Near-surface air temperature (often measured at 2 meters above the surface)
17
+ - *pr*: Precipitation
18
+ - *psl*: Sea-level pressure
19
+ - *zg*: Geopotential height
20
+ - *rlut*: Top-of-atmosphere longwave radiation
21
+ - *siconc*: Sea-ice concentration
22
+ - *co2*: Atmospheric CO2 concentration
23
+
24
+ Since CMIP7, the concept of a variable has been augmented with the idea of 'branding',
25
+ leading to the idea of a 'branded variable'.
26
+ For details, see :py:class:`BrandedVariable`.
15
27
  """
16
- validation_method: str = Field(default = "list")
17
- long_name: str
18
- standard_name: str|None
19
- units: str|None
28
+
29
+ validation_method: str = Field(default="list")
30
+ long_name: str
31
+ standard_name: str | None
32
+ units: str | None
@@ -1,5 +1,5 @@
1
- from esgvoc.api.data_descriptors.data_descriptor import CompositeTermDataDescriptor
1
+ from esgvoc.api.data_descriptors.data_descriptor import PatternTermDataDescriptor
2
2
 
3
3
 
4
- class VariantLabel(CompositeTermDataDescriptor):
5
- description: str
4
+ class VariantLabel(PatternTermDataDescriptor):
5
+ description: str
@@ -2,4 +2,18 @@ from esgvoc.api.data_descriptors.data_descriptor import PatternTermDataDescripto
2
2
 
3
3
 
4
4
  class VerticalLabel(PatternTermDataDescriptor):
5
+ """
6
+ Vertical label.
7
+
8
+ This label provides information about the vertical sampling of a given dataset.
9
+ For a list of allowed values, see
10
+ [TODO think about how to cross-reference to somewhere where people can look up the allowed values,
11
+ e.g. some summary of the values in https://github.com/WCRP-CMIP/WCRP-universe/tree/esgvoc/vertical_label.]
12
+
13
+ This label is used as the vertical component of a branded variable's suffix
14
+ (see :py:class:`BrandedSuffix`).
15
+ By definition, the vertical label must be consistent with the branded suffix.
16
+ Vertical labels must not contain the separator used when constructing the branded suffix.
17
+ """
18
+
5
19
  pass
@@ -1,5 +1,5 @@
1
1
  from enum import Enum
2
- from typing import Annotated, Literal
2
+ from typing import Annotated, Any, Literal, Optional, Protocol
3
3
 
4
4
  from pydantic import BaseModel, ConfigDict, Field
5
5
 
@@ -8,6 +8,7 @@ class DrsType(str, Enum):
8
8
  """
9
9
  The types of DRS specification (directory, file name and dataset id).
10
10
  """
11
+
11
12
  DIRECTORY = "directory"
12
13
  """The DRS directory specification type."""
13
14
  FILE_NAME = "file_name"
@@ -20,6 +21,7 @@ class DrsPartKind(str, Enum):
20
21
  """
21
22
  The kinds of DRS part (constant and collection).
22
23
  """
24
+
23
25
  CONSTANT = "constant"
24
26
  """The constant part type."""
25
27
  COLLECTION = "collection"
@@ -30,10 +32,12 @@ class DrsConstant(BaseModel):
30
32
  """
31
33
  A constant part of a DRS specification (e.g., cmip5).
32
34
  """
35
+
33
36
  value: str
34
37
  """The value of the a constant part."""
35
38
  kind: Literal[DrsPartKind.CONSTANT] = DrsPartKind.CONSTANT
36
39
  """The DRS part kind."""
40
+
37
41
  def __str__(self) -> str:
38
42
  return self.value
39
43
 
@@ -42,12 +46,14 @@ class DrsCollection(BaseModel):
42
46
  """
43
47
  A collection part of a DRS specification (e.g., institution_id for CMIP6).
44
48
  """
49
+
45
50
  collection_id: str
46
51
  """The collection id."""
47
52
  is_required: bool
48
53
  """Whether the collection is required for the DRS specification or not."""
49
54
  kind: Literal[DrsPartKind.COLLECTION] = DrsPartKind.COLLECTION
50
55
  """The DRS part kind."""
56
+
51
57
  def __str__(self) -> str:
52
58
  return self.collection_id
53
59
 
@@ -60,6 +66,7 @@ class DrsSpecification(BaseModel):
60
66
  """
61
67
  A DRS specification.
62
68
  """
69
+
63
70
  type: DrsType
64
71
  """The type of the specification."""
65
72
  separator: str
@@ -70,14 +77,122 @@ class DrsSpecification(BaseModel):
70
77
  """The parts of the DRS specification."""
71
78
 
72
79
 
80
+ class GlobalAttributeValueType(str, Enum):
81
+ """
82
+ The types of global attribute values.
83
+ """
84
+
85
+ STRING = "string"
86
+ """String value type."""
87
+ INTEGER = "integer"
88
+ """Integer value type."""
89
+ FLOAT = "float"
90
+ """Float value type."""
91
+
92
+
93
+ class GlobalAttributeVisitor(Protocol):
94
+ """
95
+ Specifications for a global attribute visitor.
96
+ """
97
+ def visit_base_attribute(self,
98
+ attribute_name: str,
99
+ attribute: "GlobalAttributeSpecBase") -> Any:
100
+ """Visit a base global attribute."""
101
+ pass
102
+
103
+ def visit_specific_attribute(self,
104
+ attribute_name: str,
105
+ attribute: "GlobalAttributeSpecSpecific") -> Any:
106
+ """Visit a specific global attribute."""
107
+ pass
108
+
109
+
110
+ class GlobalAttributeSpecBase(BaseModel):
111
+ """
112
+ Specification for a global attribute.
113
+ """
114
+
115
+ source_collection: str
116
+ """the source_collection to get the term from"""
117
+ value_type: GlobalAttributeValueType
118
+ """The expected value type."""
119
+
120
+ def accept(self, attribute_name: str, visitor: GlobalAttributeVisitor) -> Any:
121
+ return visitor.visit_base_attribute(attribute_name, self)
122
+
123
+
124
+ class GlobalAttributeSpecSpecific(GlobalAttributeSpecBase):
125
+ """
126
+ Specification for a global attribute.
127
+ with a specific key
128
+ """
129
+
130
+ specific_key: str
131
+ """If the validation is for the value of a specific key, for instance description or ui-label """
132
+
133
+ def accept(self, attribute_name: str, visitor: GlobalAttributeVisitor) -> Any:
134
+ """
135
+ Accept a global attribute visitor.
136
+
137
+ :param attribute_name: The attribute name.
138
+ :param visitor: The global attribute visitor.
139
+ :type visitor: GlobalAttributeVisitor
140
+ :return: Depending on the visitor.
141
+ :rtype: Any
142
+ """
143
+ return visitor.visit_specific_attribute(attribute_name, self)
144
+
145
+
146
+ GlobalAttributeSpec = GlobalAttributeSpecSpecific | GlobalAttributeSpecBase
147
+
148
+
149
+ class GlobalAttributeSpecs(BaseModel):
150
+ """
151
+ Container for global attribute specifications.
152
+ """
153
+
154
+ specs: dict[str, GlobalAttributeSpec] = Field(default_factory=dict)
155
+ """The global attributes specifications dictionary."""
156
+
157
+ def __str__(self) -> str:
158
+ """Return all keys when printing."""
159
+ return str(list(self.specs.keys()))
160
+
161
+ def __repr__(self) -> str:
162
+ """Return all keys when using repr."""
163
+ return f"GlobalAttributeSpecs(keys={list(self.specs.keys())})"
164
+
165
+ # Dictionary-like access methods
166
+ def __getitem__(self, key: str) -> GlobalAttributeSpec:
167
+ return self.specs[key]
168
+
169
+ def __setitem__(self, key: str, value: GlobalAttributeSpec) -> None:
170
+ self.specs[key] = value
171
+
172
+ def __contains__(self, key: str) -> bool:
173
+ return key in self.specs
174
+
175
+ def keys(self):
176
+ return self.specs.keys()
177
+
178
+ def values(self):
179
+ return self.specs.values()
180
+
181
+ def items(self):
182
+ return self.specs.items()
183
+
184
+
73
185
  class ProjectSpecs(BaseModel):
74
186
  """
75
187
  A project specifications.
76
188
  """
189
+
77
190
  project_id: str
78
191
  """The project id."""
79
192
  description: str
80
193
  """The description of the project."""
81
194
  drs_specs: list[DrsSpecification]
82
- """The DRS specifications of the project (directory, file name and dataset id."""
195
+ """The DRS specifications of the project (directory, file name and dataset id)."""
196
+ global_attributes_specs: Optional[GlobalAttributeSpecs] = None
197
+ """The global attributes specifications of the project."""
83
198
  model_config = ConfigDict(extra="allow")