Skip to content
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
57320ff
first implem to get a quick review on the structure.
ttdm Dec 3, 2025
645663e
feat: define proper name, title, description for each schema.
ttdm Dec 3, 2025
c2b1f38
chore: remore old json schema
ttdm Dec 3, 2025
1f1fe1b
feat: move the scripts in sources, create github actions
ttdm Feb 16, 2026
f5b3f6f
chore: auto-generate schemas from source [skip ci]
github-actions[bot] Feb 16, 2026
225423c
feat: simplify extensions with the working generation
ttdm Feb 16, 2026
578f65a
chore: auto-generate schemas from source [skip ci]
github-actions[bot] Feb 16, 2026
f089353
chore: remove exemples
ttdm Feb 16, 2026
1c226dd
fix: assert version path
ttdm Feb 19, 2026
ff93e48
test: testing a wrong value in a json field to test the Ci frictionl…
ttdm Feb 19, 2026
e1a0732
chore: auto-generate schemas from source [skip ci]
github-actions[bot] Feb 19, 2026
e0348d7
chore: reseting to a proper exemple value
ttdm Feb 19, 2026
f43f83f
chore: auto-generate schemas from source [skip ci]
github-actions[bot] Feb 19, 2026
41d6553
feat: merger improvements, test improvement; small code quality impr…
ttdm Feb 19, 2026
d487442
chore: keep cleaning the code
ttdm Feb 19, 2026
5034df1
chore: move the builder main entry point on top of its class; move co…
ttdm Feb 24, 2026
347808e
feat: all small improvements from the review
ttdm Mar 20, 2026
cff5e51
feat: create a proper datapackage which link towards all table-schemas
ttdm Mar 20, 2026
68fdbb8
feat: add path into schemas, clarify what to_table_schema does
ttdm Mar 20, 2026
62bf8c6
refactor(schema_builder): make the repo_root injectable
David-Guillot Apr 8, 2026
bf72731
feat(schema_example_generator): move generated examples
David-Guillot Apr 8, 2026
4256243
test: initial testing
David-Guillot Apr 8, 2026
75b1d71
chore(ci): run tests before building schemas
David-Guillot Apr 8, 2026
6ec805d
feat: centralize all constants in a file, generate the current schema…
ttdm Apr 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 24 additions & 35 deletions .github/workflows/assert_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,57 +8,46 @@
def check(obj, version, parents=""):
"""
This functions recursively parses all fields in the schema looking for
version names that would not be the same as the one mentionned
version names that would not be the same as the one mentioned
in the 'version' field
"""
errors = []
# if field is a string, we check for a potential version
if isinstance(obj, str):
tmp = re.search(pattern, obj)
if tmp and tmp[0] != version:
errors += [(parents, tmp[0])]
version_match = re.search(pattern, obj)
if version_match and version_match[0] != version:
errors += [(parents, version_match[0])]
# if field is a list, we check every item
elif isinstance(obj, list):
for idx, k in enumerate(obj):
errors += check(k, version, parents=parents + f"[{str(idx)}]")
for idx, item in enumerate(obj):
errors += check(item, version, parents=parents + f"[{str(idx)}]")
# if field is a dict, we check every value
elif isinstance(obj, dict):
for k in obj:
for key in obj:
# not checking the fields
if k != "fields":
if key != "fields":
errors += check(
obj[k],
obj[key],
version,
parents=parents + "." + k if parents else k
parents=parents + "." + key if parents else key
)
return errors


to_check = []
SCHEMA_CORE_PATH = "schema/core/schema-core.json"

if "schema.json" in os.listdir():
to_check.append("schema.json")
assert os.path.isfile(SCHEMA_CORE_PATH)

elif "datapackage.json" in os.listdir():
with open("datapackage.json", "r") as f:
datapackage = json.load(f)
for r in datapackage["resources"]:
to_check.append(r["schema"])
with open(SCHEMA_CORE_PATH, "r") as f:
schema = json.load(f)
version = schema["version"]

else:
raise Exception("No required file found")

for schema_path in to_check:
with open(schema_path, "r") as f:
schema = json.load(f)
version = schema["version"]

errors = check(schema, version)
if errors:
message = (
f"Versions are mismatched within the schema '{schema['name']}', "
f"expected version '{version}' but:"
)
for e in errors:
message += f"\n- {e[0]} has version '{e[1]}'"
raise Exception(message)
errors = check(schema, version)
if errors:
message = (
f"Versions are mismatched within the schema '{schema['name']}', "
f"expected version '{version}' but:"
)
for error_location, error_version in errors:
message += f"\n- {error_location} has version '{error_version}'"
raise Exception(message)
65 changes: 65 additions & 0 deletions .github/workflows/build_and_validate_schemas.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: Build and Validate Schemas

on:
push:
branches:
- master
- feat/**
paths:
- "schema/**/*.json"
- "src/**/*.py"
- "requirements.txt"
pull_request:
paths:
- "schema/**/*.json"
- "src/**/*.py"
- "requirements.txt"

jobs:
build-and-validate:
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.10"

- name: Cache pip
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
${{ runner.os }}-

- name: Install dependencies
run: pip install -r requirements.txt

