the-datagarden-models 0.0.1__tar.gz

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.
@@ -0,0 +1,9 @@
1
+ Metadata-Version: 2.1
2
+ Name: the-datagarden-models
3
+ Version: 0.0.1
4
+ Summary: Base data models for the datagarden
5
+ Author: Maarten de Ruyter
6
+ Author-email: "Maarten de Ruyter" <maarten@geodatagarden.com>
7
+ License: MIT
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Requires-Dist: pydantic
@@ -0,0 +1,3 @@
1
+ [build-system]
2
+ requires = ["setuptools", "wheel"]
3
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,106 @@
1
+ [metadata]
2
+ name = the-datagarden-models
3
+ version = 0.0.1
4
+ author = Maarten de Ruyter
5
+ author_email = "Maarten de Ruyter" <maarten@geodatagarden.com>
6
+ license = MIT
7
+ license_files = LICENSE
8
+ classifiers =
9
+ License :: OSI Approved :: MIT License
10
+ description = Base data models for the datagarden
11
+ long_description = file: README.rst, CHANGELOG.rst
12
+
13
+ [options]
14
+ package_dir =
15
+ =src
16
+ packages = find:
17
+ install_requires =
18
+ pydantic
19
+ include_package_data = True
20
+
21
+ [options.packages.find]
22
+ where = src
23
+ exclude =
24
+ tests*
25
+
26
+ [mypy]
27
+ python_version = 3.12
28
+ warn_unused_configs = True
29
+ show_error_context = True
30
+ pretty = True
31
+ namespace_packages = True
32
+ check_untyped_defs = True
33
+
34
+ [flake8]
35
+ max-line-length = 88
36
+
37
+ [tool:pytest]
38
+ testpaths = tests
39
+ addopts = --cov --strict-markers
40
+ xfail_strict = True
41
+
42
+ [coverage:run]
43
+ source = record_convertor
44
+ branch = True
45
+
46
+ [coverage:report]
47
+ show_missing = True
48
+ skip_covered = True
49
+
50
+ [coverage:paths]
51
+ source =
52
+ src/datagarden_models
53
+ */site-packages/datagarden_models
54
+
55
+ [tox:tox]
56
+ envlist = py310, py311, py312
57
+ isolated_build = True
58
+
59
+ [testenv]
60
+ deps =
61
+ pytest
62
+ pytest-cov
63
+ pydantic
64
+ commands =
65
+ pytest {posargs}
66
+
67
+ [testenv:typecheck]
68
+ deps =
69
+ mypy
70
+ pytest
71
+ types-PyYAML
72
+ commands =
73
+ mypy --ignore-missing-imports {posargs:src}
74
+
75
+ [testenv:format]
76
+ skip_install = True
77
+ deps =
78
+ ruff>=0.4.3
79
+ isort>=5.13
80
+ commands =
81
+ ruff check --select I --fix
82
+ ruff format src
83
+
84
+ [testenv:lint]
85
+ skip_install = True
86
+ deps =
87
+ flake8==7.0.0
88
+ flake8-bugbear==24.4.26
89
+ commands =
90
+ flake8 {posargs:src tests}
91
+
92
+ [testenv:docs]
93
+ skip_install = True
94
+ deps =
95
+ sphinx
96
+ sphinx-rtd-theme
97
+ mongoengine
98
+ error-manager
99
+ allowlist_externals = sphinx-build
100
+ commands =
101
+ sphinx-build -n -W --keep-going -b html docs/ docs/_build/
102
+
103
+ [egg_info]
104
+ tag_build =
105
+ tag_date = 0
106
+
@@ -0,0 +1,52 @@
1
+ """
2
+ Module to provide a combined storage and data classes for specified data models.
3
+ The classes include pydantic validation of the data and storage of the data via
4
+ a selected storage class.
5
+
6
+
7
+ Available methods
8
+ 'init_database'
9
+ - method to define name and alias for the database
10
+ - if needed host info and credentials can be added to the arguments
11
+
12
+ >>> configure_database(host="localhost", port=27017, username="user", password="pass")
13
+
14
+
15
+ available Dataclasses
16
+ - GeoNameDataClass, data class aimed at storing data from GeoNames website
17
+ - RetailLocationsDataClass, data class aimed at storing retail locations
18
+
19
+ avaialble fieldtypes (to be used to instantiatie specific dataclasses fields)
20
+ - PointField
21
+
22
+
23
+ Objects for discovery of available dataclasses
24
+ - ALL_MODEL_CLASSES: List with all data models
25
+ - ALL_GDG_MODEL_NAMES: List with class_names of all dataclasses.
26
+ - model_name_to_model: method to retrieve the actual data class for its name.
27
+ """
28
+
29
+ from .models.base import DataGardenModel
30
+
31
+ from .models import DemographicsV1, DemographicsV1Keys
32
+
33
+
34
+ class DatagardenDataModels:
35
+ DEMOGRAPHICS: type[DataGardenModel] = DemographicsV1
36
+
37
+
38
+ class DatagardenDataModelKeys:
39
+ DEMOGRAPHICS: type = DemographicsV1Keys
40
+
41
+
42
+ def get_values_from_class(cls: type):
43
+ for key, value in vars(cls).items():
44
+ if not key.startswith("__"):
45
+ yield value
46
+
47
+
48
+ AVAILABLE_MODELS = [
49
+ klass.DATAGARDEN_MODEL_NAME
50
+ for klass in get_values_from_class(DatagardenDataModelKeys)
51
+ ]
52
+ __all__ = ["DatagardenDataModels", "DatagardenDataModelKeys", "AVAILABLE_MODELS"]
@@ -0,0 +1,9 @@
1
+ from .base import DataGardenModel
2
+ from .demographics import DemographicsV1, DemographicsV1Keys
3
+
4
+
5
+ class DefaultAppModels:
6
+ DEMOGRAPHICS: type[DataGardenModel] = DemographicsV1
7
+
8
+
9
+ __all__ = ["DemographicsV1Keys", "DemographicsV1", "DefaultAppModels"]
@@ -0,0 +1,63 @@
1
+ from typing import Union, get_args, get_origin
2
+
3
+ from pydantic import BaseModel, Field, model_validator
4
+
5
+
6
+ class DataGardenModel(BaseModel):
7
+ datagarden_model_version: str = Field("v1.0", frozen=True)
8
+
9
+ @model_validator(mode="before")
10
+ def check_datagarden_model_version(cls, values):
11
+ if (
12
+ "datagarden_model_version" in values
13
+ and values["datagarden_model_version"]
14
+ != cls.model_fields["datagarden_model_version"].default
15
+ ):
16
+ raise ValueError("The field 'datagarden_model_version' is immutable.")
17
+ return values
18
+
19
+ @classmethod
20
+ def units(cls, attribute: str | None = None, indent: int = 0):
21
+ def print_description(prefix, field_info, indent_level):
22
+ indent_space = " " * indent_level
23
+ description = field_info.description
24
+ if description:
25
+ print(f"{indent_space}{prefix}: {description}")
26
+
27
+ def is_base_model(annotation):
28
+ if isinstance(annotation, type) and issubclass(annotation, BaseModel):
29
+ return True
30
+ if get_origin(annotation) is Union:
31
+ return any(is_base_model(arg) for arg in get_args(annotation))
32
+ return False
33
+
34
+ def recursive_units(sub_cls: type[BaseModel], attr_prefix="", indent_level=0):
35
+ for field_name, field_info in sub_cls.model_fields.items():
36
+ full_attr_name = (
37
+ f"{attr_prefix}.{field_name}" if attr_prefix else field_name
38
+ )
39
+ if is_base_model(field_info.annotation):
40
+ print_description(full_attr_name, field_info, indent_level)
41
+ if field_info.annotation:
42
+ recursive_units(
43
+ field_info.annotation, full_attr_name, indent_level + 1
44
+ )
45
+ else:
46
+ print_description(full_attr_name, field_info, indent_level)
47
+
48
+ if attribute:
49
+ parts = attribute.split(".")
50
+ current_model = cls
51
+ for part in parts:
52
+ field_info = current_model.model_fields.get(part)
53
+ if not field_info:
54
+ print(f"No description available for attribute: {attribute}")
55
+ return
56
+ if issubclass(field_info.__class__, BaseModel):
57
+ current_model = field_info.__class__
58
+ else:
59
+ print_description(attribute, field_info, indent)
60
+ return
61
+ recursive_units(current_model, attribute, indent + 1)
62
+ else:
63
+ recursive_units(cls)
@@ -0,0 +1,48 @@
1
+ from pydantic import Field
2
+
3
+ from ..base import DataGardenModel
4
+ from .base_demographics import DemographicsBaseKeys
5
+ from .fertility import Fertility, FertilityV1Keys
6
+ from .life_expectancy import LifeExpectancy, LifeExpectancyV1Keys
7
+ from .mortality import Mortality, MortalityV1Keys
8
+ from .population import Population, PopulationV1Keys
9
+
10
+
11
+ class DemographicsV1Keys(
12
+ PopulationV1Keys,
13
+ FertilityV1Keys,
14
+ LifeExpectancyV1Keys,
15
+ MortalityV1Keys,
16
+ DemographicsBaseKeys,
17
+ ):
18
+ POPULATION = "population"
19
+ MORTALITY = "mortality"
20
+ FERTILITY = "fertility"
21
+ LIFE_EXPECTANCY = "life_expectancy"
22
+ DATAGARDEN_MODEL_NAME = "Demographics"
23
+
24
+
25
+ class DemographicsV1Legends:
26
+ POPULATION = "Population indicators for the region. "
27
+ MORTALITY = "Mortality indicators for the region. "
28
+ FERTILITY = "Fertility indicators for the region. "
29
+ LIFE_EXPECTANCY = "Life expectancy indicators for the region. "
30
+ DATAGARDEN_MODEL_VERSION = "Version of the data model."
31
+
32
+
33
+ L = DemographicsV1Legends
34
+
35
+
36
+ class DemographicsV1(DataGardenModel):
37
+ datagarden_model_version: str = Field(
38
+ "v1.0", frozen=True, description=L.DATAGARDEN_MODEL_VERSION
39
+ )
40
+ population: Population = Field(default_factory=Population, description=L.POPULATION)
41
+ life_expectancy: LifeExpectancy = Field(
42
+ default_factory=LifeExpectancy, description=L.LIFE_EXPECTANCY
43
+ )
44
+ mortality: Mortality = Field(default_factory=Mortality, description=L.MORTALITY)
45
+ fertility: Fertility = Field(default_factory=Fertility, description=L.FERTILITY)
46
+
47
+
48
+
@@ -0,0 +1,23 @@
1
+ from pydantic import BaseModel, Field
2
+
3
+
4
+ class DemographicsBaseKeys:
5
+ MALE = "male"
6
+ FEMALE = "female"
7
+
8
+
9
+ class DemographicsBaseLegends:
10
+ AGE_GENDER_MALE = (
11
+ "Number of males. " "In number of individuals per age or age group."
12
+ )
13
+ AGE_GENDER_FEMALE = (
14
+ "Number of females. " "In number of individuals per age or age group."
15
+ )
16
+
17
+
18
+ L = DemographicsBaseLegends
19
+
20
+
21
+ class AgeGender(BaseModel):
22
+ male: dict = Field(default_factory=dict, description=L.AGE_GENDER_MALE)
23
+ female: dict = Field(default_factory=dict, description=L.AGE_GENDER_FEMALE)
@@ -0,0 +1,40 @@
1
+ from pydantic import BaseModel, Field
2
+
3
+
4
+ class FertilityV1Legends:
5
+ TOTAL_BIRTHS = "Total number of births in the population."
6
+ BIRTHS_BY_AGE = "Number of births categorized by age of the mother."
7
+ AVERAGE_AGE_MOTHER = "Average age of mothers at childbirth."
8
+ MEDIAN_AGE_MOTHER = "Median age of mothers at childbirth."
9
+ FERTILITY_RATE = "Overall fertility rate per woman."
10
+ FERTILITY_RATE_BY_AGE = "Fertility rates categorized by age of the mother."
11
+ BIRTH_RATE = "Crude birth rate in number of births per 1000 people."
12
+
13
+
14
+ L = FertilityV1Legends
15
+
16
+
17
+ class Fertility(BaseModel):
18
+ total_births: float | None = Field(default=None, description=L.TOTAL_BIRTHS)
19
+ births_by_age: dict = Field(default_factory=dict, description=L.BIRTHS_BY_AGE)
20
+ average_age_mother: float | None = Field(
21
+ default=None, description=L.AVERAGE_AGE_MOTHER
22
+ )
23
+ median_age_mother: float | None = Field(
24
+ default=None, description=L.MEDIAN_AGE_MOTHER
25
+ )
26
+ fertility_rate: float | None = Field(default=None, description=L.FERTILITY_RATE)
27
+ fertility_rate_by_age: dict = Field(
28
+ default_factory=dict, description=L.FERTILITY_RATE_BY_AGE
29
+ )
30
+ birth_rate: float | None = Field(default=None, description=L.BIRTH_RATE)
31
+
32
+
33
+ class FertilityV1Keys:
34
+ TOTAL_BIRTHS = "total_births"
35
+ BIRTHS_BY_AGE = "births_by_age"
36
+ AVERAGE_AGE_MOTHER = "average_age_mother"
37
+ MEDIAN_AGE_MOTHER = "median_age_mother"
38
+ FERTILITY_RATE = "fertility_rate"
39
+ FERTILITY_RATE_BY_AGE = "fertility_rate_by_age"
40
+ BIRTH_RATE = "birth_rate"
@@ -0,0 +1,32 @@
1
+ from pydantic import BaseModel, Field
2
+
3
+ from .base_demographics import AgeGender
4
+
5
+
6
+ class LifeExpectancyV1Keys:
7
+ LIFE_EXPECTANCY_AT_BIRTH = "life_expectancy_at_birth"
8
+ REMAINING_LIFE_EXPECTANCY = "remaining_life_expectancy"
9
+
10
+
11
+ class LifeExpectancyV1Legends:
12
+ LIFE_EXPECTANCY_AT_BIRTH = (
13
+ "Life expectancy per age or age group at birth. "
14
+ "In years expected to live when born"
15
+ )
16
+ REMAINING_LIFE_EXPECTANCY = (
17
+ "Life expectancy per age or age group at current age. "
18
+ "In years expected to live as of current age"
19
+ )
20
+
21
+
22
+ L = LifeExpectancyV1Legends
23
+
24
+
25
+ class LifeExpectancy(BaseModel):
26
+ life_expectancy_at_birth: AgeGender = Field(
27
+ default_factory=AgeGender, description=L.LIFE_EXPECTANCY_AT_BIRTH
28
+ )
29
+
30
+ remaining_life_expectancy: AgeGender = Field(
31
+ default_factory=AgeGender, description=L.REMAINING_LIFE_EXPECTANCY
32
+ )
@@ -0,0 +1,33 @@
1
+ from pydantic import BaseModel, Field
2
+
3
+ from .base_demographics import AgeGender
4
+
5
+
6
+ class MortalityV1Legends:
7
+ DEATHS_BY_AGE = (
8
+ "Death count per year. " "In number of individuals per age or age group."
9
+ )
10
+ TOTAL_DEATHS = "Total number of deaths in a year. " "In number of individuals."
11
+ INFANT_DEATHS = "Number of infant deaths in the population."
12
+ INFANT_DEATH_RATE = "Infant death rate per 1000 live births."
13
+
14
+
15
+ L = MortalityV1Legends
16
+
17
+
18
+ class Mortality(BaseModel):
19
+ deaths_by_age: AgeGender = Field(
20
+ default_factory=AgeGender, description=L.DEATHS_BY_AGE
21
+ )
22
+ total_deaths: float | None = Field(default=None, description=L.TOTAL_DEATHS)
23
+ infant_deaths: float | None = Field(default=None, description=L.INFANT_DEATHS)
24
+ infant_death_rate: float | None = Field(
25
+ default=None, description=L.INFANT_DEATH_RATE
26
+ )
27
+
28
+
29
+ class MortalityV1Keys:
30
+ DEATHS_BY_AGE = "deaths_by_age"
31
+ TOTAL_DEATHS = "total_deaths"
32
+ INFANT_DEATHS = "infant_deaths"
33
+ INFANT_DEATH_RATE = "infant_death_rate"
@@ -0,0 +1,59 @@
1
+ from pydantic import BaseModel, Field
2
+
3
+ from .base_demographics import AgeGender
4
+
5
+
6
+ class PopulationV1Legends:
7
+ BY_AGE_GENDER = "Age gender distribution for males and females. "
8
+ TOTAL = "Total population. " "In number of individuals."
9
+
10
+ TOTAL_MALE = "Total number of males in the population. " "In number of individuals."
11
+ TOTAL_FEMALE = (
12
+ "Total number of females in the population. " "In number of individuals."
13
+ )
14
+ POPULATION_TOTAL = (
15
+ "Total number of persons in the population. " "In number of individuals."
16
+ )
17
+ MALE_FEMALE_RATIO = "Males to femal ratio. " "In number of males per 100 females."
18
+ DENSITY = "Persons per square KM."
19
+ CHANGE = (
20
+ "Population change in number of persons. "
21
+ "In number of individuals per 1000 people."
22
+ )
23
+ NATURAL_CHANGE = "Births minus Deaths. In number of individuals."
24
+ NATURAL_CHANGE_RATE = "Rate of Natural change per 1.000 persons."
25
+
26
+
27
+ L = PopulationV1Legends
28
+
29
+
30
+ class Population(BaseModel):
31
+ by_age_gender: AgeGender = Field(
32
+ default_factory=AgeGender, description=L.BY_AGE_GENDER
33
+ )
34
+ total: float | None = Field(default=None, description=L.TOTAL)
35
+
36
+ total_male: float | None = Field(default=None, description=L.TOTAL_MALE)
37
+ total_female: float | None = Field(default=None, description=L.TOTAL_FEMALE)
38
+ male_to_female_ratio: float | None = Field(
39
+ default=None, description=L.MALE_FEMALE_RATIO
40
+ )
41
+ density: float | None = Field(default=None, description=L.DENSITY)
42
+ change: float | None = Field(default=None, description=L.CHANGE)
43
+ natural_change: float | None = Field(default=None, description=L.NATURAL_CHANGE)
44
+ natural_change_rate: float | None = Field(
45
+ default=None, description=L.NATURAL_CHANGE_RATE
46
+ )
47
+
48
+
49
+ class PopulationV1Keys:
50
+ POPULATION = "population"
51
+ BY_AGE_GENDER = "by_age_gender"
52
+ TOTAL = "total"
53
+ TOTAL_MALE = "total_male"
54
+ TOTAL_FEMALE = "total_female"
55
+ MALE_TO_FEMALE_RATIO = "male_to_female_ratio"
56
+ DENSITY = "density"
57
+ CHANGE = "change"
58
+ NATURAL_CHANGE = "natural_change"
59
+ NATURAL_CHANGE_RATE = "natural_change_rate"
@@ -0,0 +1,9 @@
1
+ Metadata-Version: 2.1
2
+ Name: the-datagarden-models
3
+ Version: 0.0.1
4
+ Summary: Base data models for the datagarden
5
+ Author: Maarten de Ruyter
6
+ Author-email: "Maarten de Ruyter" <maarten@geodatagarden.com>
7
+ License: MIT
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Requires-Dist: pydantic
@@ -0,0 +1,17 @@
1
+ pyproject.toml
2
+ setup.cfg
3
+ src/datagarden_models/__init__.py
4
+ src/datagarden_models/models/__init__.py
5
+ src/datagarden_models/models/base.py
6
+ src/datagarden_models/models/demographics/__init__.py
7
+ src/datagarden_models/models/demographics/base_demographics.py
8
+ src/datagarden_models/models/demographics/fertility.py
9
+ src/datagarden_models/models/demographics/life_expectancy.py
10
+ src/datagarden_models/models/demographics/migration.py
11
+ src/datagarden_models/models/demographics/mortality.py
12
+ src/datagarden_models/models/demographics/population.py
13
+ src/the_datagarden_models.egg-info/PKG-INFO
14
+ src/the_datagarden_models.egg-info/SOURCES.txt
15
+ src/the_datagarden_models.egg-info/dependency_links.txt
16
+ src/the_datagarden_models.egg-info/requires.txt
17
+ src/the_datagarden_models.egg-info/top_level.txt