<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.dura-lex.org/index.php?action=history&amp;feed=atom&amp;title=Development%2FPython</id>
	<title>Development/Python - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.dura-lex.org/index.php?action=history&amp;feed=atom&amp;title=Development%2FPython"/>
	<link rel="alternate" type="text/html" href="https://wiki.dura-lex.org/index.php?title=Development/Python&amp;action=history"/>
	<updated>2026-04-23T05:29:39Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.45.3</generator>
	<entry>
		<id>https://wiki.dura-lex.org/index.php?title=Development/Python&amp;diff=36&amp;oldid=prev</id>
		<title>Nicolas: Create Python conventions page from coding-conventions/PYTHON.md (via create-page on MediaWiki MCP Server)</title>
		<link rel="alternate" type="text/html" href="https://wiki.dura-lex.org/index.php?title=Development/Python&amp;diff=36&amp;oldid=prev"/>
		<updated>2026-04-23T02:04:17Z</updated>

		<summary type="html">&lt;p&gt;Create Python conventions page from coding-conventions/PYTHON.md (via create-page on MediaWiki MCP Server)&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;= Python Conventions =&lt;br /&gt;
&lt;br /&gt;
All duralex-* packages follow these conventions. No exceptions.&lt;br /&gt;
&lt;br /&gt;
== Naming ==&lt;br /&gt;
&lt;br /&gt;
=== Casing (PEP 8) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Element !! Case !! Example&lt;br /&gt;
|-&lt;br /&gt;
| Functions, methods, variables || &amp;lt;code&amp;gt;snake_case&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;parse_legislation_article()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Classes || &amp;lt;code&amp;gt;PascalCase&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;LegislationArticle&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Constants || &amp;lt;code&amp;gt;UPPER_SNAKE&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ALLOWED_TABLE_NAMES&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Enum members || &amp;lt;code&amp;gt;UPPER_SNAKE&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;Confidence.SOURCE_CHECKED&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Enum string values || &amp;lt;code&amp;gt;lowercase&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&amp;quot;source_checked&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Module filenames || &amp;lt;code&amp;gt;snake_case&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;connection_pool.py&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== No abbreviations ===&lt;br /&gt;
&lt;br /&gt;
The code is written and maintained by AI. The AI does not tire of typing. Full words always.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Wrong !! Right&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ref&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;reference&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;leg&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;legislation&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dec&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;decision&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;doc&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;document&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;fts&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;full_text_search&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;tbl&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;query&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;lim&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;limit&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;flt&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;filter&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;el&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;element&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ctx&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;context&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;conn&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;connection&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;cfg&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;configuration&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;idx&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;val&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Qualified names ===&lt;br /&gt;
&lt;br /&gt;
Single-word names are ambiguous. Always qualify with the domain.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Wrong !! Right !! Why&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;query&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;search_query&amp;lt;/code&amp;gt; || Could be SQL, HTTP, FTS...&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;text&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;article_text&amp;lt;/code&amp;gt; || Could be anything&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;content&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;html_content&amp;lt;/code&amp;gt; || What kind?&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;result&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;search_result&amp;lt;/code&amp;gt; || Result of what?&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;decision_data&amp;lt;/code&amp;gt; || Meaningless alone&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;items&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;matched_articles&amp;lt;/code&amp;gt; || What items?&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;response&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;search_response&amp;lt;/code&amp;gt; || From where?&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;path&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;file_path&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;concept_path&amp;lt;/code&amp;gt; || Filesystem? URI?&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Booleans read as phrases ===&lt;br /&gt;
&lt;br /&gt;
A boolean variable or parameter must read as a true/false statement.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Wrong&lt;br /&gt;
active = True&lt;br /&gt;
force = False&lt;br /&gt;
recursive = True&lt;br /&gt;
&lt;br /&gt;
# Right&lt;br /&gt;
is_in_force = True&lt;br /&gt;
should_force_refresh = False&lt;br /&gt;
is_recursive = True&lt;br /&gt;
has_been_verified = False&lt;br /&gt;
should_include_repealed = True&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Classes: named for what they ARE ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class LegislationArticle: ...&lt;br /&gt;
class CaseLawDecision: ...&lt;br /&gt;
class ResolvedReference: ...&lt;br /&gt;
class AnnotationEnvelope: ...&lt;br /&gt;
class ConceptDefinition: ...&lt;br /&gt;
class SearchFilters: ...&lt;br /&gt;
class SearchResults: ...&lt;br /&gt;
class CompiledPackage: ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Methods: verb + explicit object ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def parse_legislation_article(xml_path: Path) -&amp;gt; LegislationArticle: ...&lt;br /&gt;
def resolve_legal_reference(raw_text: str) -&amp;gt; list[ResolvedReference]: ...&lt;br /&gt;
def search_full_text(query: str, filters: SearchFilters) -&amp;gt; SearchResults: ...&lt;br /&gt;
def compile_domain_package(domain: str) -&amp;gt; CompiledPackage: ...&lt;br /&gt;
def sanitize_html_content(raw_html: str) -&amp;gt; str: ...&lt;br /&gt;
def extract_text_content(element: Element, xpath: str) -&amp;gt; str | None: ...&lt;br /&gt;
def validate_date_range(date_from: str | None, date_to: str | None) -&amp;gt; None: ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Protocols: named for the capability ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class LegislationParser(Protocol): ...&lt;br /&gt;
class ReferenceResolver(Protocol): ...&lt;br /&gt;
class SearchEngine(Protocol): ...&lt;br /&gt;
class VersionSelector(Protocol): ...&lt;br /&gt;
class DecisionDownloader(Protocol): ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Enums ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class ConceptType(Enum):&lt;br /&gt;
    QUALIFIABLE = &amp;quot;qualifiable&amp;quot;&lt;br /&gt;
    OPEN_STANDARD = &amp;quot;open_standard&amp;quot;&lt;br /&gt;
    GUIDING_PRINCIPLE = &amp;quot;guiding_principle&amp;quot;&lt;br /&gt;
    PROCEDURAL = &amp;quot;procedural&amp;quot;&lt;br /&gt;
    SCALE = &amp;quot;scale&amp;quot;&lt;br /&gt;
