esgvoc 2.0.2__py3-none-any.whl → 2.1.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.
esgvoc/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  import esgvoc.core.logging_handler # noqa
2
2
 
3
- __version__ = "2.0.2"
3
+ __version__ = "2.1.0"
@@ -3,50 +3,34 @@ from esgvoc.api.data_descriptors.data_descriptor import PlainTermDataDescriptor
3
3
 
4
4
  class Coordinate(PlainTermDataDescriptor):
5
5
  """
6
- Native vertical grid coordinate type. The coordinate types are all CF standard names (except where indicated) with the same definitions. See section 5.2 Native vertical grid properties.
6
+ Native vertical grid coordinate type.
7
+
8
+ The coordinate types are all CF standard names (except where indicated)
9
+ with the same definitions. See section 5.2 Native vertical grid properties.
10
+
7
11
  Options for the native vertical grid Coordinate property:
8
- • none
9
- (Not a standard name) There is no vertical dimension.
10
- height
11
- Height is the vertical distance above the earth's surface.
12
- geopotential_height
13
- Geopotential height is the geopotential divided by the standard acceleration due to gravity.
14
- air_pressure
15
- Air pressure is the pressure that exists in the medium of air.
16
- air_potential_temperature
17
- Air potential temperature is the temperature a parcel of air would have if moved dry adiabatically to a standard pressure.
18
- atmosphere_ln_pressure_coordinate
19
- Parametric atmosphere natural log pressure coordinate.
20
- atmosphere_sigma_coordinate
21
- Parametric atmosphere sigma coordinate.
22
- atmosphere_hybrid_sigma_pressure_coordinate
23
- Parametric atmosphere hybrid sigma pressure coordinate.
24
- atmosphere_hybrid_height_coordinate
25
- Parametric atmosphere hybrid height coordinate.
26
- atmosphere_sleve_coordinate
27
- Parametric atmosphere smooth vertical level coordinate.
28
- depth
29
- Depth is the vertical distance below the earth's surface.
30
- • sea_water_pressure
31
- ◦ Sea water pressure is the pressure that exists in the medium of sea water.
32
- • sea_water_potential_temperature
33
- ◦ Sea water potential temperature is the temperature a parcel of sea water would have if moved adiabatically to sea level pressure.
34
- • ocean_sigma_coordinate
35
- ◦ Parametric ocean sigma coordinate.
36
- • ocean_s_coordinate
37
- ◦ Parametric ocean s-coordinate.
38
- • ocean_s_coordinate_g1
39
- ◦ Parametric ocean s-coordinate, generic form 1.
40
- • ocean_s_coordinate_g2
41
- ◦ Parametric ocean s-coordinate, generic form 2.
42
- • ocean_sigma_z_coordinate
43
- ◦ Parametric ocean sigma over z coordinate.
44
- • ocean_double_sigma_coordinate
45
- ◦ Parametric ocean double sigma coordinate.
46
- • land_ice_sigma_coordinate
47
- ◦ Land ice (glaciers, ice-caps and ice-sheets resting on bedrock and also includes ice-shelves) sigma coordinate.
48
- • z*
49
- ◦ (Not a standard name) The z* coordinate of Adcroft and Campin (2004).
12
+
13
+ * **none** - (Not a standard name) There is no vertical dimension.
14
+ * **height** - Height is the vertical distance above the earth's surface.
15
+ * **geopotential_height** - Geopotential height is the geopotential divided by the standard acceleration due to gravity.
16
+ * **air_pressure** - Air pressure is the pressure that exists in the medium of air.
17
+ * **air_potential_temperature** - Air potential temperature is the temperature a parcel of air would have if moved dry adiabatically to a standard pressure.
18
+ * **atmosphere_ln_pressure_coordinate** - Parametric atmosphere natural log pressure coordinate.
19
+ * **atmosphere_sigma_coordinate** - Parametric atmosphere sigma coordinate.
20
+ * **atmosphere_hybrid_sigma_pressure_coordinate** - Parametric atmosphere hybrid sigma pressure coordinate.
21
+ * **atmosphere_hybrid_height_coordinate** - Parametric atmosphere hybrid height coordinate.
22
+ * **atmosphere_sleve_coordinate** - Parametric atmosphere smooth vertical level coordinate.
23
+ * **depth** - Depth is the vertical distance below the earth's surface.
24
+ * **sea_water_pressure** - Sea water pressure is the pressure that exists in the medium of sea water.
25
+ * **sea_water_potential_temperature** - Sea water potential temperature is the temperature a parcel of sea water would have if moved adiabatically to sea level pressure.
26
+ * **ocean_sigma_coordinate** - Parametric ocean sigma coordinate.
27
+ * **ocean_s_coordinate** - Parametric ocean s-coordinate.
28
+ * **ocean_s_coordinate_g1** - Parametric ocean s-coordinate, generic form 1.
29
+ * **ocean_s_coordinate_g2** - Parametric ocean s-coordinate, generic form 2.
30
+ * **ocean_sigma_z_coordinate** - Parametric ocean sigma over z coordinate.
31
+ * **ocean_double_sigma_coordinate** - Parametric ocean double sigma coordinate.
32
+ * **land_ice_sigma_coordinate** - Land ice (glaciers, ice-caps and ice-sheets resting on bedrock and also includes ice-shelves) sigma coordinate.
33
+ * **z*** - (Not a standard name) The z* coordinate of Adcroft and Campin (2004).
50
34
  """
51
35
 
52
36
  pass
@@ -14,18 +14,17 @@ class Reference(PlainTermDataDescriptor):
14
14
  An academic reference to published work for the top-level model or one of its model
15
15
  components is defined by the following properties:
16
16
 
17
- Citation
18
- A human-readable citation for the work.
19
- E.g. Smith, R. S., Mathiot, P., Siahaan, A., Lee, V., Cornford, S. L., Gregory, J. M.,
20
- et al. (2021). Coupling the U.K. Earth System model to dynamic models of the Greenland
21
- and Antarctic ice sheets. Journal of Advances in Modeling Earth Systems, 13,
22
- e2021MS002520. https://doi.org/10.1029/2021MS002520, 2023
23
- DOI
24
- The persistent identifier (DOI) used to identify the work.
25
- A DOI is required for all references. A reference that does not already have a DOI
26
- (as could be the case for some technical reports, for instance) must be given one
27
- (e.g. with a service like Zenodo).
28
- ◦ E.g. https://doi.org/10.1029/2021MS002520
17
+ * **Citation** - A human-readable citation for the work.
18
+ E.g. Smith, R. S., Mathiot, P., Siahaan, A., Lee, V., Cornford, S. L., Gregory, J. M.,
19
+ et al. (2021). Coupling the U.K. Earth System model to dynamic models of the Greenland
20
+ and Antarctic ice sheets. Journal of Advances in Modeling Earth Systems, 13,
21
+ e2021MS002520. https://doi.org/10.1029/2021MS002520, 2023
22
+
23
+ * **DOI** - The persistent identifier (DOI) used to identify the work.
24
+ A DOI is required for all references. A reference that does not already have a DOI
25
+ (as could be the case for some technical reports, for instance) must be given one
26
+ (e.g. with a service like Zenodo).
27
+ E.g. https://doi.org/10.1029/2021MS002520
29
28
  """
30
29
 
31
30
  citation: str = Field(description="A human-readable citation for the work.", min_length=1)
@@ -3,46 +3,33 @@ from esgvoc.api.data_descriptors.data_descriptor import PlainTermDataDescriptor
3
3
 
4
4
  class EMDResolution(PlainTermDataDescriptor):
5
5
  """
