weatherdb 1.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.
- docker/Dockerfile +30 -0
- docker/docker-compose.yaml +58 -0
- docker/docker-compose_test.yaml +24 -0
- docker/start-docker-test.sh +6 -0
- docs/requirements.txt +10 -0
- docs/source/Changelog.md +2 -0
- docs/source/License.rst +7 -0
- docs/source/Methode.md +161 -0
- docs/source/_static/custom.css +8 -0
- docs/source/_static/favicon.ico +0 -0
- docs/source/_static/logo.png +0 -0
- docs/source/api/api.rst +15 -0
- docs/source/api/cli.rst +8 -0
- docs/source/api/weatherDB.broker.rst +10 -0
- docs/source/api/weatherDB.config.rst +7 -0
- docs/source/api/weatherDB.db.rst +23 -0
- docs/source/api/weatherDB.rst +22 -0
- docs/source/api/weatherDB.station.rst +56 -0
- docs/source/api/weatherDB.stations.rst +46 -0
- docs/source/api/weatherDB.utils.rst +22 -0
- docs/source/conf.py +137 -0
- docs/source/index.rst +33 -0
- docs/source/setup/Configuration.md +127 -0
- docs/source/setup/Hosting.md +9 -0
- docs/source/setup/Install.md +49 -0
- docs/source/setup/Quickstart.md +183 -0
- docs/source/setup/setup.rst +12 -0
- weatherdb/__init__.py +24 -0
- weatherdb/_version.py +1 -0
- weatherdb/alembic/README.md +8 -0
- weatherdb/alembic/alembic.ini +80 -0
- weatherdb/alembic/config.py +9 -0
- weatherdb/alembic/env.py +100 -0
- weatherdb/alembic/script.py.mako +26 -0
- weatherdb/alembic/versions/V1.0.0_initial_database_creation.py +898 -0
- weatherdb/alembic/versions/V1.0.2_more_charachters_for_settings+term_station_ma_raster.py +88 -0
- weatherdb/alembic/versions/V1.0.5_fix-ma-raster-values.py +152 -0
- weatherdb/alembic/versions/V1.0.6_update-views.py +22 -0
- weatherdb/broker.py +667 -0
- weatherdb/cli.py +214 -0
- weatherdb/config/ConfigParser.py +663 -0
- weatherdb/config/__init__.py +5 -0
- weatherdb/config/config_default.ini +162 -0
- weatherdb/db/__init__.py +3 -0
- weatherdb/db/connections.py +374 -0
- weatherdb/db/fixtures/RichterParameters.json +34 -0
- weatherdb/db/models.py +402 -0
- weatherdb/db/queries/get_quotient.py +155 -0
- weatherdb/db/views.py +165 -0
- weatherdb/station/GroupStation.py +710 -0
- weatherdb/station/StationBases.py +3108 -0
- weatherdb/station/StationET.py +111 -0
- weatherdb/station/StationP.py +807 -0
- weatherdb/station/StationPD.py +98 -0
- weatherdb/station/StationT.py +164 -0
- weatherdb/station/__init__.py +13 -0
- weatherdb/station/constants.py +21 -0
- weatherdb/stations/GroupStations.py +519 -0
- weatherdb/stations/StationsBase.py +1021 -0
- weatherdb/stations/StationsBaseTET.py +30 -0
- weatherdb/stations/StationsET.py +17 -0
- weatherdb/stations/StationsP.py +128 -0
- weatherdb/stations/StationsPD.py +24 -0
- weatherdb/stations/StationsT.py +21 -0
- weatherdb/stations/__init__.py +11 -0
- weatherdb/utils/TimestampPeriod.py +369 -0
- weatherdb/utils/__init__.py +3 -0
- weatherdb/utils/dwd.py +350 -0
- weatherdb/utils/geometry.py +69 -0
- weatherdb/utils/get_data.py +285 -0
- weatherdb/utils/logging.py +126 -0
- weatherdb-1.1.0.dist-info/LICENSE +674 -0
- weatherdb-1.1.0.dist-info/METADATA +765 -0
- weatherdb-1.1.0.dist-info/RECORD +77 -0
- weatherdb-1.1.0.dist-info/WHEEL +5 -0
- weatherdb-1.1.0.dist-info/entry_points.txt +2 -0
- weatherdb-1.1.0.dist-info/top_level.txt +3 -0
weatherdb/db/views.py
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
import sqlalchemy as sa
|
2
|
+
from sqlalchemy.orm import Mapped, mapped_column
|
3
|
+
from sqlalchemy.ext.compiler import compiles
|
4
|
+
from sqlalchemy.sql.expression import Executable, ClauseElement
|
5
|
+
|
6
|
+
from .models import StationMATimeserie, StationMARaster, ModelBase
|
7
|
+
|
8
|
+
__all__ = [
|
9
|
+
"StationMATimeserieRasterQuotientView",
|
10
|
+
"StationKindQuotientView"
|
11
|
+
]
|
12
|
+
|
13
|
+
# View Bases
|
14
|
+
class CreateView(Executable, ClauseElement):
|
15
|
+
inherit_cache = True
|
16
|
+
def __init__(self, name, selectable):
|
17
|
+
self.name = name
|
18
|
+
self.selectable = selectable
|
19
|
+
|
20
|
+
@compiles(CreateView)
|
21
|
+
def compile_create_view(element, compiler, **kwargs):
|
22
|
+
return "CREATE OR REPLACE VIEW %s AS %s" % (
|
23
|
+
element.name,
|
24
|
+
compiler.sql_compiler.process(element.selectable, literal_binds=True)
|
25
|
+
)
|
26
|
+
|
27
|
+
class DropView(Executable, ClauseElement):
|
28
|
+
inherit_cache = True
|
29
|
+
def __init__(self, name, cascade=False, if_exists=True):
|
30
|
+
self.name = name
|
31
|
+
self.cascade = cascade
|
32
|
+
self.if_exists = if_exists
|
33
|
+
|
34
|
+
@compiles(DropView)
|
35
|
+
def compile_drop_view(element, compiler, **kwargs):
|
36
|
+
return "DROP VIEW %s%s%s" % (
|
37
|
+
"IF EXISTS " if element.if_exists else "",
|
38
|
+
element.name,
|
39
|
+
" CASCADE" if element.cascade else ""
|
40
|
+
)
|
41
|
+
|
42
|
+
class ViewBase(ModelBase):
|
43
|
+
__view_selectable__ = None
|
44
|
+
__abstract__ = True
|
45
|
+
|
46
|
+
@classmethod
|
47
|
+
def create_view(cls, target, connection, **kwargs):
|
48
|
+
if cls.__view_selectable__ is None:
|
49
|
+
raise NotImplementedError("No selectable defined for view. Please define a class variable \"__view_selectable__\"")
|
50
|
+
view = CreateView(cls.__tablename__, cls.__view_selectable__)
|
51
|
+
connection.execute(view)
|
52
|
+
connection.commit()
|
53
|
+
|
54
|
+
@classmethod
|
55
|
+
def drop_view(cls, target, connection, **kwargs):
|
56
|
+
drop = DropView(cls.__tablename__, if_exists=True, cascade=True)
|
57
|
+
connection.execute(drop)
|
58
|
+
connection.commit()
|
59
|
+
|
60
|
+
def __init_subclass__(cls, **kwargs):
|
61
|
+
super().__init_subclass__(**kwargs)
|
62
|
+
cls.metadata._remove_table(
|
63
|
+
cls.__tablename__,
|
64
|
+
cls.__table_args__.get("schema", "public"))
|
65
|
+
sa.event.listen(cls.metadata, 'after_create', cls.create_view)
|
66
|
+
sa.event.listen(cls.metadata, 'before_drop', cls.drop_view)
|
67
|
+
|
68
|
+
# add a views section to metadata
|
69
|
+
if hasattr(cls, "__view_selectable__"):
|
70
|
+
if not hasattr(cls.metadata, "views"):
|
71
|
+
cls.metadata.views = [cls]
|
72
|
+
elif cls not in cls.metadata.views:
|
73
|
+
cls.metadata.views.append(cls)
|
74
|
+
|
75
|
+
# declare all database views
|
76
|
+
# --------------------------
|
77
|
+
class StationMATimeserieRasterQuotientView(ViewBase):
|
78
|
+
__tablename__ = 'station_ma_timeseries_raster_quotient_view'
|
79
|
+
__table_args__ = dict(
|
80
|
+
schema='public',
|
81
|
+
comment="The multi annual mean values of the stations timeseries divided by the multi annual raster values for the maximum available timespan.",
|
82
|
+
extend_existing = True)
|
83
|
+
|
84
|
+
station_id: Mapped[int] = mapped_column(
|
85
|
+
primary_key=True,
|
86
|
+
comment="The DWD-ID of the station.")
|
87
|
+
parameter: Mapped[str] = mapped_column(
|
88
|
+
primary_key=True,
|
89
|
+
comment="The parameter of the station. e.g. 'p', 'et'")
|
90
|
+
kind: Mapped[str] = mapped_column(
|
91
|
+
primary_key=True,
|
92
|
+
comment="The kind of the timeserie. e.g. 'raw', 'filled', 'corr'")
|
93
|
+
raster_key: Mapped[str] = mapped_column(
|
94
|
+
primary_key=True,
|
95
|
+
comment="The name of the raster. e.g. 'dwd' or 'hyras'")
|
96
|
+
value: Mapped[float] = mapped_column(
|
97
|
+
comment="The multi annual value of the yearly mean value of the station to the multi annual mean value of the raster.")
|
98
|
+
|
99
|
+
__view_selectable__ = sa\
|
100
|
+
.select(
|
101
|
+
StationMATimeserie.station_id,
|
102
|
+
StationMATimeserie.parameter,
|
103
|
+
StationMATimeserie.kind,
|
104
|
+
StationMARaster.raster_key,
|
105
|
+
StationMARaster.term,
|
106
|
+
sa.case(
|
107
|
+
(StationMARaster.value is not None,
|
108
|
+
StationMATimeserie.value / StationMARaster.value),
|
109
|
+
else_=None).label("value")
|
110
|
+
).select_from(
|
111
|
+
StationMATimeserie.__table__.outerjoin(
|
112
|
+
StationMARaster.__table__,
|
113
|
+
sa.and_(
|
114
|
+
StationMATimeserie.station_id == StationMARaster.station_id,
|
115
|
+
StationMATimeserie.parameter == StationMARaster.parameter,
|
116
|
+
StationMARaster.term == "year"
|
117
|
+
)
|
118
|
+
)
|
119
|
+
).where(
|
120
|
+
StationMATimeserie.parameter.in_(["p", "et"])
|
121
|
+
)
|
122
|
+
|
123
|
+
class StationKindQuotientView(ViewBase):
|
124
|
+
__tablename__ = 'station_kind_quotient_view'
|
125
|
+
__table_args__ = dict(
|
126
|
+
schema='public',
|
127
|
+
comment="The quotient between different kinds of multi annual mean timeseries values.",
|
128
|
+
extend_existing = True)
|
129
|
+
|
130
|
+
station_id: Mapped[int] = mapped_column(
|
131
|
+
primary_key=True,
|
132
|
+
comment="The DWD-ID of the station.")
|
133
|
+
parameter: Mapped[str] = mapped_column(
|
134
|
+
primary_key=True,
|
135
|
+
comment="The parameter of the station. e.g. 'p', 'p_d', 'et'")
|
136
|
+
kind_numerator: Mapped[str] = mapped_column(
|
137
|
+
primary_key=True,
|
138
|
+
comment="The kind of the timeserie for the numerator. e.g. 'raw', 'filled', 'corr'")
|
139
|
+
kind_denominator: Mapped[str] = mapped_column(
|
140
|
+
primary_key=True,
|
141
|
+
comment="The kind of the timeserie for the denominator. e.g. 'raw', 'filled', 'corr'")
|
142
|
+
value: Mapped[float] = mapped_column(
|
143
|
+
comment="The quotient between the numerator and the nominator kind of the complete timeserie.")
|
144
|
+
|
145
|
+
__view_selectable__ = sa\
|
146
|
+
.select(
|
147
|
+
(smt1:=sa.orm.aliased(StationMATimeserie, name="smt1")).station_id,
|
148
|
+
smt1.parameter,
|
149
|
+
smt1.kind.label("kind_numerator"),
|
150
|
+
(smt2:=sa.orm.aliased(StationMATimeserie, name="smt2")).kind.label("kind_denominator"),
|
151
|
+
(smt1.value/smt2.value).label("value")
|
152
|
+
).select_from(
|
153
|
+
sa.join(
|
154
|
+
smt1,
|
155
|
+
smt2,
|
156
|
+
sa.and_(
|
157
|
+
smt1.station_id == smt2.station_id,
|
158
|
+
smt1.parameter == smt2.parameter
|
159
|
+
)
|
160
|
+
)
|
161
|
+
).where(
|
162
|
+
sa.and_(smt1.parameter.in_(["p", "p_d", "et"]),
|
163
|
+
smt1.kind != smt2.kind,
|
164
|
+
)
|
165
|
+
)
|