Mercurial > personal > weather-server
annotate weather_server/locations.py @ 36:e5a03d63b3d9 default tip
Truncate, don’t round, temperatures displayed in HTML.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Fri, 02 Jul 2021 20:38:11 -0400 |
parents | 2f3473416c11 |
children |
rev | line source |
---|---|
1
f66df122f18d
get the skeleton of a webserver up?
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
1 """Manages the directory containing the various logs.""" |
f66df122f18d
get the skeleton of a webserver up?
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
2 |
f66df122f18d
get the skeleton of a webserver up?
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
3 import configparser |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
4 import datetime |
1
f66df122f18d
get the skeleton of a webserver up?
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
5 import pathlib |
f66df122f18d
get the skeleton of a webserver up?
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
6 import typing as t |
f66df122f18d
get the skeleton of a webserver up?
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
7 |
f66df122f18d
get the skeleton of a webserver up?
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
8 import pytz |
f66df122f18d
get the skeleton of a webserver up?
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
9 |
f66df122f18d
get the skeleton of a webserver up?
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
10 from . import logfile |
f66df122f18d
get the skeleton of a webserver up?
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
11 from . import types |
f66df122f18d
get the skeleton of a webserver up?
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
12 |
f66df122f18d
get the skeleton of a webserver up?
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
13 CONFIG_FILE = 'config.ini' |
f66df122f18d
get the skeleton of a webserver up?
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
14 LOG = 'log.bson' |
f66df122f18d
get the skeleton of a webserver up?
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
15 |
f66df122f18d
get the skeleton of a webserver up?
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
16 |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
17 class ConfigError(Exception): |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
18 """Raised when a location can't be loaded.""" |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
19 |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
20 |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
21 class Location: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
22 |
26
7def5611895b
Add support for an index page displaying all locations.
Paul Fisher <paul@pfish.zone>
parents:
24
diff
changeset
|
23 def __init__(self, root: pathlib.Path, key: str): |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
24 parser = configparser.ConfigParser(interpolation=None) |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
25 self.root = root |
26
7def5611895b
Add support for an index page displaying all locations.
Paul Fisher <paul@pfish.zone>
parents:
24
diff
changeset
|
26 self.key = key |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
27 config_file = root / CONFIG_FILE |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
28 try: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
29 with open(config_file, 'r') as infile: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
30 parser.read_file(infile) |
22
e229afdd447b
locations.py: store location name into the right place.
Paul Fisher <paul@pfish.zone>
parents:
21
diff
changeset
|
31 self.name = parser.get( |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
32 'location', 'name', fallback='Weather station') |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
33 self.tz_name = parser.get('location', 'timezone', fallback='UTC') |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
34 self.password = parser.get('location', 'password') |
24
20c8ec56e447
logfile: Pull logfile thread out of Logger.
Paul Fisher <paul@pfish.zone>
parents:
22
diff
changeset
|
35 self.logger = logfile.Logger( |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
36 str(root / LOG), sample_field='sample_time') |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
37 except (IOError, KeyError, configparser.Error): |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
38 raise ConfigError("Couldn't load location info.") |
1
f66df122f18d
get the skeleton of a webserver up?
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
39 |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
40 def record( |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
41 self, |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
42 entries: t.Iterable[t.Dict[str, object]], |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
43 timestamp: datetime.datetime, |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
44 ) -> None: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
45 for e in entries: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
46 e['ingest_time'] = timestamp |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
47 self.logger.write_rows(entries) |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
48 |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
49 @property |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
50 def entries(self) -> t.Iterable[t.Dict[str, object]]: |
31
9bc3687e1e5e
logfile: Add an index, and don't keep everything in RAM.
Paul Fisher <paul@pfish.zone>
parents:
26
diff
changeset
|
51 return self.logger.cached_data |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
52 |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
53 def latest(self) -> t.Optional[types.Reading]: |
31
9bc3687e1e5e
logfile: Add an index, and don't keep everything in RAM.
Paul Fisher <paul@pfish.zone>
parents:
26
diff
changeset
|
54 most_recent = reversed(self.logger.cached_data) |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
55 for entry in most_recent: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
56 try: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
57 return types.Reading.from_dict(entry) |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
58 except KeyError: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
59 pass # go to the older one. |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
60 return None |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
61 |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
62 def timezone(self) -> datetime.tzinfo: |
1
f66df122f18d
get the skeleton of a webserver up?
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
63 try: |
f66df122f18d
get the skeleton of a webserver up?
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
64 return pytz.timezone(self.tz_name) |
f66df122f18d
get the skeleton of a webserver up?
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
65 except pytz.UnknownTimeZoneError: |
f66df122f18d
get the skeleton of a webserver up?
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
66 return pytz.UTC |
f66df122f18d
get the skeleton of a webserver up?
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
67 |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
68 def __repr__(self) -> str: |
35
2f3473416c11
Fix format string in repr(Location).
Paul Fisher <paul@pfish.zone>
parents:
31
diff
changeset
|
69 return f'<Location in {self.root!r}>' |
1
f66df122f18d
get the skeleton of a webserver up?
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
70 |
f66df122f18d
get the skeleton of a webserver up?
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
71 |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
72 class LocationFolder: |
1
f66df122f18d
get the skeleton of a webserver up?
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
73 |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
74 def __init__(self, root: pathlib.Path): |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
75 self.root = root |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
76 # locations, mtime |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
77 self.info: t.Tuple[t.Dict[str, Location], t.Optional[int]] = ({}, None) |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
78 self._maybe_reload() |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
79 |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
80 def get(self, name: str) -> Location: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
81 self._maybe_reload() |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
82 locs, _ = self.info |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
83 return locs[name] |
1
f66df122f18d
get the skeleton of a webserver up?
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
84 |
26
7def5611895b
Add support for an index page displaying all locations.
Paul Fisher <paul@pfish.zone>
parents:
24
diff
changeset
|
85 def locations(self) -> t.Dict[str, Location]: |
7def5611895b
Add support for an index page displaying all locations.
Paul Fisher <paul@pfish.zone>
parents:
24
diff
changeset
|
86 return self.info[0] |
7def5611895b
Add support for an index page displaying all locations.
Paul Fisher <paul@pfish.zone>
parents:
24
diff
changeset
|
87 |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
88 def _maybe_reload(self) -> None: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
89 new_mtime = self.root.stat().st_mtime_ns |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
90 _, old_mtime = self.info |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
91 if old_mtime == new_mtime: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
92 return |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
93 locations = {} |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
94 for child in self.root.iterdir(): |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
95 try: |
26
7def5611895b
Add support for an index page displaying all locations.
Paul Fisher <paul@pfish.zone>
parents:
24
diff
changeset
|
96 locations[child.name] = Location(child, child.name) |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
97 except ConfigError: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
98 pass # It's OK. Skip this. |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
9
diff
changeset
|
99 self.info = locations, new_mtime |