- name: Build schemas from source
run: python3 src/build_schemas.py

- name: Check for changes
id: verify_diff
run: |
git diff --quiet build/ || echo "changed=true" >> $GITHUB_OUTPUT

- name: Commit and push if changes detected
if: steps.verify_diff.outputs.changed == 'true' && github.event_name == 'push'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add build/
git commit -m "chore: auto-generate schemas from source [skip ci]"
git push

- name: Validate generated schemas
run: python3 src/validate_schemas.py
29 changes: 0 additions & 29 deletions .github/workflows/frictionless_tests.yml

This file was deleted.

2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.pyc
*.backup
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ Ce fichier répertorie les changements entre différentes versions du schéma.
## Version 0.1.0 - 2025-09-19

Publication initiale.

## Version 0.2.0 - 2026-02-XX

Publication du code dédié à générer de multiples schémas et publication d'une première version temporaire dédiée aux entreprises.
151 changes: 151 additions & 0 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# Guide d'utilisation

## Workflow automatisé

**GitHub Actions génère et valide automatiquement les schémas** lorsque sont détextées des modifications dans `schema/` lors d'un push.

Vous n'avez qu'à modifier les fichiers sources dans `schema/core/` et `schema/extensions/` et commit le tout dans une branche puis la push sur github.

## Modifier un schéma

1. Ouvrir le fichier JSON concerné (core ou extension), ex: `schema/extensions/{category}/{name}.json`
Catégory étant limité à "cible" ou "usage".
(Autoriser plus d'option, nécessiterait d'introduire plus d'éléments de configuration, notamment pour pouvoir automatiquement savoir quelles combinaisons générer entre les différents catégories et les différents éléments de chaque catégorie.)

2. Ajouter un champ dans le tableau `fields` :

```json
{
"name": "nom_du_champ",
"title": "Titre du champ",
"description": "Description",
"type": "string",
"example": "valeur d'exemple",
"constraints": {
"required": true,
"maxLength": 500
}
}
```

3. Commit et push - GitHub Actions régénère et valide automatiquement les schémas

## Ajouter une extension (cible ou usage)

Le repo génère automatiquement toutes les combinaisons d'usages pour chaque cible.

Pour ajouter une nouvelle cible ou un nouvel usage :
1. Créer un fichier JSON dans `schema/extensions/cible/` ou `schema/extensions/usage/`
2. Suivre le format des fichiers existants
3. Commit et push - les schémas combinés sont générés automatiquement

# Development Guide

## Quick Setup

```bash
# Environment
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

# Generate schemas and example files (optional - automated via GitHub Actions)
python3 src/build_schemas.py

# Validate (optional - automated via GitHub Actions)
python3 src/validate_schemas.py
```

## Architecture

The repo uses a modular datapackage structure:

- **Core schema** (`schema/core/schema-core.json`) - Base fields required for all schemas
- **Extensions** - Optional fields for specific use cases (usage & target audience)
- **Build script** - Generates schemas for all combinations of usage for each target

```
schema/
├── core/schema-core.json
└── extensions/
├── usage/
│ ├── communication.json
│ ├── pilotage.json
│ └── activation.json
└── cible/
├── associations.json
├── particuliers.json
├── professionnels.json
└── secteur-public.json
```

## Common Tasks

### Add a Field

1. Open the relevant JSON file (core or extension), ex: `schema/extensions/{category}/{name}.json`
2. Add to the `fields` array:

```json
{
"name": "field_name",
"title": "Field Title",
"description": "Description",
"type": "string",
"example": "example value"
}
```

3. Commit and push - GitHub Actions will automatically regenerate and validate schemas
4. (Optional) Test locally: `python3 src/build_schemas.py && python3 src/validate_schemas.py`

### Create an Extension

The simplest way is to copy an existing extension for reference.

The written code automatically handles new targets or usages but needs to be edited if a new category of extensions is created.

Currently, there is no generic logic to handle a new type of extension.
In particular, the associations between extensions in this new category should be defined, and the allowed combinations between extension categories should be defined.

### Resolve Field Conflicts

When fields with the same name have different types, you'll get warnings. Resolve by:

**Option 1: Rename** - Use different names in different extensions

```json
// In usage/pilotage.json
{"name": "budget_total_alloue", "type": "number"}

// In cible/individuals.json
{"name": "budget_per_person", "type": "string"}
```

**Option 2: Harmonize** - Use the same type everywhere

```json
{ "name": "budget", "type": "number" }
```

**Future enhancements:**
Handle priority fields to allow overriding some fields. (Identified use case: make a field mandatory within an extension).

## Testing

```bash
# Validate a specific schema
frictionless validate build/schemas/dispositif-aide-pilotage.json

# Validate data against a schema
frictionless validate data.csv --schema build/schemas/dispositif-aide.json

# Validate all schemas
python3 scripts/validate_schemas.py
```

## References

- [Frictionless Data Specs](https://specs.frictionlessdata.io/)
- [Table Schema Spec](https://specs.frictionlessdata.io/table-schema/)
- [Data Package Spec](https://specs.frictionlessdata.io/data-package/)
Loading
Loading