weatherdb 1.1.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. docker/Dockerfile +30 -0
  2. docker/docker-compose.yaml +58 -0
  3. docker/docker-compose_test.yaml +24 -0
  4. docker/start-docker-test.sh +6 -0
  5. docs/requirements.txt +10 -0
  6. docs/source/Changelog.md +2 -0
  7. docs/source/License.rst +7 -0
  8. docs/source/Methode.md +161 -0
  9. docs/source/_static/custom.css +8 -0
  10. docs/source/_static/favicon.ico +0 -0
  11. docs/source/_static/logo.png +0 -0
  12. docs/source/api/api.rst +15 -0
  13. docs/source/api/cli.rst +8 -0
  14. docs/source/api/weatherDB.broker.rst +10 -0
  15. docs/source/api/weatherDB.config.rst +7 -0
  16. docs/source/api/weatherDB.db.rst +23 -0
  17. docs/source/api/weatherDB.rst +22 -0
  18. docs/source/api/weatherDB.station.rst +56 -0
  19. docs/source/api/weatherDB.stations.rst +46 -0
  20. docs/source/api/weatherDB.utils.rst +22 -0
  21. docs/source/conf.py +137 -0
  22. docs/source/index.rst +33 -0
  23. docs/source/setup/Configuration.md +127 -0
  24. docs/source/setup/Hosting.md +9 -0
  25. docs/source/setup/Install.md +49 -0
  26. docs/source/setup/Quickstart.md +183 -0
  27. docs/source/setup/setup.rst +12 -0
  28. weatherdb/__init__.py +24 -0
  29. weatherdb/_version.py +1 -0
  30. weatherdb/alembic/README.md +8 -0
  31. weatherdb/alembic/alembic.ini +80 -0
  32. weatherdb/alembic/config.py +9 -0
  33. weatherdb/alembic/env.py +100 -0
  34. weatherdb/alembic/script.py.mako +26 -0
  35. weatherdb/alembic/versions/V1.0.0_initial_database_creation.py +898 -0
  36. weatherdb/alembic/versions/V1.0.2_more_charachters_for_settings+term_station_ma_raster.py +88 -0
  37. weatherdb/alembic/versions/V1.0.5_fix-ma-raster-values.py +152 -0
  38. weatherdb/alembic/versions/V1.0.6_update-views.py +22 -0
  39. weatherdb/broker.py +667 -0
  40. weatherdb/cli.py +214 -0
  41. weatherdb/config/ConfigParser.py +663 -0
  42. weatherdb/config/__init__.py +5 -0
  43. weatherdb/config/config_default.ini +162 -0
  44. weatherdb/db/__init__.py +3 -0
  45. weatherdb/db/connections.py +374 -0
  46. weatherdb/db/fixtures/RichterParameters.json +34 -0
  47. weatherdb/db/models.py +402 -0
  48. weatherdb/db/queries/get_quotient.py +155 -0
  49. weatherdb/db/views.py +165 -0
  50. weatherdb/station/GroupStation.py +710 -0
  51. weatherdb/station/StationBases.py +3108 -0
  52. weatherdb/station/StationET.py +111 -0
  53. weatherdb/station/StationP.py +807 -0
  54. weatherdb/station/StationPD.py +98 -0
  55. weatherdb/station/StationT.py +164 -0
  56. weatherdb/station/__init__.py +13 -0
  57. weatherdb/station/constants.py +21 -0
  58. weatherdb/stations/GroupStations.py +519 -0
  59. weatherdb/stations/StationsBase.py +1021 -0
  60. weatherdb/stations/StationsBaseTET.py +30 -0
  61. weatherdb/stations/StationsET.py +17 -0
  62. weatherdb/stations/StationsP.py +128 -0
  63. weatherdb/stations/StationsPD.py +24 -0
  64. weatherdb/stations/StationsT.py +21 -0
  65. weatherdb/stations/__init__.py +11 -0
  66. weatherdb/utils/TimestampPeriod.py +369 -0
  67. weatherdb/utils/__init__.py +3 -0
  68. weatherdb/utils/dwd.py +350 -0
  69. weatherdb/utils/geometry.py +69 -0
  70. weatherdb/utils/get_data.py +285 -0
  71. weatherdb/utils/logging.py +126 -0
  72. weatherdb-1.1.0.dist-info/LICENSE +674 -0
  73. weatherdb-1.1.0.dist-info/METADATA +765 -0
  74. weatherdb-1.1.0.dist-info/RECORD +77 -0
  75. weatherdb-1.1.0.dist-info/WHEEL +5 -0
  76. weatherdb-1.1.0.dist-info/entry_points.txt +2 -0
  77. 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
+ )