6
- The nominal resolution (in km) characterises the resolution of a model's native horizontal grid. See section 5.1 Native horizontal grid properties.
7
- Options for the native horizontal grid nominal resolution property are defined in the following table as a function of the value of the mean resolution km property:
6
+ The nominal resolution (in km) characterises the resolution of a model's native horizontal grid.
8
7
 
9
- for mean resolution, R, in the range (km):
10
- nominal resolution is:
11
- 0.036 R < 0.072
12
- 0.05 km
13
- 0.072 ≤ R < 0.16
14
- 0.1 km
15
- 0.16 ≤ R < 0.36
16
- 0.25 km
17
- 0.36 ≤ R < 0.72
18
- 0.5 km
19
- 0.72 ≤ R < 1.6
20
- 1 km
21
- 1.6 ≤ R < 3.6
22
- 2.5 km
23
- 3.6 ≤ R < 7.2
24
- 5 km
25
- 7.2 ≤ R < 16
26
- 10 km
27
- 16 ≤ R < 36
28
- 25 km
29
- 36 ≤ R < 72
30
- 50 km
31
- 72 ≤ R < 160
32
- 100 km
33
- 160 ≤ R < 360
34
- 250 km
35
- 360 ≤ R < 720
36
- 500 km
37
- 720 ≤ R < 1600
38
- 1000 km
39
- 1600 ≤ R < 3600
40
- 2500 km
41
- 3600 ≤ R < 7200
42
- 5000 km
43
- 7200 ≤ R < 16000
44
- 10000 km
45
- 7.10. Native vertical grid "Coordinate" CV
8
+ See section 5.1 Native horizontal grid properties.
9
+ Options for the native horizontal grid nominal resolution property are defined
10
+ in the following table as a function of the value of the mean resolution km property:
11
+
12
+ ==================== ====================
13
+ Mean resolution R Nominal resolution
14
+ ==================== ====================
15
+ 0.036 ≤ R < 0.072 0.05 km
16
+ 0.072 ≤ R < 0.16 0.1 km
17
+ 0.16 ≤ R < 0.36 0.25 km
18
+ 0.36 ≤ R < 0.72 0.5 km
19
+ 0.72 ≤ R < 1.6 1 km
20
+ 1.6 ≤ R < 3.6 2.5 km
21
+ 3.6 ≤ R < 7.2 5 km
22
+ 7.2 ≤ R < 16 10 km
23
+ 16 ≤ R < 36 25 km
24
+ 36 ≤ R < 72 50 km
25
+ 72 ≤ R < 160 100 km
26
+ 160 ≤ R < 360 250 km
27
+ 360 ≤ R < 720 500 km
28
+ 720 ≤ R < 1600 1000 km
29
+ 1600 ≤ R < 3600 2500 km
30
+ 3600 ≤ R < 7200 5000 km
31
+ 7200 ≤ R < 16000 10000 km
32
+ ==================== ====================
46
33
  """
47
34
 
48
35
  mean_resolution: str
@@ -1,7 +1,7 @@
1
1
  from abc import ABC, abstractmethod
2
2
  from typing import Any, ClassVar, Protocol
3
3
 
4
- from pydantic import BaseModel, ConfigDict
4
+ from pydantic import BaseModel, ConfigDict, Field, model_serializer
5
5
 
6
6
 
7
7
  class ConfiguredBaseModel(BaseModel):
@@ -68,10 +68,39 @@ class DataDescriptor(ConfiguredBaseModel, ABC):
68
68
  class DataDescriptorSubSet(DataDescriptor):
69
69
  """
70
70
  A sub set of the information contains in a term.
71
+ When using selected_term_fields, only id is guaranteed to be present.
72
+ Other fields (type, description) may be None if not selected.
71
73
  """
72
74
 
73
- MANDATORY_TERM_FIELDS: ClassVar[tuple[str, str]] = ("id", "type")
74
- """The set of mandatory term fields."""
75
+ # Override inherited fields to make them truly optional using Field()
76
+ # Using default_factory to ensure Pydantic treats them as optional
77
+ type: str | None = Field(default=None, validate_default=False) # type: ignore[assignment]
78
+ """The data descriptor to which the term belongs (optional in subset)."""
79
+ description: str | None = Field(default=None, validate_default=False) # type: ignore[assignment]
80
+ """The description of the term (optional in subset)."""
81
+
82
+ MANDATORY_TERM_FIELDS: ClassVar[tuple[str]] = ("id",)
83
+ """The set of mandatory term fields (only id is guaranteed when using selected_term_fields)."""
84
+
85
+ @model_serializer(mode='wrap')
86
+ def serialize_model(self, serializer: Any) -> dict[str, Any]:
87
+ """
88
+ Custom serializer that only includes fields that actually exist on the instance.
89
+ This prevents Pydantic warnings when fields are removed via delattr().
90
+ Uses 'wrap' mode to override default serialization behavior completely.
91
+ """
92
+ # Serialize all attributes from __dict__ that are not private
93
+ result = {
94
+ field_name: field_value
95
+ for field_name, field_value in self.__dict__.items()
96
+ if not field_name.startswith('_')
97
+ }
98
+
99
+ # Also include extra fields (like drs_name) that are stored in __pydantic_extra__
100
+ if hasattr(self, '__pydantic_extra__') and self.__pydantic_extra__:
101
+ result.update(self.__pydantic_extra__)
102
+
103
+ return result
75
104
 
76
105
  def accept(self, visitor: DataDescriptorVisitor) -> Any:
77
106
  return visitor.visit_sub_set_term(self)
esgvoc/api/projects.py CHANGED
@@ -8,7 +8,7 @@ from sqlmodel import Session, and_, col, select
8
8
  import esgvoc.api.universe as universe
9
9
  import esgvoc.core.constants as constants
10
10
  import esgvoc.core.service as service
11
- from esgvoc.api.data_descriptors.data_descriptor import DataDescriptor
11
+ from esgvoc.api.data_descriptors.data_descriptor import DataDescriptor, DataDescriptorSubSet
12
12
  from esgvoc.api.project_specs import ProjectSpecs
13
13
  from esgvoc.api.report import ProjectTermError, UniverseTermError, ValidationReport
14
14
  from esgvoc.api.pydantic_handler import instantiate_pydantic_term
@@ -483,7 +483,7 @@ def valid_term_in_all_projects(value: str) -> list[MatchingTerm]:
483
483
 
484
484
  def get_all_terms_in_collection(
485
485
  project_id: str, collection_id: str, selected_term_fields: Iterable[str] | None = None
486
- ) -> list[DataDescriptor]:
486
+ ) -> list[DataDescriptor | DataDescriptorSubSet]:
487
487
  """
