Summary
morpc.frictionless.create_package() writes a *.package.yaml that frictionless.Package() refuses to load. The descriptor it produces violates the Data Package spec in two independent ways, so a package this library writes cannot be read back by the library it is built on.
Noticed while adding prepare_release()/create_release() in #164 (v0.5.15) — prepare_release() calls create_package(), and a test that round-tripped the resulting package through frictionless.Package(path) failed. The test now parses the YAML directly as a workaround, and the limitation is recorded in the v0.5.15 release notes.
Reproduction
import frictionless, morpc.frictionless as mf
open("data.csv", "wb").write(b"id,name\r\n1,alice\r\n")
open("data.schema.yaml", "w").write("fields:\n - name: id\n type: integer\n - name: name\n type: string\n")
mf.create_resource("data.csv", resourcePath="data.resource.yaml", schemaPath="data.schema.yaml",
name="parcels", writeResource=True)
mf.create_package(dir=".", resources=["data.resource.yaml"], name="bundle", version="2026.7.30")
frictionless.Package("bundle.package.yaml") # raises
What gets written:
name: bundle
version: 2026.7.30
created: 2026-07-30 09:17:49.773407
resources:
- data.resource.yaml
What happens on read:
FrictionlessException: [package-error] The data package has an error: descriptor is not valid
(datetime.datetime(2026, 7, 30, 9, 17, 49, 773407) is not of type 'string' at property 'created')
('data.resource.yaml' is not of type 'object' at property 'resources/0')
Package.validate() fails identically, so the descriptor cannot be validated either.
Two separate causes
1. created is a datetime object, not a string. create_package() passes created=datetime.datetime.now(), and frictionless serializes it through to the descriptor unchanged. The spec requires an RFC3339 string. datetime.datetime.now().isoformat() fixes this one outright.
2. resources/0 is a path string, not a resource object. This is frictionless's own behavior, not a line in our code: a Resource constructed from a descriptor path remembers that path, and Package.to_dict() then serializes it by reference rather than inlining the resource. Confirmed independent of cause 1 — with created corrected, from_descriptor still rejects resources/0:
r = frictionless.Resource("data.resource.yaml") # .path == "data.csv", .name == "parcels"
p = frictionless.Package(name="bundle", resources=[r], created="2026-07-30T09:18:05", version="1")
p.to_dict() # {'resources': ['data.resource.yaml'], ...} <- reference, not object
Fixing this means inlining each resource's descriptor (e.g. building the package from frictionless.Resource.from_descriptor(path).to_dict()) rather than from path-constructed Resource objects.
Tradeoff worth deciding before fixing
The path-reference form is what every package this library has ever written looks like, including the ones published as release assets — morpc-addresspoints-standardize.package.yaml is resources: [morpc-addresspoints-standardize.resource.yaml]. Inlining resources changes the emitted format, so anything that reads these packages expecting a list of sidecar paths would need to change too. Worth deciding deliberately whether to:
- inline the resources (spec-correct, readable by
frictionless.Package, changes the published format); or
- keep path references and document that these descriptors are a MORPC convention rather than valid Data Packages, fixing only
created.
Fixing created alone is safe and strictly an improvement either way.
Impact
Low urgency — nothing in the library reads these packages back today, which is why this went unnoticed. It matters for consumers: a package published as a release asset cannot be opened with frictionless.Package(), so the package descriptor is currently documentation rather than something machine-readable.
Environment
frictionless 5.19.0, morpc 0.5.15, Python 3.12.
🤖 Generated with Claude Code
Summary
morpc.frictionless.create_package()writes a*.package.yamlthatfrictionless.Package()refuses to load. The descriptor it produces violates the Data Package spec in two independent ways, so a package this library writes cannot be read back by the library it is built on.Noticed while adding
prepare_release()/create_release()in #164 (v0.5.15) —prepare_release()callscreate_package(), and a test that round-tripped the resulting package throughfrictionless.Package(path)failed. The test now parses the YAML directly as a workaround, and the limitation is recorded in the v0.5.15 release notes.Reproduction
What gets written:
What happens on read:
Package.validate()fails identically, so the descriptor cannot be validated either.Two separate causes
1.
createdis a datetime object, not a string.create_package()passescreated=datetime.datetime.now(), and frictionless serializes it through to the descriptor unchanged. The spec requires an RFC3339 string.datetime.datetime.now().isoformat()fixes this one outright.2.
resources/0is a path string, not a resource object. This is frictionless's own behavior, not a line in our code: aResourceconstructed from a descriptor path remembers that path, andPackage.to_dict()then serializes it by reference rather than inlining the resource. Confirmed independent of cause 1 — withcreatedcorrected,from_descriptorstill rejectsresources/0:Fixing this means inlining each resource's descriptor (e.g. building the package from
frictionless.Resource.from_descriptor(path).to_dict()) rather than from path-constructedResourceobjects.Tradeoff worth deciding before fixing
The path-reference form is what every package this library has ever written looks like, including the ones published as release assets —
morpc-addresspoints-standardize.package.yamlisresources: [morpc-addresspoints-standardize.resource.yaml]. Inlining resources changes the emitted format, so anything that reads these packages expecting a list of sidecar paths would need to change too. Worth deciding deliberately whether to:frictionless.Package, changes the published format); orcreated.Fixing
createdalone is safe and strictly an improvement either way.Impact
Low urgency — nothing in the library reads these packages back today, which is why this went unnoticed. It matters for consumers: a package published as a release asset cannot be opened with
frictionless.Package(), so the package descriptor is currently documentation rather than something machine-readable.Environment
frictionless 5.19.0, morpc 0.5.15, Python 3.12.
🤖 Generated with Claude Code