API¶
The API (Application Programming Interface) of a library is its public face: the objects, functions and methods that users are meant to touch. Everything else is an implementation detail you are free to change. Designing that face well is what separates a library people enjoy using from one they fight with.
The esperantilo package exposes one class and one function so far, so most of this
page is a design target: it shows what an NLP interface looks like.
The part that already exists
Everything below is illustrated by real, shipped code:
Library → API reference is the current public surface
of esperantilo, generated from its docstrings. Read this page for why an
API looks the way it does, and that one for what the library offers today.
What an API is here¶
Think of a library as having two sides:
- the public API — what users import and call, and what you promise to keep stable across versions;
- the internals — helper functions, private modules and data structures that make it work, which you can rewrite at any time.
The value of the distinction is freedom: as long as the public API keeps its shape, you can refactor everything behind it without breaking a single user. The first job of API design is therefore to decide what is public and to make that boundary obvious.
In Python, the boundary is drawn by convention and by __all__:
- Names prefixed with an underscore (
_helper,_Cache) are private — a signal that users should not rely on them. - The
__all__list in a module names its public objects. It documents the intended surface and controls whatfrom esperantilo import *brings in:
This is how esperantilo does it today, with its public API stated explicitly in __init__.py:
# esperantilo/__init__.py
from esperantilo.nlp import sentence_tokenizer
from esperantilo.wiki import WikiPage
__version__ = "0.1.0"
__all__ = ["__version__", "WikiPage", "sentence_tokenizer"] # the public API, stated explicitly
With this, a user writes from esperantilo import WikiPage and never has to
know that the class really lives in esperantilo.wiki.wiki, nor that it sits on
a private esperantilo.wiki._wiki_api module that may change without notice.
The full list, generated from the code itself, is in Library → API reference.
Designing a good one¶
A handful of principles make an interface predictable and pleasant. They are the same ones that make scikit-learn and spaCy easy to learn:
- Consistency. Similar things should look similar. If a
Docis iterable to yieldTokens, then any collection in the library should be iterable the same way. - Small, predictable signatures. Few parameters, sensible defaults, and no
surprises.
parse(text)should just work; options are extras, not obligations. - Meaningful names.
lemma,pos,is_stopsay what they are. Avoid abbreviations that only the author understands. - Type hints. Annotate parameters and return types. They document the interface, enable editor autocompletion, and let tools catch mistakes before runtime.
- Docstrings. Every public object gets a short docstring saying what it does, what it takes and what it returns.
def parse(text: str) -> "Doc":
"""Analyse Esperanto ``text`` and return a :class:`Doc`.
Args:
text: the raw Esperanto text to analyse.
Returns:
A ``Doc`` holding the analysed tokens.
"""
...
The type hints (text: str, -> "Doc") and the docstring together tell a user
everything they need to call parse correctly, without reading its body.
A spaCy-like API¶
spaCy is the reference model for this project. Its design is
worth copying because it turns messy text processing into a small set of typed,
predictable objects. The core idea: analysing text returns a Doc, and a
Doc is a sequence of Tokens, each carrying its linguistic attributes.
Here is the spaCy shape, which the Esperanto library aims to mirror:
import spacy
nlp = spacy.load("en_core_web_sm")
doc = nlp("The quick brown fox jumps.") # -> a Doc
for token in doc: # a Doc is iterable over Tokens
print(token.text, token.lemma_, token.pos_, token.is_stop)
The the DET True
quick quick ADJ False
brown brown ADJ False
fox fox NOUN False
jumps jump VERB False
. . PUNCT False
Two typed objects carry the whole model:
| Object | What it represents | Typical attributes |
|---|---|---|
Doc |
An analysed piece of text | iterable of Token, text, sents |
Token |
A single word/unit | text, lemma, pos, is_stop |
Applied to Esperanto — where the regular grammar makes these attributes computable by rule — the target interface looks like this:
# Illustrative target API for esperantilo.
import esperantilo
doc = esperantilo.parse("La rapida vulpo saltas.")
for token in doc:
print(token.text, token.lemma, token.pos, token.is_stop)
La la DET True
rapida rapida ADJ False
vulpo vulpo NOUN False
saltas salti VERB False
. . PUNCT False
Notice how the Esperanto endings map cleanly onto attributes — -a → adjective,
-o → noun, -as → present-tense verb (with lemma salti), and la is a
stop-word. That regularity, described in the Esperanto section,
is exactly what makes a rule-based Doc / Token implementation feasible.
For the full reference to imitate — method names, attribute names and object relationships — see the spaCy API documentation.
Documenting the API automatically¶
An API reference written by hand goes stale quickly: someone renames a parameter and the page still shows the old one. The fix is to generate the page from the docstrings, so there is only ever one copy of the truth.
mkdocstrings does that for MkDocs. A page holding nothing but a directive:
renders the signature, the type hints, the argument table and the examples of every listed object, each with a link to the source lines it came from. That is exactly how Library → API reference is built; its page source is four directives and a paragraph.
Two habits make the generated page worth reading:
- Write docstrings in a consistent style. This project uses the Google style
shown above (
Args:,Returns:,Examples:), declared once inmkdocs.yml. - Put examples in
Examples:blocks. Written as>>>sessions they are both documentation and doctests — CI runs them, so they cannot silently go stale.
Where to go next¶
- Library → API reference — the same ideas, applied: the
real public surface of
esperantilo, generated from its source. - Testing — how to verify the API behaves as designed.
- Esperanto § Grammar — the rules the API will encode.