sanmar_sdk.ftp.readers ====================== .. py:module:: sanmar_sdk.ftp.readers .. autoapi-nested-parse:: Streaming SanMar's delimited data files into records, one row at a time. SanMar's files are large (the extended product file runs to hundreds of thousands of rows), so nothing here reads a whole file into memory: every reader is a generator over the lines of an open text stream. Column names are matched after normalizing them, because SanMar's spelling drifts between files and guide revisions: ``STYLE#``, ``BACK_MODEL _IMAGE_URL``, ``CATALOG.COLOR`` and ``Whse_ No`` become ``style#``, ``back_model_image_url``, ``catalog_color`` and ``whse_no``. Records declare their columns by those normalized names. Attributes ---------- .. autoapisummary:: sanmar_sdk.ftp.readers.logger sanmar_sdk.ftp.readers.Source Functions --------- .. autoapisummary:: sanmar_sdk.ftp.readers.normalize_column sanmar_sdk.ftp.readers.open_source sanmar_sdk.ftp.readers.read_delimited Module Contents --------------- .. py:data:: logger .. py:data:: Source A file to read, as a path on disk or a text stream that is already open. .. py:function:: normalize_column(name: str) -> str Normalize a column name for matching: lowercase, with runs of punctuation as ``_``. ``#`` is kept, because SanMar uses it to mean "number" (``STYLE#``, ``SALESORDER#``). .. py:function:: open_source(source: Source, encoding: str = 'utf-8-sig') -> collections.abc.Iterator[TextIO] Open a path for reading, or pass an already-open stream through untouched. ``utf-8-sig`` reads plain UTF-8 too, and drops the byte-order mark SanMar's CSV files start with. .. py:function:: read_delimited[R: sanmar_sdk.base.Record](source: Source, record: type[R], *, columns: collections.abc.Sequence[str], delimiter: str = ',', encoding: str = 'utf-8-sig') -> collections.abc.Iterator[R] Yield one record per row of a delimited SanMar file. ``columns`` is the file's layout, already normalized. When the file starts with a header row, its own column names are used and the order of ``columns`` does not matter. When it does not, rows must have exactly as many fields as ``columns``. :raises ~sanmar_sdk.exceptions.FileFormatError: If the header lacks a column the record requires, a headerless row has the wrong number of fields, or a row does not validate. The error names the line.