&lt;br /&gt;
class Confidence(Enum):&lt;br /&gt;
    STUB = &amp;quot;stub&amp;quot;&lt;br /&gt;
    MEMORY_ONLY = &amp;quot;memory_only&amp;quot;&lt;br /&gt;
    SOURCE_CHECKED = &amp;quot;source_checked&amp;quot;&lt;br /&gt;
    CROSS_VALIDATED = &amp;quot;cross_validated&amp;quot;&lt;br /&gt;
&lt;br /&gt;
class Outcome(Enum):&lt;br /&gt;
    QUALIFIED = &amp;quot;qualified&amp;quot;&lt;br /&gt;
    NOT_QUALIFIED = &amp;quot;not_qualified&amp;quot;&lt;br /&gt;
    VALIDATED = &amp;quot;validated&amp;quot;&lt;br /&gt;
    INVALIDATED = &amp;quot;invalidated&amp;quot;&lt;br /&gt;
    PROCEDURAL = &amp;quot;procedural&amp;quot;&lt;br /&gt;
    MOOT = &amp;quot;moot&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Architecture patterns ==&lt;br /&gt;
&lt;br /&gt;
=== Dependency injection ===&lt;br /&gt;
&lt;br /&gt;
Dependencies are passed explicitly. No global singletons, no module-level mutable state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Wrong&lt;br /&gt;
class SearchEngine:&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self._pool = _get_global_pool()&lt;br /&gt;
        self._load_cache()&lt;br /&gt;
&lt;br /&gt;
# Right&lt;br /&gt;
class FullTextSearchEngine:&lt;br /&gt;
    def __init__(self, connection_pool: ConnectionPool):&lt;br /&gt;
        self.connection_pool = connection_pool&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== No side effects in &amp;lt;code&amp;gt;__init__&amp;lt;/code&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Constructors store parameters. They do not open connections, load caches, or perform I/O.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Wrong&lt;br /&gt;
class FrenchReferenceResolver:&lt;br /&gt;
    def __init__(self, connection_pool: ConnectionPool):&lt;br /&gt;
        self.connection_pool = connection_pool&lt;br /&gt;
        self._code_cache = self._load_code_cache()  # I/O in __init__&lt;br /&gt;
&lt;br /&gt;
# Right&lt;br /&gt;
class FrenchReferenceResolver:&lt;br /&gt;
    def __init__(self, connection_pool: ConnectionPool):&lt;br /&gt;
        self.connection_pool = connection_pool&lt;br /&gt;
        self._code_cache: dict[str, str] | None = None&lt;br /&gt;
&lt;br /&gt;
    def _ensure_code_cache(self) -&amp;gt; dict[str, str]:&lt;br /&gt;
        if self._code_cache is None:&lt;br /&gt;
            self._code_cache = self._load_code_cache()&lt;br /&gt;
        return self._code_cache&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Composition over inheritance ===&lt;br /&gt;
&lt;br /&gt;
Core libraries define &amp;lt;code&amp;gt;Protocol&amp;lt;/code&amp;gt; interfaces. Country packages and plugins provide implementations. Applications compose them.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# duralex -- defines the interface&lt;br /&gt;
class ReferenceResolver(Protocol):&lt;br /&gt;
    def resolve_legal_reference(self, raw_text: str) -&amp;gt; list[ResolvedReference]: ...&lt;br /&gt;
&lt;br /&gt;
class CompositeReferenceResolver:&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Chains multiple resolvers. First match wins.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    def __init__(self, resolvers: list[ReferenceResolver]):&lt;br /&gt;
        self.resolvers = resolvers&lt;br /&gt;
&lt;br /&gt;
    def resolve_legal_reference(self, raw_text: str) -&amp;gt; list[ResolvedReference]:&lt;br /&gt;
        for resolver in self.resolvers:&lt;br /&gt;
            if results := resolver.resolve_legal_reference(raw_text):&lt;br /&gt;
                return results&lt;br /&gt;
        return []&lt;br /&gt;
&lt;br /&gt;
# duralex-fr -- implements for France&lt;br /&gt;
class FrenchLegalReferenceResolver:&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;French legal references: articles, lois, pourvois, ECLI.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
# Application -- composes at startup&lt;br /&gt;
resolver = CompositeReferenceResolver([&lt;br /&gt;
    FrenchLegalReferenceResolver(connection_pool=pool),&lt;br /&gt;
    SireneCompanyResolver(),&lt;br /&gt;
])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== One module = one concept ===&lt;br /&gt;
&lt;br /&gt;
A Python file should contain one coherent concept. If you need a table of contents to navigate the file, split it.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Wrong !! Right&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;db.py&amp;lt;/code&amp;gt; (1400 lines: pool + CRUD + FTS + ingest + dedup + browse) || &amp;lt;code&amp;gt;connection_pool.py&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;full_text_search.py&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ingest_state.py&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;browse_structure.py&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;validation.py&amp;lt;/code&amp;gt; (filters + jurisdiction + pagination + dates + courts) || &amp;lt;code&amp;gt;search_filters.py&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;court_classification.py&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Target: &amp;#039;&amp;#039;&amp;#039;under 300 lines per file&amp;#039;&amp;#039;&amp;#039;. Hard limit: &amp;#039;&amp;#039;&amp;#039;500 lines&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
== Type annotations ==&lt;br /&gt;
&lt;br /&gt;
Every function signature is fully annotated. An auditor reads signatures before reading bodies.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Wrong&lt;br /&gt;
def search(query, table, limit=20):&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
# Right&lt;br /&gt;
def search_full_text(&lt;br /&gt;
    search_query: str,&lt;br /&gt;
    table_name: str,&lt;br /&gt;
    result_limit: int = 20,&lt;br /&gt;
    date_from: date | None = None,&lt;br /&gt;
    date_to: date | None = None,&lt;br /&gt;
) -&amp;gt; SearchResults:&lt;br /&gt;
    ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt; union syntax (Python 3.10+), not &amp;lt;code&amp;gt;Optional&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Union&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Docstrings ==&lt;br /&gt;
&lt;br /&gt;
Every public class and function has a docstring. Docstrings include &amp;lt;code&amp;gt;Examples&amp;lt;/code&amp;gt; blocks -- AI reads examples first to understand expected behavior.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def resolve_legal_reference(raw_text: str) -&amp;gt; list[ResolvedReference]:&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Parse a legal citation string into structured references.&lt;br /&gt;
&lt;br /&gt;
    Runs a pipeline of detectors in priority order (most specific first).&lt;br /&gt;
    First match wins. Returns empty list if no pattern matches.&lt;br /&gt;
&lt;br /&gt;
    Args:&lt;br /&gt;
        raw_text: A French legal citation in natural language.&lt;br /&gt;
&lt;br /&gt;
    Returns:&lt;br /&gt;
        List of resolved references with canonical URIs.&lt;br /&gt;
&lt;br /&gt;
    Examples:&lt;br /&gt;
        &amp;gt;&amp;gt;&amp;gt; resolve_legal_reference(&amp;quot;article 1240 du code civil&amp;quot;)&lt;br /&gt;
        [ResolvedReference(uri=&amp;quot;fr.law.code.civil.article-1240&amp;quot;)]&lt;br /&gt;
&lt;br /&gt;
        &amp;gt;&amp;gt;&amp;gt; resolve_legal_reference(&amp;quot;loi n° 85-677&amp;quot;)&lt;br /&gt;
        [ResolvedReference(uri=&amp;quot;fr.law.loi.85-677&amp;quot;)]&lt;br /&gt;
&lt;br /&gt;
        &amp;gt;&amp;gt;&amp;gt; resolve_legal_reference(&amp;quot;bonjour&amp;quot;)&lt;br /&gt;
        []&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Error handling ==&lt;br /&gt;
&lt;br /&gt;
Errors are explicit. Never swallowed. Never hidden behind a generic fallback.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Wrong&lt;br /&gt;
try:&lt;br /&gt;
    result = parse_article(path)&lt;br /&gt;
except Exception:&lt;br /&gt;
    result = None&lt;br /&gt;
&lt;br /&gt;
# Right&lt;br /&gt;
try:&lt;br /&gt;
    result = parse_article(path)&lt;br /&gt;
except FileNotFoundError:&lt;br /&gt;
    raise ArticleNotFoundError(article_id=article_id, path=path) from None&lt;br /&gt;
except etree.XMLSyntaxError as error:&lt;br /&gt;
    raise ArticleParseError(article_id=article_id, detail=str(error)) from error&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Custom exception classes inherit from a common base:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class DuralexError(Exception):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Base exception for all Dura Lex errors.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
class ArticleNotFoundError(DuralexError):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Raised when a legislation article file does not exist on disk.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
class ArticleParseError(DuralexError):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Raised when a legislation article XML file cannot be parsed.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
class ReferenceResolutionError(DuralexError):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Raised when a legal reference is ambiguous or malformed.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Language ==&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;All code is in English.&amp;#039;&amp;#039;&amp;#039; Variable names, function names, class names, docstrings, comments, error messages -- everything.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Content is in the jurisdiction&amp;#039;s language.&amp;#039;&amp;#039;&amp;#039; Concept names (&amp;lt;code&amp;gt;fr.civil.contrat.formation.consentement.vice.dol&amp;lt;/code&amp;gt;), article text, legal vocabulary, court names -- these are in French (or the local language of the jurisdiction).&lt;br /&gt;
&lt;br /&gt;
The boundary is clear: code structure is English, data values are local.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;/div&gt;</summary>
		<author><name>Nicolas</name></author>
	</entry>
</feed>