
❌ This issue is not open for contribution. Visit Contributing guidelines to learn about the contributing process and how to find suitable issues.

Overview
Migrate le_utils/constants/licenses.py from the legacy JSON-as-data approach to the modern spec + code generation system following the pattern established in #182.
Context
Currently, le_utils/constants/licenses.py uses the legacy approach:
- Loads
resources/licenselookup.json at runtime with pkgutil.get_data()
- Manual Python constants (
CC_BY = "CC BY", etc.) must be kept in sync
- No JavaScript export available
- Tests verify Python/JSON sync
Current Structure
File: le_utils/resources/licenselookup.json
{
"1": {
"name": "CC BY",
"exists": true,
"custom": false,
"copyright_holder_required": true,
"url": "https://creativecommons.org/licenses/by/4.0/"
},
"2": {
"name": "CC BY-SA",
...
},
...
}
Python module has:
- Namedtuple:
class License(namedtuple("License", ["id", "name", "exists", "url", "description", "custom", "copyright_holder_required"])): pass
- Manual constants:
CC_BY = "CC BY", CC_BY_SA = "CC BY-SA", etc.
LICENSELIST with License namedtuples
choices tuple
Target Spec Format
Create spec/constants-licenses.json:
{
"namedtuple": {
"name": "License",
"fields": ["id", "name", "exists", "url", "description", "custom", "copyright_holder_required"]
},
"constants": {
"1": {
"name": "CC BY",
"exists": true,
"custom": false,
"copyright_holder_required": true,
"url": "https://creativecommons.org/licenses/by/4.0/",
"description": ""
},
"2": {
"name": "CC BY-SA",
"exists": true,
"custom": false,
"copyright_holder_required": true,
"url": "https://creativecommons.org/licenses/by-sa/4.0/",
"description": ""
},
"3": {
"name": "CC BY-ND",
"exists": true,
"custom": false,
"copyright_holder_required": true,
"url": "https://creativecommons.org/licenses/by-nd/4.0/",
"description": ""
},
"4": {
"name": "CC BY-NC",
"exists": true,
"custom": false,
"copyright_holder_required": true,
"url": "https://creativecommons.org/licenses/by-nc/4.0/",
"description": ""
},
"5": {
"name": "CC BY-NC-SA",
"exists": true,
"custom": false,
"copyright_holder_required": true,
"url": "https://creativecommons.org/licenses/by-nc-sa/4.0/",
"description": ""
},
"6": {
"name": "CC BY-NC-ND",
"exists": true,
"custom": false,
"copyright_holder_required": true,
"url": "https://creativecommons.org/licenses/by-nc-nd/4.0/",
"description": ""
},
"7": {
"name": "All Rights Reserved",
"exists": true,
"custom": false,
"copyright_holder_required": true,
"url": "http://www.allrights-reserved.com/",
"description": ""
},
"8": {
"name": "Public Domain",
"exists": true,
"custom": false,
"copyright_holder_required": false,
"url": "https://creativecommons.org/publicdomain/mark/1.0/",
"description": ""
},
"9": {
"name": "Special Permissions",
"exists": false,
"custom": true,
"copyright_holder_required": true,
"url": "",
"description": ""
}
}
}
Note: The description field is in the namedtuple but currently empty in the JSON. Keep it as empty string for now.
Generated Output Example
Python (le_utils/constants/licenses.py):
# Generated by scripts/generate_from_specs.py
from collections import namedtuple
class License(namedtuple("License", ["id", "name", "exists", "url", "description", "custom", "copyright_holder_required"])):
pass
CC_BY = "CC BY"
CC_BY_SA = "CC BY-SA"
# ...
choices = (
(CC_BY, "Cc By"),
(CC_BY_SA, "Cc By-Sa"),
# ...
)
LICENSELIST = [
License(id=1, name="CC BY", exists=True, url="...", description="", custom=False, copyright_holder_required=True),
# ...
]
JavaScript (js/Licenses.js):
// Generated by scripts/generate_from_specs.py
export default {
CC_BY: "CC BY",
CC_BY_SA: "CC BY-SA",
// ...
};
export const LicensesList = [
{ id: 1, name: "CC BY", exists: true, url: "...", description: "", custom: false, copyright_holder_required: true },
// ...
];
export const LicensesMap = new Map(
LicensesList.map(license => [license.id, license])
);
Testing Updates
File: tests/test_licenses.py
Update to test against spec:
spec_path = os.path.join(os.path.dirname(__file__), "..", "spec", "constants-licenses.json")
with open(spec_path) as f:
spec = json.load(f)
licenselookup = spec["constants"]
How to Run Tests
pytest tests/test_licenses.py -v
pytest tests/ -v
Acceptance Criteria
Disclosure
🤖 This issue was written by Claude Code, under supervision, review and final edits by @rtibbles 🤖
❌ This issue is not open for contribution. Visit Contributing guidelines to learn about the contributing process and how to find suitable issues.
Overview
Migrate
le_utils/constants/licenses.pyfrom the legacy JSON-as-data approach to the modern spec + code generation system following the pattern established in #182.Context
Currently,
le_utils/constants/licenses.pyuses the legacy approach:resources/licenselookup.jsonat runtime withpkgutil.get_data()CC_BY = "CC BY", etc.) must be kept in syncCurrent Structure
File:
le_utils/resources/licenselookup.json{ "1": { "name": "CC BY", "exists": true, "custom": false, "copyright_holder_required": true, "url": "https://creativecommons.org/licenses/by/4.0/" }, "2": { "name": "CC BY-SA", ... }, ... }Python module has:
class License(namedtuple("License", ["id", "name", "exists", "url", "description", "custom", "copyright_holder_required"])): passCC_BY = "CC BY",CC_BY_SA = "CC BY-SA", etc.LICENSELISTwith License namedtupleschoicestupleTarget Spec Format
Create
spec/constants-licenses.json:{ "namedtuple": { "name": "License", "fields": ["id", "name", "exists", "url", "description", "custom", "copyright_holder_required"] }, "constants": { "1": { "name": "CC BY", "exists": true, "custom": false, "copyright_holder_required": true, "url": "https://creativecommons.org/licenses/by/4.0/", "description": "" }, "2": { "name": "CC BY-SA", "exists": true, "custom": false, "copyright_holder_required": true, "url": "https://creativecommons.org/licenses/by-sa/4.0/", "description": "" }, "3": { "name": "CC BY-ND", "exists": true, "custom": false, "copyright_holder_required": true, "url": "https://creativecommons.org/licenses/by-nd/4.0/", "description": "" }, "4": { "name": "CC BY-NC", "exists": true, "custom": false, "copyright_holder_required": true, "url": "https://creativecommons.org/licenses/by-nc/4.0/", "description": "" }, "5": { "name": "CC BY-NC-SA", "exists": true, "custom": false, "copyright_holder_required": true, "url": "https://creativecommons.org/licenses/by-nc-sa/4.0/", "description": "" }, "6": { "name": "CC BY-NC-ND", "exists": true, "custom": false, "copyright_holder_required": true, "url": "https://creativecommons.org/licenses/by-nc-nd/4.0/", "description": "" }, "7": { "name": "All Rights Reserved", "exists": true, "custom": false, "copyright_holder_required": true, "url": "http://www.allrights-reserved.com/", "description": "" }, "8": { "name": "Public Domain", "exists": true, "custom": false, "copyright_holder_required": false, "url": "https://creativecommons.org/publicdomain/mark/1.0/", "description": "" }, "9": { "name": "Special Permissions", "exists": false, "custom": true, "copyright_holder_required": true, "url": "", "description": "" } } }Note: The
descriptionfield is in the namedtuple but currently empty in the JSON. Keep it as empty string for now.Generated Output Example
Python (
le_utils/constants/licenses.py):JavaScript (
js/Licenses.js):Testing Updates
File:
tests/test_licenses.pyUpdate to test against spec:
How to Run Tests
Acceptance Criteria
spec/constants-licenses.jsoncreated with all license datamake buildsuccessfully generates Python and JavaScript filesle_utils/constants/licenses.pyhas:choicestupleLICENSELISTwith License namedtuplesjs/Licenses.jshas:LicensesListwith full license dataLicensesMapfor lookupstests/test_licenses.pyupdated to test against specresources/licenselookup.jsondeletedDisclosure
🤖 This issue was written by Claude Code, under supervision, review and final edits by @rtibbles 🤖