Data Nexus

Language · We run it ourselves

Python

A general-purpose language whose value in this practice is narrow and specific: the reference implementations for reading and writing awkward archive and binary formats — .docx, .xlsx internals, font tables — are written in it.

The language for a script is chosen by asking which ecosystem already contains a correct implementation of the format the script has to produce. For document generation, font compilation, spreadsheet extraction and audio transcription that answer is Python, and for nothing else in the inventory is it. Python here is build-time tooling that emits artefacts, never a runtime — the deployed surface is Node.

python.org

01/Why this one

  1. 01

    A .docx file is a ZIP archive of XML parts joined by a relationship graph, and the failure mode of writing one by hand is not a crash. It is a document that opens with a repair prompt, or one where list numbering silently restarts at the third heading. python-docx encodes which parts must exist and how they reference each other; reimplementing that in whatever language the surrounding application happens to use buys nothing and costs the weeks it takes to discover which parts a word processor actually validates.


  2. 02

    Hyperlinks in an .xlsx do not live in the cell. The cell holds a display string; the target sits in xl/worksheets/_rels/sheetN.xml.rels keyed by a relationship id. Every tool that treats a spreadsheet as a grid of values drops them, which is precisely the data extract-xlsx-links.py exists to recover — the URLs someone pasted into a column years ago, often the only surviving record of where a number came from.


  3. 03

    Fonts are binary tables, not text. build-fonts.py and build-logo.py in the DYD repositories compile typographic assets ahead of the build rather than at request time, and the same reasoning puts OG image font embedding in Python: a face has to be subset and re-embedded, which means reading and rewriting tables, not templating a string. A language that cannot open the file at byte level is not a candidate for that job regardless of how pleasant it is elsewhere.


  4. 04

    The audio transcription pipeline is Python because container decoding, resampling and model invocation are all bindings problems and the bindings are there. It is not there for speed. Wall clock is dominated by the model, and the surrounding code does nothing but move buffers, retry on partial input and write out timings — work at which the language is irrelevant and the library availability is decisive.


  5. 05

    Python is confined to build time. Nothing on datanexus.ae and nothing in the deployed products executes Python on a request; the runtime is Node. This site generates its own PDFs in TypeScript — scripts/build-invoice.mts and scripts/build-proposal.mts — because that layout logic sits beside the site's own types and content, and no Python library removes work the Node PDF tooling does not already do.


  6. 06

    The rule cuts both ways and mostly cuts against Python. When the advantage would be a single library function, a second toolchain — an interpreter version, a virtual environment, wheels with native extensions, a second image in CI — costs more than the function returns. That is why the repository inventory contains no Python web service and no Python API layer: a language earns entry per problem, not per project, and most problems here do not admit it.


  7. 07

    These scripts are pure functions from inputs to artefacts, which makes the choice reversible. If the format tooling in another ecosystem catches up, build-fonts.py or extract-xlsx-links.py can be rewritten and deleted without anything at runtime noticing, because nothing at runtime depends on them. A Python service would not have that property, and that asymmetry is the reason the boundary sits where it sits.

02/What you can check

An entry that cannot point at something you can open, run or read does not compile. That is a property of the type, not a promise in a paragraph.

Case record
Font subsetting and logo generation as build steps, and two brand books rendered from source rather than laid out by hand.Read the record

In our code
DYD-main/ and dyd-site/ — A next / react / @supabase/supabase-js application whose only Python is build tooling: build-fonts.py, build-logo.py and extract-xlsx-links.py. The boundary is visible in the file listing — Python produces assets and extracted data, the application itself is TypeScript.

In our code
scripts/build-invoice.mts and scripts/build-proposal.mts (this site) — Document generation on datanexus.ae is TypeScript, not Python, and is run with tsx over the site's own content types. Evidence of where the rule refuses Python: the surrounding runtime is Node and no Python library removes work here.

Run it yourself
python3 -m zipfile -l proposal.docx → A listing containing word/document.xml and word/_rels/document.xml.rels. A .docx is an archive of parts plus a relationship graph, which is what python-docx constructs and what hand-rolled generators get wrong.

Property of the thing
Hyperlink targets in an .xlsx are stored outside the cell, in the worksheet's relationship part, and are lost by any reader that returns only cell values. — unzip -o book.xlsx -d out, then compare out/xl/worksheets/sheet1.xml (display strings, r:id attributes) with out/xl/worksheets/_rels/sheet1.xml.rels (the actual Target URLs). The URLs appear only in the second file.

Property of the thing
python-docx builds OOXML directly and requires no word processor, no COM automation and no headless office suite, so document generation runs in a plain Linux container with no licence attached to it. — In a container image with no office software installed: pip install python-docx, then generate and open a document. It succeeds; the equivalent automation route fails for want of an application to drive.
03/Where it stops

Invariant

Every Python script is a second toolchain living beside a TypeScript one, and it breaks at the seam rather than in the code. The artefacts these scripts produce — compiled fonts, generated documents, extracted link tables — are committed outputs, and nothing in the deployed build re-runs the scripts, so the build gates that guard this site (scripts/check-schema.ts, check-markdown.ts, check-knowledge.ts) cannot see when an artefact has drifted from the source it was generated from. A colleague on a different interpreter version, or one missing a wheel with a native extension, cannot regenerate them at all, and discovers this at the worst moment. Below roughly a few hundred lines of glue the arithmetic fails outright: a second lockfile, a second version manager and a second CI image cost more than the library saves, and the correct decision is to write the awkward parsing by hand in the language already present.