tephpy.io.wyoming ================= .. py:module:: tephpy.io.wyoming .. autoapi-nested-parse:: University of Wyoming sounding archive reader (spec §3.4). :func:`fetch` requests one ascent from the archive's post-2024 wsgi interface in its machine-readable ``TEXT:CSV`` form — bare, self-describing CSV (verified 2026-07-27) — over stdlib ``urllib`` behind a function-local import, and hands the body to a pure, transport-free parser. Network failures, HTTP errors, and the archive's "no data" replies raise :class:`~tephpy.exceptions.TephpyIOError` summarising the upstream response; the parsed sounding passes the ordinary ingest validation (spec §6). Notes ----- .. versionadded:: 0.1.0 .. !! processed by numpydoc !! Functions --------- .. autoapisummary:: tephpy.io.wyoming.fetch tephpy.io.wyoming.parse Module Contents --------------- .. py:function:: fetch(station: str, time: datetime.datetime | str, *, timeout: float | None = None) -> tephpy.sounding.Sounding Fetch one sounding from the University of Wyoming archive. :Parameters: **station** : :class:`python:str` The WMO station identifier, e.g. ``"72357"``. **time** : :obj:`datetime.datetime` or :class:`python:str` The nominal launch time; a string is read with :meth:`datetime.datetime.fromisoformat`, and a naive value is read as UTC (the ``Sounding`` convention). **timeout** : :class:`python:float`, optional The request timeout in seconds (default ``WYOMING_TIMEOUT``). :Returns: :obj:`Sounding ` The validated sounding, with `station` and `time` as metadata — so the legend label derives for free (spec §3.4). :Raises: :obj:`TephpyIOError ` For network failures, HTTP errors (including the archive's "no data at that time" and "unknown station" replies), or a response the parser does not recognise. :obj:`TypeError` If `time` is neither a datetime nor a string. :obj:`ValueError` If a `time` string is not ISO 8601. .. rubric:: Notes .. versionadded:: 0.1.0 .. !! processed by numpydoc !! .. py:function:: parse(text: str, *, station: str | None = None, time: datetime.datetime | str | None = None) -> tephpy.sounding.Sounding Read one ``TEXT:CSV`` archive body into a sounding. The route :func:`fetch` cannot serve: a body the caller already has. A response cached against a rate limit, one pulled through a proxy that this package's ``urlopen`` call cannot reach, or a bulk archive dump someone else downloaded -- each is the same text over the same format, with only the retrieval differing, and :func:`fetch` is retrieval. The two share this parser rather than agreeing by inspection, so a body read here and a body fetched become the same ``Sounding``. `station` and `time` are metadata rather than parsing input: the archive body carries neither the identifier that was asked for nor the nominal hour it was asked for, so a caller who knows them says so and gets the legend label derived (spec §3.4). A caller who does not gets a sounding without one, which is a sounding all the same. Blank cells read as NaN (NaN gaps are data, spec §3.4); rows whose pressure does not strictly decrease on the running minimum are dropped keeping the first occurrence, so the dense BUFR-era ascents satisfy ``Sounding``'s strict monotonicity; an optional field that is entirely NaN is treated as absent — and the wind pair as a unit, so a one-sided wind column passes as absent rather than tripping ``Sounding``'s pairing rule — keeping the missing-data errors meaningful downstream (spec §6). The archive's CSV is rectangular, so a row with fewer cells than the header is a truncated reply rather than a gap: it is rejected naming the row (the header is row 1). Trailing cells beyond the header are ignored — every carried column is located by its header index. :Parameters: **text** : :class:`python:str` The response body. **station** : :class:`python:str`, optional The WMO station identifier, carried as metadata; omitted, no legend label derives. **time** : :obj:`datetime.datetime` or :class:`python:str`, optional The nominal launch time, carried as metadata; a string is read the way :func:`fetch` reads one, so the two do not diverge. Omitted, no legend label derives. :Returns: :obj:`Sounding ` The validated sounding. :Raises: :obj:`TephpyIOError ` If the body is not readable as CSV at all, expected columns are missing, a row is shorter than the header, the header carries no data rows, or a cell is not numeric. :obj:`TypeError` If `time` is neither a datetime nor a string. :obj:`ValueError` If a `time` string is not ISO 8601. .. rubric:: Notes .. versionadded:: 0.1.0 .. !! processed by numpydoc !!