././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1746721154.5017426 pynina-0.3.6/0000777000175000017500000000000015007154603011601 5ustar00useruser././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1630435553.0 pynina-0.3.6/LICENSE0000777000175000017500000000207714113474341012620 0ustar00useruserMIT License Copyright (c) 2021 DeerMaximum Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1746721154.4987426 pynina-0.3.6/PKG-INFO0000777000175000017500000000401515007154602012700 0ustar00useruserMetadata-Version: 2.1 Name: pynina Version: 0.3.6 Summary: A Python API wrapper to retrieve warnings from the german NINA app. Home-page: https://gitlab.com/DeerMaximum/pynina Author: DeerMaximum Author-email: git983456@parabelmail.de License: MIT License Copyright (c) 2021 DeerMaximum Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Description-Content-Type: text/markdown License-File: LICENSE # Nina-API A Python API wrapper to retrieve warnings from the german NINA app. ## How to use package ```python import asyncio from pynina import Nina, ApiError async def main(): try: n: Nina = Nina() n.addRegion("146270000000") await n.update() for i in n.warnings["146270000000"]: print(i) print(i.isValid()) except ApiError as error: print(f"Error: {error}") loop = asyncio.get_event_loop() loop.run_until_complete(main()) loop.close() ``` ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1631395824.0 pynina-0.3.6/README.md0000777000175000017500000000105014117217760013064 0ustar00useruser# Nina-API A Python API wrapper to retrieve warnings from the german NINA app. ## How to use package ```python import asyncio from pynina import Nina, ApiError async def main(): try: n: Nina = Nina() n.addRegion("146270000000") await n.update() for i in n.warnings["146270000000"]: print(i) print(i.isValid()) except ApiError as error: print(f"Error: {error}") loop = asyncio.get_event_loop() loop.run_until_complete(main()) loop.close() ```././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1746721154.4012427 pynina-0.3.6/pynina/0000777000175000017500000000000015007154602013076 5ustar00useruser././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1746721004.0 pynina-0.3.6/pynina/__init__.py0000777000175000017500000000021215007154354015211 0ustar00useruser__version__ = "0.3.6" __author__ = "DeerMaximum" from .baseApi import ApiError from .nina import Nina from .warning import Warning ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691523357.0 pynina-0.3.6/pynina/baseApi.py0000777000175000017500000000274514464514435015041 0ustar00useruserimport asyncio from typing import Any, Dict from aiohttp import ClientSession, ClientConnectionError, ClientTimeout from .const import _LOGGER class BaseAPI: """Class to perform CMI API requests""" def __init__(self, session: ClientSession = None): """Constructor for BaseAPI.""" self.session = session async def _makeRequest(self, url: str): """Retrieve data from API.""" internalSession: bool = False if self.session is None: internalSession = True self.session = ClientSession() _LOGGER.debug(f"Try to fetch {url}") try: async with self.session.get(url, timeout=ClientTimeout(total=9)) as res: if res.status != 200: raise ApiError(f"Invalid response: {res.status}") json: Dict[str, Any] = await res.json() if internalSession: await self.session.close() self.session = None return json except (ClientConnectionError, asyncio.TimeoutError): if internalSession: await self.session.close() self.session = None raise ApiError(f"Could not connect to {url}") class ApiError(Exception): """Raised when API request ended in error.""" def __init__(self, status: str): """Initialize.""" super().__init__(status) self.status = status ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1746720941.0 pynina-0.3.6/pynina/const.py0000777000175000017500000003337115007154255014614 0ustar00useruserfrom logging import Logger, getLogger, NullHandler ENDPOINT_REGIONAL_CODE: str = "https://www.xrepository.de/api/xrepository/urn:de:bund:destatis:bevoelkerungsstatistik:schluessel:rs_2021-07-31/download/Regionalschl_ssel_2021-07-31.json" ENDPOINT_NINA_BASE: str = "https://warnung.bund.de/api31/dashboard/" ENDPOINT_WARNING_DETAIL: str = "https://warnung.bund.de/api31/warnings/" ENDPOINT_DE_LABELS: str = ( "https://warnung.bund.de/api/appdata/gsb/labels/de_labels.json" ) _LOGGER: Logger = getLogger(__package__) _LOGGER.addHandler(NullHandler()) CITY_STATES_CODE = ["02", "11"] COUNTIES = { "01051": "Dithmarschen - Schleswig-Holstein", "01053": "Herzogtum Lauenburg - Schleswig-Holstein", "01054": "Nordfriesland - Schleswig-Holstein", "01055": "Ostholstein - Schleswig-Holstein", "01056": "Pinneberg - Schleswig-Holstein", "01057": "Plön - Schleswig-Holstein", "01058": "Rendsburg-Eckernförde - Schleswig-Holstein", "01059": "Schleswig-Flensburg - Schleswig-Holstein", "01060": "Segeberg - Schleswig-Holstein", "01061": "Steinburg - Schleswig-Holstein", "01062": "Stormarn - Schleswig-Holstein", "03151": "Gifhorn - Niedersachsen", "03153": "Goslar - Niedersachsen", "03154": "Helmstedt - Niedersachsen", "03155": "Northeim - Niedersachsen", "03157": "Peine - Niedersachsen", "03158": "Wolfenbüttel - Niedersachsen", "03159": "Göttingen - Niedersachsen", "03241": "Hannover, Region - Niedersachsen", "03251": "Diepholz - Niedersachsen", "03252": "Hameln-Pyrmont - Niedersachsen", "03254": "Hildesheim - Niedersachsen", "03255": "Holzminden - Niedersachsen", "03256": "Nienburg/Weser - Niedersachsen", "03257": "Schaumburg - Niedersachsen", "03351": "Celle - Niedersachsen", "03352": "Cuxhaven - Niedersachsen", "03353": "Harburg - Niedersachsen", "03354": "Lüchow-Dannenberg - Niedersachsen", "03355": "Lüneburg - Niedersachsen", "03356": "Osterholz - Niedersachsen", "03357": "Rotenburg (Wümme) - Niedersachsen", "03358": "Heidekreis - Niedersachsen", "03359": "Stade - Niedersachsen", "03360": "Uelzen - Niedersachsen", "03361": "Verden - Niedersachsen", "03451": "Ammerland - Niedersachsen", "03452": "Aurich - Niedersachsen", "03453": "Cloppenburg - Niedersachsen", "03454": "Emsland - Niedersachsen", "03455": "Friesland - Niedersachsen", "03456": "Grafschaft Bentheim - Niedersachsen", "03457": "Leer - Niedersachsen", "03458": "Oldenburg - Niedersachsen", "03459": "Osnabrück - Niedersachsen", "03460": "Vechta - Niedersachsen", "03461": "Wesermarsch - Niedersachsen", "03462": "Wittmund - Niedersachsen", "05154": "Kleve - Nordrhein-Westfalen", "05158": "Mettmann - Nordrhein-Westfalen", "05162": "Rhein-Kreis Neuss - Nordrhein-Westfalen", "05166": "Viersen - Nordrhein-Westfalen", "05170": "Wesel - Nordrhein-Westfalen", "05334": "Aachen, Städteregion - Nordrhein-Westfalen", "05358": "Düren - Nordrhein-Westfalen", "05362": "Rhein-Erft-Kreis - Nordrhein-Westfalen", "05366": "Euskirchen - Nordrhein-Westfalen", "05370": "Heinsberg - Nordrhein-Westfalen", "05374": "Oberbergischer Kreis - Nordrhein-Westfalen", "05378": "Rheinisch-Bergischer Kreis - Nordrhein-Westfalen", "05382": "Rhein-Sieg-Kreis - Nordrhein-Westfalen", "05554": "Borken - Nordrhein-Westfalen", "05558": "Coesfeld - Nordrhein-Westfalen", "05562": "Recklinghausen - Nordrhein-Westfalen", "05566": "Steinfurt - Nordrhein-Westfalen", "05570": "Warendorf - Nordrhein-Westfalen", "05754": "Gütersloh - Nordrhein-Westfalen", "05758": "Herford - Nordrhein-Westfalen", "05762": "Höxter - Nordrhein-Westfalen", "05766": "Lippe - Nordrhein-Westfalen", "05770": "Minden-Lübbecke - Nordrhein-Westfalen", "05774": "Paderborn - Nordrhein-Westfalen", "05954": "Ennepe-Ruhr-Kreis - Nordrhein-Westfalen", "05958": "Hochsauerlandkreis - Nordrhein-Westfalen", "05962": "Märkischer Kreis - Nordrhein-Westfalen", "05966": "Olpe - Nordrhein-Westfalen", "05970": "Siegen-Wittgenstein - Nordrhein-Westfalen", "05974": "Soest - Nordrhein-Westfalen", "05978": "Unna - Nordrhein-Westfalen", "06431": "Bergstraße - Hessen", "06432": "Darmstadt-Dieburg - Hessen", "06433": "Groß-Gerau - Hessen", "06434": "Hochtaunuskreis - Hessen", "06435": "Main-Kinzig-Kreis - Hessen", "06436": "Main-Taunus-Kreis - Hessen", "06437": "Odenwaldkreis - Hessen", "06438": "Offenbach - Hessen", "06439": "Rheingau-Taunus-Kreis - Hessen", "06440": "Wetteraukreis - Hessen", "06531": "Gießen - Hessen", "06532": "Lahn-Dill-Kreis - Hessen", "06533": "Limburg-Weilburg - Hessen", "06534": "Marburg-Biedenkopf - Hessen", "06535": "Vogelsbergkreis - Hessen", "06631": "Fulda - Hessen", "06632": "Hersfeld-Rotenburg - Hessen", "06633": "Kassel - Hessen", "06634": "Schwalm-Eder-Kreis - Hessen", "06635": "Waldeck-Frankenberg - Hessen", "06636": "Werra-Meißner-Kreis - Hessen", "07131": "Ahrweiler - Rheinland-Pfalz", "07132": "Altenkirchen (Westerwald) - Rheinland-Pfalz", "07133": "Bad Kreuznach - Rheinland-Pfalz", "07134": "Birkenfeld - Rheinland-Pfalz", "07135": "Cochem-Zell - Rheinland-Pfalz", "07137": "Mayen-Koblenz - Rheinland-Pfalz", "07138": "Neuwied - Rheinland-Pfalz", "07140": "Rhein-Hunsrück-Kreis - Rheinland-Pfalz", "07141": "Rhein-Lahn-Kreis - Rheinland-Pfalz", "07143": "Westerwaldkreis - Rheinland-Pfalz", "07231": "Bernkastel-Wittlich - Rheinland-Pfalz", "07232": "Eifelkreis Bitburg-Prüm - Rheinland-Pfalz", "07233": "Vulkaneifel - Rheinland-Pfalz", "07235": "Trier-Saarburg - Rheinland-Pfalz", "07331": "Alzey-Worms - Rheinland-Pfalz", "07332": "Bad Dürkheim - Rheinland-Pfalz", "07333": "Donnersbergkreis - Rheinland-Pfalz", "07334": "Germersheim - Rheinland-Pfalz", "07335": "Kaiserslautern - Rheinland-Pfalz", "07336": "Kusel - Rheinland-Pfalz", "07337": "Südliche Weinstraße - Rheinland-Pfalz", "07338": "Rhein-Pfalz-Kreis - Rheinland-Pfalz", "07339": "Mainz-Bingen - Rheinland-Pfalz", "07340": "Südwestpfalz - Rheinland-Pfalz", "08115": "Böblingen - Baden-Württemberg", "08116": "Esslingen - Baden-Württemberg", "08117": "Göppingen - Baden-Württemberg", "08118": "Ludwigsburg - Baden-Württemberg", "08119": "Rems-Murr-Kreis - Baden-Württemberg", "08125": "Heilbronn - Baden-Württemberg", "08126": "Hohenlohekreis - Baden-Württemberg", "08127": "Schwäbisch Hall - Baden-Württemberg", "08128": "Main-Tauber-Kreis - Baden-Württemberg", "08135": "Heidenheim - Baden-Württemberg", "08136": "Ostalbkreis - Baden-Württemberg", "08215": "Karlsruhe - Baden-Württemberg", "08216": "Rastatt - Baden-Württemberg", "08225": "Neckar-Odenwald-Kreis - Baden-Württemberg", "08226": "Rhein-Neckar-Kreis - Baden-Württemberg", "08235": "Calw - Baden-Württemberg", "08236": "Enzkreis - Baden-Württemberg", "08237": "Freudenstadt - Baden-Württemberg", "08315": "Breisgau-Hochschwarzwald - Baden-Württemberg", "08316": "Emmendingen - Baden-Württemberg", "08317": "Ortenaukreis - Baden-Württemberg", "08325": "Rottweil - Baden-Württemberg", "08326": "Schwarzwald-Baar-Kreis - Baden-Württemberg", "08327": "Tuttlingen - Baden-Württemberg", "08335": "Konstanz - Baden-Württemberg", "08336": "Lörrach - Baden-Württemberg", "08337": "Waldshut - Baden-Württemberg", "08415": "Reutlingen - Baden-Württemberg", "08416": "Tübingen - Baden-Württemberg", "08417": "Zollernalbkreis - Baden-Württemberg", "08425": "Alb-Donau-Kreis - Baden-Württemberg", "08426": "Biberach - Baden-Württemberg", "08435": "Bodenseekreis - Baden-Württemberg", "08436": "Ravensburg - Baden-Württemberg", "08437": "Sigmaringen - Baden-Württemberg", "09171": "Altötting - Bayern", "09172": "Berchtesgadener Land - Bayern", "09173": "Bad Tölz-Wolfratshausen - Bayern", "09174": "Dachau - Bayern", "09175": "Ebersberg - Bayern", "09176": "Eichstätt - Bayern", "09177": "Erding - Bayern", "09178": "Freising - Bayern", "09179": "Fürstenfeldbruck - Bayern", "09180": "Garmisch-Partenkirchen - Bayern", "09181": "Landsberg am Lech - Bayern", "09182": "Miesbach - Bayern", "09183": "Mühldorf am Inn - Bayern", "09184": "München - Bayern", "09185": "Neuburg-Schrobenhausen - Bayern", "09186": "Pfaffenhofen an der Ilm - Bayern", "09187": "Rosenheim - Bayern", "09188": "Starnberg - Bayern", "09189": "Traunstein - Bayern", "09190": "Weilheim-Schongau - Bayern", "09271": "Deggendorf - Bayern", "09272": "Freyung-Grafenau - Bayern", "09273": "Kelheim - Bayern", "09274": "Landshut - Bayern", "09275": "Passau - Bayern", "09276": "Regen - Bayern", "09277": "Rottal-Inn - Bayern", "09278": "Straubing-Bogen - Bayern", "09279": "Dingolfing-Landau - Bayern", "09371": "Amberg-Sulzbach - Bayern", "09372": "Cham - Bayern", "09373": "Neumarkt in der Oberpfalz - Bayern", "09374": "Neustadt an der Waldnaab - Bayern", "09375": "Regensburg - Bayern", "09376": "Schwandorf - Bayern", "09377": "Tirschenreuth - Bayern", "09471": "Bamberg - Bayern", "09472": "Bayreuth - Bayern", "09473": "Coburg - Bayern", "09474": "Forchheim - Bayern", "09475": "Hof - Bayern", "09476": "Kronach - Bayern", "09477": "Kulmbach - Bayern", "09478": "Lichtenfels - Bayern", "09479": "Wunsiedel im Fichtelgebirge - Bayern", "09571": "Ansbach - Bayern", "09572": "Erlangen-Höchstadt - Bayern", "09573": "Fürth - Bayern", "09574": "Nürnberger Land - Bayern", "09575": "Neustadt an der Aisch-Bad Windsheim - Bayern", "09576": "Roth - Bayern", "09577": "Weißenburg-Gunzenhausen - Bayern", "09671": "Aschaffenburg - Bayern", "09672": "Bad Kissingen - Bayern", "09673": "Rhön-Grabfeld - Bayern", "09674": "Haßberge - Bayern", "09675": "Kitzingen - Bayern", "09676": "Miltenberg - Bayern", "09677": "Main-Spessart - Bayern", "09678": "Schweinfurt - Bayern", "09679": "Würzburg - Bayern", "09771": "Aichach-Friedberg - Bayern", "09772": "Augsburg - Bayern", "09773": "Dillingen an der Donau - Bayern", "09774": "Günzburg - Bayern", "09775": "Neu-Ulm - Bayern", "09776": "Lindau (Bodensee) - Bayern", "09777": "Ostallgäu - Bayern", "09778": "Unterallgäu - Bayern", "09779": "Donau-Ries - Bayern", "09780": "Oberallgäu - Bayern", "10041": "Saarbrücken, Regionalverband - Saarland", "10042": "Merzig-Wadern - Saarland", "10043": "Neunkirchen - Saarland", "10044": "Saarlouis - Saarland", "10045": "Saarpfalz-Kreis - Saarland", "10046": "St. Wendel - Saarland", "12060": "Barnim - Brandenburg", "12061": "Dahme-Spreewald - Brandenburg", "12062": "Elbe-Elster - Brandenburg", "12063": "Havelland - Brandenburg", "12064": "Märkisch-Oderland - Brandenburg", "12065": "Oberhavel - Brandenburg", "12066": "Oberspreewald-Lausitz - Brandenburg", "12067": "Oder-Spree - Brandenburg", "12068": "Ostprignitz-Ruppin - Brandenburg", "12069": "Potsdam-Mittelmark - Brandenburg", "12070": "Prignitz - Brandenburg", "12071": "Spree-Neiße - Brandenburg", "12072": "Teltow-Fläming - Brandenburg", "12073": "Uckermark - Brandenburg", "13071": "Mecklenburgische Seenplatte - Mecklenburg-Vorpommern", "13072": "Rostock - Mecklenburg-Vorpommern", "13073": "Vorpommern-Rügen - Mecklenburg-Vorpommern", "13074": "Nordwestmecklenburg - Mecklenburg-Vorpommern", "13075": "Vorpommern-Greifswald - Mecklenburg-Vorpommern", "13076": "Ludwigslust-Parchim - Mecklenburg-Vorpommern", "14521": "Erzgebirgskreis - Sachsen", "14522": "Mittelsachsen - Sachsen", "14523": "Vogtlandkreis - Sachsen", "14524": "Zwickau - Sachsen", "14625": "Bautzen - Sachsen", "14626": "Görlitz - Sachsen", "14627": "Meißen - Sachsen", "14628": "Sächsische Schweiz-Osterzgebirge - Sachsen", "14729": "Leipzig - Sachsen", "14730": "Nordsachsen - Sachsen", "15081": "Altmarkkreis Salzwedel - Sachsen-Anhalt", "15082": "Anhalt-Bitterfeld - Sachsen-Anhalt", "15083": "Börde - Sachsen-Anhalt", "15084": "Burgenlandkreis - Sachsen-Anhalt", "15085": "Harz - Sachsen-Anhalt", "15086": "Jerichower Land - Sachsen-Anhalt", "15087": "Mansfeld-Südharz - Sachsen-Anhalt", "15088": "Saalekreis - Sachsen-Anhalt", "15089": "Salzlandkreis - Sachsen-Anhalt", "15090": "Stendal - Sachsen-Anhalt", "15091": "Wittenberg - Sachsen-Anhalt", "16061": "Eichsfeld - Thüringen", "16062": "Nordhausen - Thüringen", "16063": "Wartburgkreis - Thüringen", "16064": "Unstrut-Hainich-Kreis - Thüringen", "16065": "Kyffhäuserkreis - Thüringen", "16066": "Schmalkalden-Meiningen - Thüringen", "16067": "Gotha - Thüringen", "16068": "Sömmerda - Thüringen", "16069": "Hildburghausen - Thüringen", "16070": "Ilm-Kreis - Thüringen", "16071": "Weimarer Land - Thüringen", "16072": "Sonneberg - Thüringen", "16073": "Saalfeld-Rudolstadt - Thüringen", "16074": "Saale-Holzland-Kreis - Thüringen", "16075": "Saale-Orla-Kreis - Thüringen", "16076": "Greiz - Thüringen", "16077": "Altenburger Land - Thüringen", } class ReadOnlyClass(type): def __setattr__(self, name, value): raise ValueError(name) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1670531143.0 pynina-0.3.6/pynina/label_matcher.py0000777000175000017500000000127014344444107016242 0ustar00useruserfrom typing import Dict from aiohttp import ClientSession from .const import ReadOnlyClass, ENDPOINT_DE_LABELS from .baseApi import BaseAPI class LabelMatcher(BaseAPI, metaclass=ReadOnlyClass): """Class to fetch and match labels with their codes.""" def __init__(self, session: ClientSession = None): """Initialize.""" super().__init__(session) self.labels: Dict[str, str] = {} async def update(self) -> None: """Update the labels.""" self.labels = await self._makeRequest(ENDPOINT_DE_LABELS) def match(self, code: str) -> str: """Match a code to a label.""" return self.labels.get(code, code) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691523423.0 pynina-0.3.6/pynina/nina.py0000777000175000017500000000437114464514537014422 0ustar00useruserfrom typing import Dict, Any from aiohttp import ClientSession from .const import ( ReadOnlyClass, ENDPOINT_REGIONAL_CODE, ENDPOINT_NINA_BASE, CITY_STATES_CODE, COUNTIES, _LOGGER, ) from .baseApi import BaseAPI from .warning import Warning from .label_matcher import LabelMatcher class Nina(BaseAPI, metaclass=ReadOnlyClass): """Main class to interact with the NINA API""" def __init__(self, session: ClientSession = None): """Initialize.""" super().__init__(session) self.warnings: Dict[str, list[Any]] = {} self.regions: list = [] self.matcher: LabelMatcher = LabelMatcher(session) def addRegion(self, regionCode: str): """Add a region to monitor.""" if regionCode not in self.regions: self.regions.append(regionCode) async def update(self): """Update the warnings.""" if not len(self.matcher.labels): await self.matcher.update() self.warnings.clear() for regionCode in self.regions: _LOGGER.debug(f"Update region: {regionCode}") url: str = ENDPOINT_NINA_BASE + regionCode + ".json" data = await self._makeRequest(url) self.warnings[regionCode] = [] for warn in data: warning: Warning = Warning(warn) await warning.getDetails(self.matcher) self.warnings[regionCode].append(warning) async def getAllRegionalCodes(self) -> Dict[str, str]: """Fetch all regional codes.""" _LOGGER.debug("Get all regional codes") rawCodeData: Dict[str, Any] = await self._makeRequest(ENDPOINT_REGIONAL_CODE) regionalCodes: Dict[str, str] = {} for dataBlock in rawCodeData["daten"]: id: str = dataBlock[0] name: str = dataBlock[1] if id[:5] in COUNTIES: name = f"{name} ({COUNTIES[id[:5]]})" if id[:2] not in CITY_STATES_CODE: id = id[: len(id) - 7] + "0000000" regionalCodes[name] = id if id[:2] in CITY_STATES_CODE and id[:2] + "0" * 10 == id: regionalCodes[name] = id return regionalCodes ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1743707833.0 pynina-0.3.6/pynina/warning.py0000777000175000017500000000552514773557271015151 0ustar00useruserimport datetime import html from typing import Any, Dict, Optional from aiohttp import ClientSession from .baseApi import BaseAPI from .const import _LOGGER, ENDPOINT_WARNING_DETAIL, ReadOnlyClass from .label_matcher import LabelMatcher class Warning(BaseAPI, metaclass=ReadOnlyClass): """Class to reflect a warning.""" def __init__(self, data: Dict[str, Any], session: ClientSession = None): """Initialize.""" super().__init__(session) self.id: str = data["payload"]["id"] self.headline: str = data["payload"]["data"]["headline"] self.severity: str = data["payload"]["data"]["severity"] self.description: str = "" self.sender: str = "" self.affected_areas: list[str] = [] self.recommended_actions: list[str] = [] self.web: str = "" self.sent: str = data["sent"] self.start: Optional[str] = data.get("effective", data.get("onset", None)) self.expires: Optional[str] = data.get("expires", None) self.raw: Dict[str, Any] = data def isValid(self) -> bool: """Test if warning is valid.""" if self.expires is not None: currDate: datetime = datetime.datetime.now().timestamp() expiresDate = datetime.datetime.fromisoformat(self.expires).timestamp() return currDate < expiresDate return True async def getDetails(self, matcher: LabelMatcher = None): """Get the details of a warning.""" _LOGGER.debug(f"Fetch details for {self.id}") url: str = ENDPOINT_WARNING_DETAIL + self.id + ".json" data = await self._makeRequest(url) infos = data["info"][0] self.description = html.unescape(infos.get("description", "")) if "senderName" in infos: self.sender = infos.get("senderName", "") if "web" in infos: self.web = infos.get("web", "") for area in infos.get("area", []): self.affected_areas.append(area["areaDesc"]) recommended_actions_raw: list[str] = [] for parameter in infos.get("parameter", {}): if parameter["valueName"] == "instructionCode": recommended_actions_raw = parameter["value"].split(" ") if "instruction" in infos: self.recommended_actions = [ infos.get("instruction", "").replace("
", " ") ] if matcher is not None and len(self.recommended_actions) == 0: for code in recommended_actions_raw: self.recommended_actions.append(matcher.match(code)) def __repr__(self) -> str: return ( f"{self.id} ({self.sent}): [{self.sender}, {self.start} - " f"{self.expires} ({self.sent})] {self.headline}, {self.description} - {self.web}" ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1746721154.4802425 pynina-0.3.6/pynina.egg-info/0000777000175000017500000000000015007154602014570 5ustar00useruser././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1746721154.0 pynina-0.3.6/pynina.egg-info/PKG-INFO0000777000175000017500000000401515007154602015670 0ustar00useruserMetadata-Version: 2.1 Name: pynina Version: 0.3.6 Summary: A Python API wrapper to retrieve warnings from the german NINA app. Home-page: https://gitlab.com/DeerMaximum/pynina Author: DeerMaximum Author-email: git983456@parabelmail.de License: MIT License Copyright (c) 2021 DeerMaximum Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Description-Content-Type: text/markdown License-File: LICENSE # Nina-API A Python API wrapper to retrieve warnings from the german NINA app. ## How to use package ```python import asyncio from pynina import Nina, ApiError async def main(): try: n: Nina = Nina() n.addRegion("146270000000") await n.update() for i in n.warnings["146270000000"]: print(i) print(i.isValid()) except ApiError as error: print(f"Error: {error}") loop = asyncio.get_event_loop() loop.run_until_complete(main()) loop.close() ``` ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1746721154.0 pynina-0.3.6/pynina.egg-info/SOURCES.txt0000777000175000017500000000043515007154602016461 0ustar00useruserLICENSE README.md setup.py pynina/__init__.py pynina/baseApi.py pynina/const.py pynina/label_matcher.py pynina/nina.py pynina/warning.py pynina.egg-info/PKG-INFO pynina.egg-info/SOURCES.txt pynina.egg-info/dependency_links.txt pynina.egg-info/requires.txt pynina.egg-info/top_level.txt././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1746721154.0 pynina-0.3.6/pynina.egg-info/dependency_links.txt0000777000175000017500000000000115007154602020641 0ustar00useruser ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1746721154.0 pynina-0.3.6/pynina.egg-info/requires.txt0000777000175000017500000000002015007154602017163 0ustar00useruseraiohttp>=3.11.6 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1746721154.0 pynina-0.3.6/pynina.egg-info/top_level.txt0000777000175000017500000000000715007154602017322 0ustar00useruserpynina ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1746721154.5027418 pynina-0.3.6/setup.cfg0000777000175000017500000000004615007154603013425 0ustar00useruser[egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1746721004.0 pynina-0.3.6/setup.py0000777000175000017500000000111415007154354013316 0ustar00useruserfrom setuptools import setup with open("README.md", "r") as f: readme = f.read() with open("LICENSE", "r") as f: license = f.read() setup( name="pynina", version="0.3.6", description="A Python API wrapper to retrieve warnings from the german NINA app.", long_description=readme, long_description_content_type="text/markdown", url="https://gitlab.com/DeerMaximum/pynina", author="DeerMaximum", author_email="git983456@parabelmail.de", license=license, packages=["pynina"], install_requires=["aiohttp>=3.11.6"], )