Skip to content

deprecate old creation functions #3976

Open

Description

@d-v-b

the create function has a few things against it:

  • it uses zarr python 2.x parameters, many of which do nothing (synchronizer, chunk_store, object_codec)
  • it has an ambiguous name. create what?
  • it is functionally superseded by the create_array function, which doesn't suffer the previously stated deficiencies

I recommend deprecating create, and deprecating the use of the create-style signature in functions that wrap it. this would entail:

  • adding a deprecation warning to the create function, indicating that it will be removed in the next minor release (3.3.0), and directing people to use create_array instead.
  • adding deprecations as needed to any of the functions that use create (I think zeros, empty, etc all use it). Upon release 3.3.0, these functions will all wrap create_array and use keyword arguments suitable for it.

Activity

  1. changed the title [-]deprecate `create`[/-] [+]deprecate old creation functions[/+] on May 14, 2026
  2. d-v-b commented on May 14, 2026

    @d-v-b
    ContributorAuthor

    I didn't realize there were so many different creation routines. In addition to create, I propose deprecating:

    @zarr-developers/python-core-devs please let me know if you or someone you know is still using any of these functions! I see no urgency for deprecating them, but I also think we are far enough from the 3.0.0 release that we can relax a bit of our 2.x compatibility layer.

  3. maxrjones commented on May 15, 2026

    @maxrjones
    Member

    There are almost certainly users of those functions, given that we were telling v2→v3 migrators to use them for the past 15 months:

    • zarr.creation deprecation warning ("import from top-level zarr namespace instead") shipped in 3.0.0 (Jan 2025) and ran across v3.0.0 → v3.1.6, which roughly 15 months of telling users to migrate to zarr.create / zarr.zeros / zarr.empty.
    • The module was actually removed in 3.2.0 (May 2026; this month).

    Therefore, we should expect these deprecations to cause user-pain. I'd prefer we make this decision in the context of the overall post-v2-migration API roadmap, so we're confident we won't identify another component that's sub-optimal after this deprecation cycle and impact users with another cycle.

  4. d-v-b commented on May 15, 2026

    @d-v-b
    ContributorAuthor

    given that many of these functions take placeholder zarr-python 2.x kwargs like synchronizer and chunk_store that we do not support and do not plan to support, I feel like we can do something to clean this up before setting up a post-v2 migration roadmap?

  5. maxrjones commented on May 15, 2026

    @maxrjones
    Member

    Yes, we could deprecate those functions without a longer plan in place. The risk of that path as mentioned in #3976 (comment) is that we deprecate users of those functions to other functions that themselves go through later deprecation cycles if we decide we're not fully satisfied with those portions of the API. To mitigate that risk without a full roadmap, we'd at least need high confidence that the preferred paths (create_array, etc.) are stable.

    More broadly, I'm advocating for considering users' long-term experience with zarr-python before starting a deprecation cycle, since each cycle causes some amount of pain. So, are you confident in the API design of create_array? Which specific functions would you recommend instead of the 12 listed in #3976 (comment)? Are you confident enough in those that we won't subject users to more churn shortly after?

    The roadmap is one mechanism for ensuring we consider the long-term experience of users. It's my preferred mechanism, but I'm open to alternatives. For instance, if the broken kwargs are the specific motivation, we could raise on those kwargs (synchronizer, chunk_store, object_codec, etc.) without deprecating the functions themselves.

  6. d-v-b commented on May 15, 2026

    @d-v-b
    ContributorAuthor

    For instance, if the broken kwargs are the specific motivation, we could raise on those kwargs (synchronizer, chunk_store, object_codec, etc.) without deprecating the functions themselves.

    That's along the lines of the second of my two proposals (the first being full deprecation):

    adding deprecations as needed to any of the functions that use create (I think zeros, empty, etc all use it). Upon release 3.3.0, these functions will all wrap create_array and use keyword arguments suitable for it.

    More broadly, I recommend reading through each of the functions I enumerated. It's a mixed bag, but there are some simple answers: some of those functions literally do nothing except raise NotImplementedError. We don't need a roadmap in place before we remove this kind of stuff. Others are weirdly storage-backend-specific in a way that's antithetical to the basic design of the library (save only targets the local file system). And others are genuinely useful for numpy compatibility (zeros and the like), but they take silly kwargs.

  7. maxrjones commented on May 15, 2026

    @maxrjones
    Member

    some of those functions literally do nothing except raise NotImplementedError. We don't need a roadmap in place before we remove this kind of stuff.

    I worry that going back on an intention to implement a feature, implied by the existing function with a NotImplementedError, a 1.5 year old issue that has promised users this functionality (#2407), and the "yet" in our own documentation, erodes the trust of less-engaged maintainers, users, and stakeholders if it isn't accompanied by communication about how we'll support that functionality in the future.

    If we had a roadmap embedded in zarr-python, we could deprecate the functions with a pointer to how we plan to support that functionality, so that we match the pain with a promise and a specific timeline. The lack of a timeline for V2 migration functionality contributed to us being in this position, so I propose we break out of that limitation.

    Each of the functions you mentioned falls into one of three categories:

    • tier 1: dead code that we never promised to deliver
    • tier 2: dead code that we promised to deliver
    • tier 3: working code with real users

    We could remove tier 1 without further planning. All others benefit from a comprehensive planning exercise. The sooner that is done, the sooner we can proceed with cleaning out the cruft in a systematic way. While the kwargs-specific changes could be exempted, I don't find that as urgent as producing a plan that would include prioritizing the most impactful cleanup or features.

  8. d-v-b commented on May 15, 2026

    @d-v-b
    ContributorAuthor

    The lack of a timeline for V2 migration functionality contributed to us being in this position, so I propose we break out of that limitation.

    I think this gives too much credit to timelines. The lack of a timeline had no power to put us in this position, it was simply a lack of execution: we did not write implementations for copy, copy_all, and copy_store. Personally I think there are good reasons for not copying these functions verbatim, and thinking a bit more about the API we want here, in part because this functionality is so important. I am 100% in favor of having a plan for adding the functionality that copy, copy_all, and copy_store served, but I also don't see why the lack of such a plan in the short term gives us any reason to keep functions that raise NotImplementedError.

  9. maxrjones commented on May 15, 2026

    @maxrjones
    Member

    The lack of a timeline for V2 migration functionality contributed to us being in this position, so I propose we break out of that limitation.

    I think this gives too much credit to timelines. The lack of a timeline had no power to put us in this position, it was simply a lack of execution: we did not write implementations for copy, copy_all, and copy_store. Personally I think there are good reasons for not copying these functions verbatim, and thinking a bit more about the API we want here, in part because this functionality is so important. I am 100% in favor of having a plan for adding the functionality that copy, copy_all, and copy_store served.

    I'm glad we're aligned on the value of a plan. Timelines matter because they force the plan to be grounded in actual resources, including developer time. A post-V2 migration plan with timelines would have made it visible early that high-importance features like the copy API weren't going to land successfully given the resources we had, which would have prompted a choice to rescope, reprioritize, or seek more help. Without timelines to surface overly optimistic parts of the plan, gaps only become visible at moments like this one, when we're considering deprecating the stubs for functions users have been asking about for 15 months. Accountability is a related benefit, but the usefulness to scoping is the relevant one to this discussion.

    I also don't see why the lack of such a plan in the short term gives us any reason to keep functions that raise NotImplementedError.

    My argument in #3976 (comment) is that our lack of a plan reduces trust/confidence across users and other stakeholders. They can't see where the library is going or when the gaps they're hitting will be addressed, only that we're active enough to clean up the API surface. Trust and confidence is what gives our library value via people/organizations using and/or investing in zarr-python, so I think it's worth weighing when making decisions like this.

  10. d-v-b commented on May 15, 2026

    @d-v-b
    ContributorAuthor

    These two things can be true:

    • copy today is worse than useless, because it takes up space in our public API but only raises NotImplementedError. Frankly it looks unserious to have dead weight like this in the public API (e.g., confidence-eroding in stakeholders), and as there are no concrete plans to fix this, we should remove it immediately.
    • We need a roadmap for store utilities like copy. We should eventually plan out a copy function that does useful stuff for users.

    I don't see how these two actions -- remove dead code, and write a roadmap -- are related. From my POV, they are both things we need to do, that don't conflict.

  11. maxrjones commented on May 15, 2026

    @maxrjones
    Member

    I agree that it was not a good design decision to include an empty stub for copy. I still want to avoid this release note: "We removed the stubs for copy", as it would not promote confidence in our execution ability. My preference would be: "We removed the stubs for copy, see <roadmap> for the implementation plan and timeline". Concretely, I think that the two components are related because deletion and communicating a plan is better than deletion with no communication about the plan. My preference for the former is predicated on our ODD team creating and getting feedback on a roadmap by July 10. That calculus could sway to deletion without a plan being better if we are not able to get the plan merged into zarr-python during that timeframe. It seems worth it to me to do the better option here that includes a plan given that this dead code has already been sitting for 15 months.

  12. maxrjones commented on Oct 17, 2026

    @maxrjones
    Member

    the discussion in #4192 inspired me to follow through on this discussion. I think this is the consensus that came out of https://github.com/zarr-developers/zarr-python-planning.

    Group 1: dead keyword arguments (remove in 3.5.0, ~Nov 2026)

    synchronizer, chunk_store, cache_metadata, cache_attrs, object_codec, read_only, meta_array from the create, group, open_group functions, which do nothing. Today they emit a ZarrRuntimeWarning saying "not yet implemented", which reads as a promise we aren't going to keep.

    • Change the warning to a ZarrDeprecationWarning saying the argument is ignored and will be removed in a release after January 2027
    • Rewrite the docstrings for these arguments to say the same
    • Update the "not ported" list in docs/user-guide/v3_migration.md
    • Remove the arguments in a release after January 2026

    No working code changes behavior.

    Group 2: the copy stubs (3.5.0 for the message, implementation per the plan)

    copy, copy_all, copy_store only raise NotImplementedError. The plan commits to implementing them in 3.x. Deleting the names now and adding them back later just creates two migrations where we need zero, so I'd rather keep the names and make the stubs honest.

    Group 3: working functions with real users

    These need replacements first.

    create, zeros, ones, empty, full and the _like variants. The numpy-style wrappers are worth keeping IMO. create is only a problem because of its signature and may be redemable.

    • 3.5.0 or 3.6.0: rewire zeros/ones/empty/full/array and friends to call create_array, translating the legacy spellings (compressor to compressors, codecs to serializer/compressors, chunk_shape to chunks, dimension_separator to chunk_key_encoding) with a ZarrDeprecationWarning on each legacy spelling only
    • Same release: deprecate create itself, pointing at create_array
    • 4.0 (or a release after 6 months): remove create and the legacy spellings

    open, open_group, open_array, open_consolidated, group. All of these are mode= under the hood. xarray calls them in five places and icechunk in over twenty, and both run their test suites with warnings as errors, so a deprecation here before a replacement exists breaks downstream CI signaling they should migrate.

    • Settle the constructor names (currently placeholders in the plan: open_for_read, create_or_overwrite, open_or_create)
    • 3.6.0 (~Jan 2027): ship the explicit constructors, additively, with no warnings anywhere
    • 3.7.0 (~Mar 2027): deprecate mode= on open/open_group/open_array, and deprecate open, open_consolidated and group in favor of the new constructors
    • 4.0: remove

    save, save_array, save_group, load. These work and are cheap to keep. Two small fixes:

    • Fix the save docstring that claims it only targets the local file system
    • Either implement load for groups (it currently raises) or document that it is array-only

    Before any Group 3 deprecation lands

    • Migrate zarr-python's own tests off the deprecated spellings (zarr.create appears 33 times, zarr.open 28, zarr.group 17; the suite runs with warnings as errors)
    • Open tracking issues in xarray and icechunk once the replacements are released, so they have a full release window before the warning appears

    Timeline summary

    Release Target What lands
    3.5.0 Nov 2026 Group 1 deprecation warnings; honest copy stub messages
    3.6.0 Jan 2027 Explicit constructors; numpy-style wrappers on create_array; create deprecated
    3.7.0 Mar 2027 mode=, open, open_consolidated, group deprecated
    4.0.0 per the v4 plan Everything above removed
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

    design discussionDiscussion about the design of the library

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions