Skip to content

create_package() writes a package descriptor that frictionless cannot read back #165

Description

@jinskeep-morpc

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions