Editing
Development/Packaging
(section)
Jump to navigation
Jump to search
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
= Packaging Conventions = All duralex-* packages follow these conventions for consistent packaging, installation, and namespace management. == Naming == {| class="wikitable" ! Layer !! Convention !! Example |- | Brand || Dura Lex (always two words) || β |- | Domain || <code>dura-lex.*</code> (hyphenated) || <code>dura-lex.org</code> |- | GitHub org || <code>duralex</code> || <code>github.com/duralex/</code> |- | PyPI package || <code>duralex-{name}</code> (hyphenated) || <code>duralex-fr</code>, <code>duralex-mcp</code> |- | Python import || <code>duralex.{name}</code> (dotted) || <code>from duralex.corpus import ...</code> |- | Exception || The core package is just <code>duralex</code> on PyPI || <code>pip install duralex</code> |} == Repository structure (6 repos) == <pre> ~/duralex/ βββ duralex/ # PyPI: duralex (core + corpus + specs) β βββ pyproject.toml β βββ src/duralex/ β β βββ corpus/ # DocumentStore, FTS, TagQuery β β βββ temporal/ # versioning, temporal types β β βββ data/ # citation types, text utils β β βββ annotations/ # annotation framework β β βββ concepts/ # concept definitions β β βββ errors.py # DuralexError base β β βββ database.py # DSN builder β β βββ logging.py # JSON/console logging β β βββ middleware.py # ASGI middleware β β βββ retry.py # exponential backoff β βββ tests/ β βββ sql/ # corpus DDL β βββ spec/ # authoritative specifications β βββ coding-conventions/ # this directory β βββ design-decisions/ # ADRs β βββ research/ # investigation logs β βββ issues/ # issue tracker β βββ duralex-jurisdictions/ # monorepo, two PyPI packages β βββ duralex-fr/ # PyPI: duralex-fr β β βββ pyproject.toml β β βββ src/duralex/fr/ β β βββ tests/ β βββ duralex-eu/ # PyPI: duralex-eu β βββ pyproject.toml β βββ src/duralex/eu/ β βββ tests/ β βββ duralex-ingest/ # monorepo, three PyPI packages β βββ duralex-ingest/ # PyPI: duralex-ingest β β βββ pyproject.toml β β βββ src/duralex/ingest/ # NO __init__.py (namespace) β β βββ tests/ β βββ duralex-ingest-fr/ # PyPI: duralex-ingest-fr β β βββ pyproject.toml β β βββ src/duralex/ingest/fr/ β β βββ tests/ β βββ duralex-ingest-eu/ # PyPI: duralex-ingest-eu β βββ pyproject.toml β βββ src/duralex/ingest/eu/ β βββ tests/ β βββ duralex-mcp/ # PyPI: duralex-mcp (+ Docker infra) β βββ pyproject.toml β βββ src/duralex/mcp/ β βββ tests/ β βββ Dockerfile β βββ docker-compose.dev.yml β βββ docker-compose.prod.yml β βββ Caddyfile β βββ duralex-portal/ # PyPI: duralex-portal β βββ pyproject.toml β βββ src/duralex/portal/ β βββ tests/ β βββ duralex-feedback/ # standalone, not distributed βββ server.py βββ Dockerfile βββ docker-compose.yml </pre> == src layout with namespace packages == Every package uses the '''src layout''' with implicit namespace packages (PEP 420). The critical rule: '''no <code>__init__.py</code> in namespace directories'''. Only leaf packages have <code>__init__.py</code>. <pre> duralex-fr/ βββ pyproject.toml βββ src/ β βββ duralex/ # NO __init__.py (namespace) β βββ fr/ # NO __init__.py (namespace) β βββ mcp/ β β βββ __init__.py # leaf package β β βββ ... β βββ refs/ β β βββ __init__.py β β βββ ... β βββ courts/ β βββ __init__.py β βββ ... βββ tests/ </pre> === Special case: duralex-ingest namespace === The <code>duralex.ingest</code> namespace is shared across three packages. The base <code>duralex-ingest</code> package must NOT have <code>__init__.py</code> at <code>src/duralex/ingest/</code> β otherwise Python blocks namespace discovery of <code>duralex.ingest.fr</code> and <code>duralex.ingest.eu</code> from sibling packages. <pre> duralex-ingest/duralex-ingest/src/duralex/ingest/ # NO __init__.py duralex-ingest/duralex-ingest/src/duralex/ingest/database/__init__.py # leaf duralex-ingest/duralex-ingest-fr/src/duralex/ingest/fr/__init__.py # leaf duralex-ingest/duralex-ingest-eu/src/duralex/ingest/eu/__init__.py # leaf </pre> == pyproject.toml template == <syntaxhighlight lang="toml"> [build-system] requires = ["setuptools>=69.0"] build-backend = "setuptools.build_meta" [project] name = "duralex-fr" version = "0.1.0" description = "France: legal reference resolver, court hierarchy, and validation for the Dura Lex ecosystem" requires-python = ">=3.12" license = "MIT" authors = [{ name = "Nicolas Baldeck" }] keywords = ["legal", "open-data", "france"] dependencies = [ "duralex>=0.1.0", ] [project.optional-dependencies] dev = [ "pytest>=8.2", "ruff>=0.15", "mypy>=1.15", ] [tool.setuptools.packages.find] where = ["src"] include = ["duralex.fr*"] [tool.ruff] line-length = 120 target-version = "py312" [tool.ruff.lint] select = ["E", "F", "W", "I", "UP", "B", "SIM", "TCH", "RUF", "PTH"] [tool.ruff.format] quote-style = "double" [tool.mypy] python_version = "3.12" strict = true namespace_packages = true explicit_package_bases = true mypy_path = ["src", "../../duralex/src"] [tool.pytest.ini_options] testpaths = ["tests"] addopts = ["--strict-config", "--strict-markers", "--import-mode=importlib", "-m not slow and not integration"] xfail_strict = true consider_namespace_packages = true filterwarnings = ["error"] markers = [ "slow: tests with extended runtime", "integration: requires PostgreSQL (testcontainers)", ] </syntaxhighlight> == Editable development installs == Install all packages in editable mode from the repo root: <syntaxhighlight lang="bash"> cd ~/duralex pip install -e "./duralex[dev,pg]" pip install -e "./duralex-jurisdictions/duralex-fr[dev,db]" pip install -e "./duralex-jurisdictions/duralex-eu[dev]" pip install -e "./duralex-ingest/duralex-ingest[dev]" pip install -e "./duralex-ingest/duralex-ingest-fr[dev]" pip install -e "./duralex-ingest/duralex-ingest-eu[dev]" pip install -e "./duralex-mcp[dev]" pip install -e "./duralex-portal[dev]" </syntaxhighlight> If namespace resolution breaks between sibling packages: <syntaxhighlight lang="bash"> pip install -e ".[dev]" --config-settings editable_mode=compat </syntaxhighlight> == Version policy == All packages start at <code>0.1.0</code>. Packages are versioned independently. A major version bump in <code>duralex</code> triggers compatibility review in all downstream packages. == Brand vs. code == The brand is always written '''Dura Lex''' (two words). Code identifiers use <code>duralex</code> (one word, no space) because Python and PyPI do not allow spaces. Never write "Duralex" β it is either "Dura Lex" (prose) or <code>duralex</code> (code). [[Category:Development]]
Summary:
Please note that all contributions to Dura Lex Wiki are considered to be released under the Creative Commons Attribution-ShareAlike (see
Dura Lex Wiki:Copyrights
for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource.
Do not submit copyrighted work without permission!
Cancel
Editing help
(opens in new window)
Navigation menu
Personal tools
Not logged in
Talk
Contributions
Create account
Log in
Namespaces
Page
Discussion
English
Views
Read
Edit
Edit source
View history
More
Search
Navigation
Main page
Recent changes
Random page
Help about MediaWiki
Special pages
Tools
What links here
Related changes
Page information