488
488
  Gets all terms of the given collection of a project.
489
489
  This function performs an exact match on the `project_id` and `collection_id`,
@@ -496,10 +496,13 @@ def get_all_terms_in_collection(
496
496
  :param collection_id: A collection id
497
497
  :type collection_id: str
498
498
  :param selected_term_fields: A list of term fields to select or `None`. If `None`, all the \
499
- fields of the terms are returned. If empty, selects the id and type fields.
499
+ fields of the terms are returned (full DataDescriptor). If provided, only the selected fields \
500
+ are included (returns DataDescriptorSubSet with id + selected fields that exist).
500
501
  :type selected_term_fields: Iterable[str] | None
501
- :returns: a list of term instances. Returns an empty list if no matches are found.
502
- :rtype: list[DataDescriptor]
502
+ :returns: A list of term instances. Each term is a full DataDescriptor when \
503
+ selected_term_fields is None, or a DataDescriptorSubSet when selected_term_fields is provided. \
504
+ Returns an empty list if no matches are found.
505
+ :rtype: list[DataDescriptor | DataDescriptorSubSet]
503
506
  """
504
507
  result = list()
505
508
  if connection := _get_project_connection(project_id):
@@ -610,7 +613,7 @@ def _get_all_terms_in_collection(
610
613
 
611
614
  def get_all_terms_in_project(
612
615
  project_id: str, selected_term_fields: Iterable[str] | None = None
613
- ) -> list[DataDescriptor]:
616
+ ) -> list[DataDescriptor | DataDescriptorSubSet]:
614
617
  """
615
618
  Gets all terms of the given project.
616
619
  This function performs an exact match on the `project_id` and
@@ -621,10 +624,13 @@ def get_all_terms_in_project(
621
624
  :param project_id: A project id
622
625
  :type project_id: str
623
626
  :param selected_term_fields: A list of term fields to select or `None`. If `None`, all the \
624
- fields of the terms are returned. If empty, selects the id and type fields.
627
+ fields of the terms are returned (full DataDescriptor). If provided, only the selected fields \
628
+ are included (returns DataDescriptorSubSet with id + selected fields that exist).
625
629
  :type selected_term_fields: Iterable[str] | None
626
- :returns: A list of term instances. Returns an empty list if no matches are found.
627
- :rtype: list[DataDescriptor]
630
+ :returns: A list of term instances. Each term is a full DataDescriptor when \
631
+ selected_term_fields is None, or a DataDescriptorSubSet when selected_term_fields is provided. \
632
+ Returns an empty list if no matches are found.
633
+ :rtype: list[DataDescriptor | DataDescriptorSubSet]
628
634
  """
629
635
  result = list()
630
636
  if connection := _get_project_connection(project_id):
@@ -638,15 +644,17 @@ def get_all_terms_in_project(
638
644
 
639
645
  def get_all_terms_in_all_projects(
640
646
  selected_term_fields: Iterable[str] | None = None,
641
- ) -> list[tuple[str, list[DataDescriptor]]]:
647
+ ) -> list[tuple[str, list[DataDescriptor | DataDescriptorSubSet]]]:
642
648
  """
643
649
  Gets all terms of all projects.
644
650
 
645
651
  :param selected_term_fields: A list of term fields to select or `None`. If `None`, all the \
646
- fields of the terms are returned. If empty, selects the id and type fields.
652
+ fields of the terms are returned (full DataDescriptor). If provided, only the selected fields \
653
+ are included (returns DataDescriptorSubSet with id + selected fields that exist).
647
654
  :type selected_term_fields: Iterable[str] | None
648
- :returns: A list of tuple project_id and term instances of that project.
649
- :rtype: list[tuple[str, list[DataDescriptor]]]
655
+ :returns: A list of tuples containing (project_id, terms). Each term is a full DataDescriptor when \
656
+ selected_term_fields is None, or a DataDescriptorSubSet when selected_term_fields is provided.
657
+ :rtype: list[tuple[str, list[DataDescriptor | DataDescriptorSubSet]]]
650
658
  """
651
659
  project_ids = get_all_projects()
652
660
  result = list()
@@ -676,7 +684,7 @@ def _get_term_in_project(term_id: str, session: Session) -> PTerm | None:
676
684
 
677
685
  def get_term_in_project(
678
686
  project_id: str, term_id: str, selected_term_fields: Iterable[str] | None = None
679
- ) -> DataDescriptor | None:
687
+ ) -> DataDescriptor | DataDescriptorSubSet | None:
680
688
  """
681
689
  Returns the first occurrence of the terms, in the given project, whose id corresponds exactly to
682
690
  the given term id.
@@ -691,12 +699,14 @@ def get_term_in_project(
691
699
  :param term_id: The id of a term to be found.
692
700
  :type term_id: str
693
701
  :param selected_term_fields: A list of term fields to select or `None`. If `None`, all the \
694
- fields of the terms are returned. If empty, selects the id and type fields.
702
+ fields of the terms are returned (full DataDescriptor). If provided, only the selected fields \
703
+ are included (returns DataDescriptorSubSet with id + selected fields that exist).
695
704
  :type selected_term_fields: Iterable[str] | None
696
- :returns: A term instance. Returns `None` if no match is found.
697
- :rtype: DataDescriptor | None
705
+ :returns: A term instance. The term is a full DataDescriptor when selected_term_fields is None, \
706
+ or a DataDescriptorSubSet when selected_term_fields is provided. Returns `None` if no match is found.
707
+ :rtype: DataDescriptor | DataDescriptorSubSet | None
698
708
  """
699
- result: DataDescriptor | None = None
709
+ result: DataDescriptor | DataDescriptorSubSet | None = None
700
710
  if connection := _get_project_connection(project_id):
701
711
  with connection.create_session() as session:
702
712
  term_found = _get_term_in_project(term_id, session)
@@ -714,7 +724,7 @@ def _get_term_in_collection(collection_id: str, term_id: str, session: Session)
714
724
 
715
725
  def get_term_in_collection(
716
726
  project_id: str, collection_id: str, term_id: str, selected_term_fields: Iterable[str] | None = None
717
- ) -> DataDescriptor | None:
727
+ ) -> DataDescriptor | DataDescriptorSubSet | None:
718
728
  """
719
729
  Returns the term, in the given project and collection,
720
730
  whose id corresponds exactly to the given term id.
@@ -730,12 +740,14 @@ def get_term_in_collection(
730
740
  :param term_id: The id of a term to be found.
731
741
  :type term_id: str
732
742
  :param selected_term_fields: A list of term fields to select or `None`. If `None`, all the \
733
- fields of the terms are returned. If empty, selects the id and type fields.
743
+ fields of the terms are returned (full DataDescriptor). If provided, only the selected fields \
744
+ are included (returns DataDescriptorSubSet with id + selected fields that exist).
734
745
  :type selected_term_fields: Iterable[str] | None
735
- :returns: A term instance. Returns `None` if no match is found.
736
- :rtype: DataDescriptor | None
746
+ :returns: A term instance. The term is a full DataDescriptor when selected_term_fields is None, \
747
+ or a DataDescriptorSubSet when selected_term_fields is provided. Returns `None` if no match is found.
748
+ :rtype: DataDescriptor | DataDescriptorSubSet | None
737
749
  """
738
- result: DataDescriptor | None = None
750
+ result: DataDescriptor | DataDescriptorSubSet | None = None
739
751
  if connection := _get_project_connection(project_id):
740
752
  with connection.create_session() as session:
741
753
  term_found = _get_term_in_collection(collection_id, term_id, session)
@@ -871,7 +883,7 @@ def _get_term_from_universe_term_id_in_project(
871
883
 
872
884
  def get_term_from_universe_term_id_in_project(
873
885
  project_id: str, data_descriptor_id: str, universe_term_id: str, selected_term_fields: Iterable[str] | None = None
874
- ) -> tuple[str, DataDescriptor] | None:
886
+ ) -> tuple[str, DataDescriptor | DataDescriptorSubSet] | None:
875
887
  """
876
888
  Returns the term, in the given project, that corresponds to the given term in the universe.
877
889
  This function performs an exact match on the `project_id`, `data_descriptor_id`
@@ -887,12 +899,15 @@ def get_term_from_universe_term_id_in_project(
887
899
  :param universe_term_id: The id of the given universe term.
888
900
  :type universe_term_id: str
889
901
  :param selected_term_fields: A list of term fields to select or `None`. If `None`, all the \
890
- fields of the terms are returned. If empty, selects the id and type fields.
902
+ fields of the terms are returned (full DataDescriptor). If provided, only the selected fields \
903
+ are included (returns DataDescriptorSubSet with id + selected fields that exist).
891
904
  :type selected_term_fields: Iterable[str] | None
892
- :returns: A collection id and the project term instance. Returns `None` if no matches are found.
893
- :rtype: tuple[str, DataDescriptor] | None
905
+ :returns: A collection id and the project term instance. The term is a full DataDescriptor when \
906
+ selected_term_fields is None, or a DataDescriptorSubSet when selected_term_fields is provided. \
907
+ Returns `None` if no matches are found.
908
+ :rtype: tuple[str, DataDescriptor | DataDescriptorSubSet] | None
894
909
  """
895
- result: tuple[str, DataDescriptor] | None = None
910
+ result: tuple[str, DataDescriptor | DataDescriptorSubSet] | None = None
896
911
  if connection := _get_project_connection(project_id):
897
912
  with connection.create_session() as session:
898
913
  term_found = _get_term_from_universe_term_id_in_project(data_descriptor_id, universe_term_id, session)
@@ -904,7 +919,7 @@ def get_term_from_universe_term_id_in_project(
904
919
 
905
920
  def get_term_from_universe_term_id_in_all_projects(
906
921
  data_descriptor_id: str, universe_term_id: str, selected_term_fields: Iterable[str] | None = None
907
- ) -> list[tuple[str, str, DataDescriptor]]:
922
+ ) -> list[tuple[str, str, DataDescriptor | DataDescriptorSubSet]]:
908
923
  """
909
924
  Returns the terms, in all projects, that correspond to the given term in the universe.
910
925
  This function performs an exact match on the `data_descriptor_id`
@@ -918,13 +933,15 @@ def get_term_from_universe_term_id_in_all_projects(
918
933
  :param universe_term_id: The id of the given universe term.
919
934
  :type universe_term_id: str
920
935
  :param selected_term_fields: A list of term fields to select or `None`. If `None`, all the \
921
- fields of the terms are returned. If empty, selects the id and type fields.
936
+ fields of the terms are returned (full DataDescriptor). If provided, only the selected fields \
937
+ are included (returns DataDescriptorSubSet with id + selected fields that exist).
922
938
  :type selected_term_fields: Iterable[str] | None
923
- :returns: A project_id, collection id and the project term instance. \
924
- Returns an empty list if no matches are found.
925
- :rtype: list[tuple[str, str, DataDescriptor]]
939
+ :returns: A list of tuples containing (project_id, collection_id, term). The term is a full \
940
+ DataDescriptor when selected_term_fields is None, or a DataDescriptorSubSet when \
941
+ selected_term_fields is provided. Returns an empty list if no matches are found.
942
+ :rtype: list[tuple[str, str, DataDescriptor | DataDescriptorSubSet]]
926
943
  """
927
- result: list[tuple[str, str, DataDescriptor]] = list()
944
+ result: list[tuple[str, str, DataDescriptor | DataDescriptorSubSet]] = list()
928
945
  project_ids = get_all_projects()
929
946
  for project_id in project_ids:
930
947
  term_found = get_term_from_universe_term_id_in_project(
@@ -6,7 +6,7 @@ import esgvoc.core.constants as api_settings
6
6
  from esgvoc.core.exceptions import EsgvocDbError
7
7
 
8
8
  if TYPE_CHECKING:
9
- from esgvoc.api.data_descriptors.data_descriptor import DataDescriptor
9
+ from esgvoc.api.data_descriptors.data_descriptor import DataDescriptor, DataDescriptorSubSet
10
10
  from esgvoc.core.db.models.project import PTerm
11
11
  from esgvoc.core.db.models.universe import UTerm
12
12
 
@@ -103,7 +103,7 @@ def get_pydantic_class(data_descriptor_id_or_term_type: str) -> type["DataDescri
103
103
  raise EsgvocDbError(f"'{data_descriptor_id_or_term_type}' pydantic class not found")
104
104
 
105
105
 
106
- def instantiate_pydantic_term(term: "UTerm | PTerm", selected_term_fields: Iterable[str] | None) -> "DataDescriptor":
106
+ def instantiate_pydantic_term(term: "UTerm | PTerm", selected_term_fields: Iterable[str] | None) -> "DataDescriptor | DataDescriptorSubSet":
107
107
  """
108
108
  Instantiate a Pydantic DataDescriptor from a database term.
109
109
 
@@ -112,32 +112,42 @@ def instantiate_pydantic_term(term: "UTerm | PTerm", selected_term_fields: Itera
112
112
  selected_term_fields: Optional list of specific fields to include. If None, all fields are included.
113
113
 
114
114
  Returns:
115
- A DataDescriptor instance (either DataDescriptorSubSet or the full model)
115
+ A DataDescriptor instance (full model) when selected_term_fields is None,
116
+ or a DataDescriptorSubSet instance when selected_term_fields is provided.
116
117
  """
117
118
  from esgvoc.api.data_descriptors.data_descriptor import DataDescriptorSubSet
118
119
 
119
120
  type = term.specs[api_settings.TERM_TYPE_JSON_KEY]
120
121
  if selected_term_fields is not None:
121
- subset = DataDescriptorSubSet(id=term.id, type=type)
122
-
123
- # Get model field defaults to use when fields are missing from term.specs
124
- model_fields = DataDescriptorSubSet.model_fields
122
+ # Build data dict with only id (truly mandatory) + selected fields
123
+ data = {
124
+ "id": term.id,
125
+ }
125
126
 
127
+ # Add selected fields from term.specs, but only if they exist
126
128
  for field in selected_term_fields:
127
- # Use model's default value if field is missing from specs
128
- if field in model_fields and field not in term.specs:
129
- default_value = model_fields[field].default
130
- setattr(subset, field, default_value if default_value is not None else term.specs.get(field, None))
131
- else:
132
- setattr(subset, field, term.specs.get(field, None))
129
+ if field in term.specs:
130
+ data[field] = term.specs[field]
131
+
132
+ # Create instance with all fields initially
133
+ # We need type for validation, will remove it if not selected
134
+ if "type" not in data:
135
+ data["type"] = type
136
+ if "description" not in data:
137
+ data["description"] = "" # Use default value
138
+
139
+ subset = DataDescriptorSubSet.model_construct(**data)
140
+
141
+ # Now remove unselected optional fields using delattr
142
+ # This maintains backward compatibility (hasattr will return False)
143
+ if "type" not in selected_term_fields and hasattr(subset, "type"):
144
+ delattr(subset, "type")
145
+ if "description" not in selected_term_fields and hasattr(subset, "description"):
146
+ delattr(subset, "description")
147
+
148
+ # Mark which fields were actually set
149
+ subset.__pydantic_fields_set__ = {"id"} | set(selected_term_fields)
133
150
 
134
- for field in DataDescriptorSubSet.MANDATORY_TERM_FIELDS:
135
- # Use model's default value if field is missing from specs
136
- if field in model_fields and field not in term.specs:
137
- default_value = model_fields[field].default
138
- setattr(subset, field, default_value if default_value is not None else term.specs.get(field, None))
139
- else:
140
- setattr(subset, field, term.specs.get(field, None))
141
151
  return subset
142
152
  else:
143
153
  term_class = get_pydantic_class(type)
esgvoc/api/universe.py CHANGED
@@ -3,7 +3,7 @@ from typing import Iterable, Sequence
3
3
  from sqlalchemy import text
4
4
  from sqlmodel import Session, col, select
5
5
 
6
- from esgvoc.api.data_descriptors.data_descriptor import DataDescriptor
6
+ from esgvoc.api.data_descriptors.data_descriptor import DataDescriptor, DataDescriptorSubSet
7
7
  from esgvoc.api.pydantic_handler import instantiate_pydantic_term
8
8
  from esgvoc.api.search import (
9
9
  Item,
@@ -28,7 +28,7 @@ def _get_all_terms_in_data_descriptor(
28
28
 
29
29
  def get_all_terms_in_data_descriptor(
30
30
  data_descriptor_id: str, selected_term_fields: Iterable[str] | None = None
31
- ) -> list[DataDescriptor]:
31
+ ) -> list[DataDescriptor | DataDescriptorSubSet]:
32
32
  """
33
33
  Gets all the terms of the given data descriptor.
34
34
  This function performs an exact match on the `data_descriptor_id` and does not search
@@ -38,10 +38,13 @@ def get_all_terms_in_data_descriptor(
38
38
  :param data_descriptor_id: A data descriptor id
39
39
  :type data_descriptor_id: str
40
40
  :param selected_term_fields: A list of term fields to select or `None`. If `None`, all the \
41
- fields of the terms are returned. If empty, selects the id and type fields.
41
+ fields of the terms are returned (full DataDescriptor). If provided, only the selected fields \
42
+ are included (returns DataDescriptorSubSet with id + selected fields that exist).
42
43
  :type selected_term_fields: Iterable[str] | None
43
- :returns: a list of term instances. Returns an empty list if no matches are found.
44
- :rtype: list[DataDescriptor]
44
+ :returns: A list of term instances. Each term is a full DataDescriptor when \
45
+ selected_term_fields is None, or a DataDescriptorSubSet when selected_term_fields is provided. \
46
+ Returns an empty list if no matches are found.
47
+ :rtype: list[DataDescriptor | DataDescriptorSubSet]
45
48
  """
46
49
  with get_universe_session() as session:
47
50
  data_descriptor = _get_data_descriptor_in_universe(data_descriptor_id, session)
@@ -74,16 +77,18 @@ def get_all_data_descriptors_in_universe() -> list[str]:
74
77
  return result
75
78
 
76
79
 
77
- def get_all_terms_in_universe(selected_term_fields: Iterable[str] | None = None) -> list[DataDescriptor]:
80
+ def get_all_terms_in_universe(selected_term_fields: Iterable[str] | None = None) -> list[DataDescriptor | DataDescriptorSubSet]:
78
81
  """
79
82
  Gets all the terms of the universe.
80
83
  Terms are unique within a data descriptor but may have some synonyms in the universe.
81
84
 
82
85
  :param selected_term_fields: A list of term fields to select or `None`. If `None`, all the \
83
- fields of the terms are returned. If empty, selects the id and type fields.
86
+ fields of the terms are returned (full DataDescriptor). If provided, only the selected fields \
87
+ are included (returns DataDescriptorSubSet with id + selected fields that exist).
84
88
  :type selected_term_fields: Iterable[str] | None
85
- :returns: A list of term instances.
86
- :rtype: list[DataDescriptor]
89
+ :returns: A list of term instances. Each term is a full DataDescriptor when \
90
+ selected_term_fields is None, or a DataDescriptorSubSet when selected_term_fields is provided.
91
+ :rtype: list[DataDescriptor | DataDescriptorSubSet]
87
92
  """
88
93
  result = list()
89
94
  with get_universe_session() as session:
@@ -104,7 +109,7 @@ def _get_term_in_data_descriptor(data_descriptor_id: str, term_id: str, session:
104
109
 
105
110
  def get_term_in_data_descriptor(
106
111
  data_descriptor_id: str, term_id: str, selected_term_fields: Iterable[str] | None = None
107
- ) -> DataDescriptor | None:
112
+ ) -> DataDescriptor | DataDescriptorSubSet | None:
108
113
  """
109
114
  Returns the term, in the given data descriptor, whose id corresponds exactly to the given term id.
110
115
  This function performs an exact match on the `term_id` and the `data_descriptor_id` and does
@@ -116,10 +121,12 @@ def get_term_in_data_descriptor(
116
121
  :param term_id: The id of a term to be found.
117
122
  :type term_id: str
118
123
  :param selected_term_fields: A list of term fields to select or `None`. If `None`, all the \
119
- fields of the terms are returned. If empty, selects the id and type fields.
124
+ fields of the terms are returned (full DataDescriptor). If provided, only the selected fields \
125
+ are included (returns DataDescriptorSubSet with id + selected fields that exist).
120
126
  :type selected_term_fields: Iterable[str] | None
121
- :returns: A term instance. Returns `None` if no match is found.
122
- :rtype: DataDescriptor | None
127
+ :returns: A term instance. The term is a full DataDescriptor when selected_term_fields is None, \
128
+ or a DataDescriptorSubSet when selected_term_fields is provided. Returns `None` if no match is found.
129
+ :rtype: DataDescriptor | DataDescriptorSubSet | None
123
130
  """
124
131
  with get_universe_session() as session:
125
132
  term_found = _get_term_in_data_descriptor(data_descriptor_id, term_id, session)
@@ -137,7 +144,7 @@ def _get_term_in_universe(term_id: str, session: Session) -> UTerm | None:
137
144
  return result
138
145
 
139
146
 
140
- def get_term_in_universe(term_id: str, selected_term_fields: Iterable[str] | None = None) -> DataDescriptor | None:
147
+ def get_term_in_universe(term_id: str, selected_term_fields: Iterable[str] | None = None) -> DataDescriptor | DataDescriptorSubSet | None:
141
148
  """
142
149
  Returns the first occurrence of the terms, in the universe, whose id corresponds exactly to
143
150
  the given term id.
@@ -148,10 +155,12 @@ def get_term_in_universe(term_id: str, selected_term_fields: Iterable[str] | Non
148
155
  :param term_id: The id of a term to be found.
149
156
  :type term_id: str
150
157
  :param selected_term_fields: A list of term fields to select or `None`. If `None`, all the \
151
- fields of the terms are returned. If empty, selects the id and type fields.
158
+ fields of the terms are returned (full DataDescriptor). If provided, only the selected fields \
159
+ are included (returns DataDescriptorSubSet with id + selected fields that exist).
152
160
  :type selected_term_fields: Iterable[str] | None
153
- :returns: A term instance. Returns `None` if no match is found.
154
- :rtype: DataDescriptor | None
161
+ :returns: A term instance. The term is a full DataDescriptor when selected_term_fields is None, \
162
+ or a DataDescriptorSubSet when selected_term_fields is provided. Returns `None` if no match is found.
163
+ :rtype: DataDescriptor | DataDescriptorSubSet | None
155
164
  """
156
165
  with get_universe_session() as session:
157
166
  term_found = _get_term_in_universe(term_id, session)
esgvoc/cli/get.py CHANGED
@@ -107,7 +107,7 @@ def display(data: Any):
107
107
  @app.command()
108
108
  def get(
109
109
  keys: List[str] = typer.Argument(..., help="List of keys in XXXX:YYYY:ZZZZ format"),
110
- select: Optional[List[str]] = typer.Option(None, "--select", help="keys selected for the result"),
110
+ select: Optional[List[str]] = typer.Option(None, "--select", help="keys selected for the result. Can be used as --select field1 --select field2 or --select [field1,field2]"),
111
111
  ):
112
112
  """
113
113
  Retrieve a specific value from the database system.\n
@@ -117,25 +117,65 @@ def get(
117
117
 
118
118
  Usage:\n
119
119
  `get <project>:<collection>:<term>`\n
120
+ `get <project>:<collection>:<term> --select <field>`\n
121
+ `get <project>:<collection>:<term> --select [<field1>,<field2>,...]`\n
120
122
  \n
121
123
  Arguments:\n
122
124
  <project>\tThe project id to query. like `cmip6plus`\n
123
125
  <collection>\tThe collection id in the specified database.\n
124
126
  <term>\t\tThe term id within the specified collection.\n
125
127
  \n
126
- Example:
127
- To retrieve the value from the "cmip6plus" project, under the "institution_id" column, the term with the identifier "ipsl", you would use: \n
128
+ Options:\n
129
+ --select\tSelect specific fields to display. By default, all fields are returned.\n
130
+ \t\tThe result will always include the 'id' field plus the selected fields.\n
131
+ \t\tYou can use this option in multiple ways:\n
132
+ \t\t - Single field: --select drs_name\n
133
+ \t\t - Multiple flags: --select drs_name --select description\n
134
+ \t\t - Bracket notation: --select [drs_name,description]\n
135
+ \n
136
+ Examples:\n
137
+ Retrieve full term information:\n
128
138
  `get cmip6plus:institution_id:ipsl`\n
129
- The default project is the universe CV : the argument would be like `universe:institution:ipsl` or `:institution:ipsl` \n
130
- - to get list of available term from universe institution `:institution:` \n
139
+ \n
140
+ Retrieve only specific fields:\n
141
+ `get :activity:volmip --select drs_name`\n
142
+ Returns: id='volmip' drs_name='VolMIP'\n
143
+ \n
144
+ Retrieve multiple fields using bracket notation:\n
145
+ `get :activity:volmip --select [drs_name,description]`\n
146
+ Returns: id='volmip' drs_name='VolMIP' description=...\n
147
+ \n
148
+ Retrieve multiple fields using multiple flags:\n
149
+ `get :activity:volmip --select drs_name --select description`\n
150
+ \n
151
+ List all terms in a collection with selected fields:\n
152
+ `get :activity: --select drs_name`\n
153
+ \n
154
+ The default project is the universe CV: the argument would be like `universe:institution:ipsl` or `:institution:ipsl`\n
131
155
  \n
132
156
  \n
133
157
  Notes:\n
134
158
  - Ensure data exist in your system before using this command (use `esgvoc status` command to see whats available).\n
135
159
  - Use a colon (`:`) to separate the parts of the argument. \n
136
- - if more than one argument is given i.e get X:Y:Z A:B:C the 2 results are appended. \n
160
+ - If more than one argument is given i.e get X:Y:Z A:B:C the 2 results are appended. \n
161
+ - The 'id' field is always included in the result, even when using --select.\n
137
162
  \n
138
163
  """
164
+ # Parse select parameter to handle bracket notation [field1,field2,...]
165
+ parsed_select = None
166
+ if select is not None:
167
+ parsed_select = []
168
+ for item in select:
169
+ # Check if item is in bracket notation like [field1,field2]
170
+ if item.startswith("[") and item.endswith("]"):
171
+ # Remove brackets and split by comma
172
+ fields = item[1:-1].split(",")
173
+ # Strip whitespace and quotes from each field
174
+ parsed_select.extend([f.strip().strip("'\"") for f in fields if f.strip()])
175
+ else:
176
+ # Regular field, just add it
177
+ parsed_select.append(item.strip().strip("'\""))
178
+
139
179
  known_projects = get_all_projects()
140
180
 
141
181
  # Validate and process each key
@@ -146,9 +186,9 @@ def get(
146
186
  what = what if what != "" else None
147
187
  who = who if who != "" else None
148
188
  if where == "" or where == "universe":
149
- res = handle_universe(what, who, select)
189
+ res = handle_universe(what, who, parsed_select)
150
190
  elif where in known_projects:
151
- res = handle_project(where, what, who, select)
191
+ res = handle_project(where, what, who, parsed_select)
152
192
  else:
153
193
  res = handle_unknown(where, what, who)
154
194
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: esgvoc
3
- Version: 2.0.2
3
+ Version: 2.1.0
4
4
  Summary: python library and CLI to interact with WCRP CVs
5
5
  Project-URL: Repository, https://github.com/ESGF/esgf-vocab
6
6
  Author-email: Sébastien Gardoll <sebastien@gardoll.fr>, Guillaume Levavasseur <guillaume.levavasseur@ipsl.fr>, Laurent Troussellier <laurent.troussellier@ipsl.fr>
@@ -1,12 +1,12 @@
1
- esgvoc/__init__.py,sha256=7eC8qPIlBApL95flwVy-OGVzl6hUFFu0pPPTPUtd7k0,66
1
+ esgvoc/__init__.py,sha256=2csMOm138N0yfN9CTw8qW94oSOWgtMvOh5_oryxlx9E,66
2
2
  esgvoc/api/__init__.py,sha256=5MK2lhD2L8DC_qlVjj5KNJNQ90UkX60eoPJOBuSG18A,3916
3
3
  esgvoc/api/project_specs.py,sha256=-kjNx6EcFRKJrMU7yy_0YmMqTv4Crvh4e2fPI2wGrbI,4285
4
- esgvoc/api/projects.py,sha256=dhvBhAAokptUvkA3B9tPfoQsD4F-jGCSA4t5tThXcgw,59018
4
+ esgvoc/api/projects.py,sha256=6KCmVnTOnni6DcNK8oQi8TRdBQJ5ftg7RF2a1-tMOvc,61187
5
5
  esgvoc/api/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- esgvoc/api/pydantic_handler.py,sha256=vWNBlzkQu_fx1bbfmAcFZts9C36VfBd-9yge5q54TLQ,6058
6
+ esgvoc/api/pydantic_handler.py,sha256=10m7h7WlMDwaToaa7FVAB5bV9I_7_dzY7QhupxsPuVQ,6254
7
7
  esgvoc/api/report.py,sha256=OlK5ApnaikMKmC6FyJ1uTSBeTezZe85yTCJwsk14uZE,3526
8
8
  esgvoc/api/search.py,sha256=W0RHTymqn67exjp0DJWNMC9mxX4EpMgLKEdMXsOYeLw,6665
9
- esgvoc/api/universe.py,sha256=K0BbX8bCM2x0OY_-fkd0UCEj4_Vq4hRE7UVn43OvEKw,21257
9
+ esgvoc/api/universe.py,sha256=6w4va8sm0afunAOjelfIwE7kytMT5a_RA-czw4JT3hA,22455
10
10
  esgvoc/api/data_descriptors/__init__.py,sha256=yqTDrr7VydWPUUkoZ3EC9c4xclHrKXKscSDB8cnELmM,8090
11
11
  esgvoc/api/data_descriptors/activity.py,sha256=ZJ5_jHNaFcX78Hho_ve-G7YiArSm_-U7wVd0rtnKzoE,2179
12
12
  esgvoc/api/data_descriptors/archive.py,sha256=5tmY5AsKAvyoU8839VdzLCbvP0pAhrCYP6EggZXFMTY,131
@@ -17,7 +17,7 @@ esgvoc/api/data_descriptors/citation_url.py,sha256=R0bjM8MU6IdqvLzc4q0aeAbndmRod
17
17
  esgvoc/api/data_descriptors/contact.py,sha256=q1tNm8VcG7xvv4ophVIuy58_2y-rSozs86c7_gMupdk,135
18
18
  esgvoc/api/data_descriptors/conventions.py,sha256=U3qugWG1KRIqxQqvUTFFc5v9DtTdxNAIQxc_bZAA6ns,1072
19
19
  esgvoc/api/data_descriptors/creation_date.py,sha256=QftPsJwoEmpitTs6xnWHVGZytppYymiouD33Vanp8gM,566
20
- esgvoc/api/data_descriptors/data_descriptor.py,sha256=p-ACPn8gRfZ4N7TK2Vno95KHr-WOKjSNhX_oDdfi0g0,3281
20
+ esgvoc/api/data_descriptors/data_descriptor.py,sha256=ndenK4yInquk8ehiuIAQpIuZH9xkCVhffUU7z1mOwxI,4832
21
21
  esgvoc/api/data_descriptors/data_specs_version.py,sha256=Sy1JI2bZOP0RNylkGMfJveV-OhSQgyPYCwkhUuKDHyo,1003
22
22
  esgvoc/api/data_descriptors/date.py,sha256=mkWivY0orl0wha38sMamrVbUbdZks-iUS_Wf6Gqz0-4,132
23
23
  esgvoc/api/data_descriptors/directory_date.py,sha256=lq50IGnUrgWstPHjwW0w0_DMFDYDet19BesZWly9nQE,743
@@ -62,7 +62,7 @@ esgvoc/api/data_descriptors/EMD_models/arrangement.py,sha256=W8PR1dJ4DJTKDIY2h-z
62
62
  esgvoc/api/data_descriptors/EMD_models/calendar.py,sha256=jBLtjK5aQBoPPnWzPse6ZDRhlcBAjvEAJitBvm1kmZU,132
63
63
  esgvoc/api/data_descriptors/EMD_models/cell_variable_type.py,sha256=T12HPRU1l3HGoQEkfMLee7NQjwE_nOyBIU5mIk6hd1I,488
64
64
  esgvoc/api/data_descriptors/EMD_models/component_type.py,sha256=3oMEtc9DMqHnN09zbRNKN6FEHub5i4O_Umw_5j0of6E,137
65
- esgvoc/api/data_descriptors/EMD_models/coordinate.py,sha256=siYPtEeyBfrXnwIIyVKYYlhlFQQTjOu0yKMeHG11lgU,2795
65
+ esgvoc/api/data_descriptors/EMD_models/coordinate.py,sha256=5YNb8eT0bGES4_FoQ-1yH3WolXZkJ3SawBVk4pY6Y4Q,2470
66
66
  esgvoc/api/data_descriptors/EMD_models/grid_mapping.py,sha256=dI0tH5Ag36af-39OYNuKKKoF52xyxRhtN8Xd3z3D6F4,436
67
67
  esgvoc/api/data_descriptors/EMD_models/grid_region.py,sha256=GUaJwSidLHVCdKNJetPgAAoqyBqMfyRWx9495Y1-T7k,445
68
68
  esgvoc/api/data_descriptors/EMD_models/grid_type.py,sha256=Z4MFHr8WWIVskv8w9JsjtFeaSaAyWYfjuNdCuxt52_Y,444
@@ -72,8 +72,8 @@ esgvoc/api/data_descriptors/EMD_models/horizontal_subgrid.py,sha256=vSUsrDhRX6VV
72
72
  esgvoc/api/data_descriptors/EMD_models/horizontal_units.py,sha256=npSeoQNf0-OqFCzhLGwZGXIjoTK2R7DE288o3-qPYLQ,139
73
73
  esgvoc/api/data_descriptors/EMD_models/model.py,sha256=CGQ9iosUqHr0zboJnugEsPJxMBgWiOp7WX6dxE8dCfw,5031
74
74
  esgvoc/api/data_descriptors/EMD_models/model_component.py,sha256=Cy3kF2HccH5VObes3AWcEdimOw5JSBMGhP3Yr8-Op4c,4629
75
- esgvoc/api/data_descriptors/EMD_models/reference.py,sha256=ZjNsbXQkcAMFsLSPVbQG_5sq2ovBhKa-309yRLydkOY,2517
76
- esgvoc/api/data_descriptors/EMD_models/resolution.py,sha256=CcBUAzeYSkvVjeCfhFSwTND6atldZQxS3rzNZqldmjI,1162
75
+ esgvoc/api/data_descriptors/EMD_models/reference.py,sha256=-Gywq1a-H1yhqJSjI_Vn9HAalGX_A5iXrGjNfmq71Fg,2464
76
+ esgvoc/api/data_descriptors/EMD_models/resolution.py,sha256=iFT4Bm0xiK4AKgzMdQ1u9_9Zf0_HfQivGvITiR8Hv3I,1261
77
77
  esgvoc/api/data_descriptors/EMD_models/temporal_refinement.py,sha256=7vSJb5kUkoH_0AWKOLO-MsuJ9JCYGsuE0ts4CbQm09A,421
78
78
  esgvoc/api/data_descriptors/EMD_models/truncation_method.py,sha256=TBKVGeha7Tjg2xSrLVRzhCQdQc5Y14Vx-aoVjJRz1eQ,383
79
79
  esgvoc/api/data_descriptors/EMD_models/vertical_computational_grid.py,sha256=3EQtYfLI8ncYkxrvnPgaoPvdNTqdzLNcjW8AkSjlG9U,4176
@@ -110,7 +110,7 @@ esgvoc/cli/cmor.py,sha256=Q1Q0AvP3Up8wAkylSGveBw1c_Mqo752wEE2NTUDqCYw,1098
110
110
  esgvoc/cli/config.py,sha256=iPU6OKkHQEo2qXdzjl35C5-C_I8pu122E2H7xj0HpYs,52555
111
111
  esgvoc/cli/drs.py,sha256=X89syVrxs82ZIc1YdWRPw_HmafOZH1u-wXRe6N-xBcM,9427
112
112
  esgvoc/cli/find.py,sha256=DxpEvSbQIJ3-XL-pgH5RicBzS3asjG2Cn_fJhjXKSoU,4497
113
- esgvoc/cli/get.py,sha256=Ucz0nE68wLB3K55aJfDnVNt8jCvPvBL4c1qmS_YHTh0,5451
113
+ esgvoc/cli/get.py,sha256=hxVUEkVOcZPq47fHXA4SRPTwlCYDvLN3g-6sw9S8so8,7368
114
114
  esgvoc/cli/install.py,sha256=qTtWQp0SlpQ7uIJnUeFUfdU0RRb2s55QAv11TogfwGk,1381
115
115
  esgvoc/cli/main.py,sha256=QzDhSXRnc1e3RlXD7KJBCwlnQV_DL-f9zaAlzlqoyx4,1866
116
116
  esgvoc/cli/offline.py,sha256=I9gccId98FLXPQ9VOmmZQ9aU_zfZYtCGZyO7XabQnc8,9007
@@ -140,8 +140,8 @@ esgvoc/core/service/term_cache.py,sha256=xH8No2w8KXDg7N3L9b4bv-dMGwqvlbko1bPxPMT
140
140
  esgvoc/core/service/uri_resolver.py,sha256=USDvnEkJwPJgdGduup_EQJODHZyAWj62MG8-AEaLMTo,3963
141
141
  esgvoc/core/service/configuration/config_manager.py,sha256=adKeK8xDE72UIfYqQ4pc7pPxAmBuCsybyx7ZdchbL6U,8797
142
142
  esgvoc/core/service/configuration/setting.py,sha256=aaBE6P8TttQr0kJjSRNH4Vaa_guWPFQGHdB24B1oYtU,13514
143
- esgvoc-2.0.2.dist-info/METADATA,sha256=H-uYgjZG98AWezy4zTNgd-LULeUrJfnUU0waFg1N4jw,2368
144
- esgvoc-2.0.2.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
145
- esgvoc-2.0.2.dist-info/entry_points.txt,sha256=ZXufSC7Jlx1lb52U6Buv9IitJMcqAAXOerR2V9DaIto,48
146
- esgvoc-2.0.2.dist-info/licenses/LICENSE.txt,sha256=rWJoZt3vach8ZNdLq-Ee5djzCMFnJ1gIfBeJU5RIop4,21782
147
- esgvoc-2.0.2.dist-info/RECORD,,
143
+ esgvoc-2.1.0.dist-info/METADATA,sha256=NSc8Jrv6DX_8Kaav4TQfyjryfJ-lc7vcjtL0_92aPbE,2368
144
+ esgvoc-2.1.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
145
+ esgvoc-2.1.0.dist-info/entry_points.txt,sha256=ZXufSC7Jlx1lb52U6Buv9IitJMcqAAXOerR2V9DaIto,48
146
+ esgvoc-2.1.0.dist-info/licenses/LICENSE.txt,sha256=rWJoZt3vach8ZNdLq-Ee5djzCMFnJ1gIfBeJU5RIop4,21782
147
+ esgvoc-2.1.0.dist-info/RECORD,,
File without changes