[Python-Dev] PEP 423 : naming conventions and recipes related to packaging (original) (raw)

Benoît Bryon benoit at marmelune.net
Fri Jul 5 09:38:36 CEST 2013


Hi!

Attached is a an updated proposal for PEP 423. You can also find it online at https://gist.github.com/benoitbryon/2815051

I am attending at EuroPython 2013 in Florence. Isn't it a great opportunity to get feedback and discuss about a PEP? I registered an open-space session and a lightning-talk today!

Some notes about the update...

The main point that was discussed in the previous proposal was the "top-level namespace relates to code ownership rule". Here is a quote from Antoine Pitrou:

Le 27/06/2012 12:50, Antoine Pitrou a écrit :

On Wed, 27 Jun 2012 11:08:45 +0200 Benoît Bryon<benoit at marmelune.net> wrote:

Hi,

Here is an informational PEP proposal: http://hg.python.org/peps/file/52767ab7e140/pep-0423.txt Could you review it for style, consistency and content? There is one Zen principle this PEP is missing: Flat is better than nested. This PEP seems to promote the practice of having a top-level namespace denote ownership. I think it should do the reverse: promote meaningful top-level packages (e.g. "sphinx") as standard practice, and allow an exception for when a piece of software is part of a larger organizational body.

So, the main change in the proposal I'm sending today is the removal of this "ownership" rule. It has been replaced by "Use a single namespace (except special cases)".

Some additional changes have been performed, such as removal of some sections about "opportunity" or "promote migrations". I also added a "Rationale" section where I pointed out some issues related to naming.

The PEP has been marked as "deferred" because it was inactive and it is partly related to PEP 426. I left this deferred state.

I am aware that some links in the PEP are broken... I will fix them later. My very first motivation is to get feedback about the "big" changes in the PEP. I wanted the update to be sent before EuroPython-2013's open-space session. I guess a detailed review would be nice anyway, for links, style, grammar...

Also, I wonder whether the PEP could be shortened or not. Sometimes I cannot find straightforward words to explain things, so perhaps someone with better skills in english language could help. Or maybe some parts, such as the "How to rename a project" section, could be moved in other documents.

Regards,

Benoît -------------- next part -------------- PEP: 423 Title: Naming conventions and recipes related to packaging Version: RevisionRevisionRevision Last-Modified: DateDateDate Author: Benoît Bryon <benoit at marmelune.net> Discussions-To: <distutils-sig at python.org> Status: Deferred Type: Informational Content-Type: text/x-rst Created: 24-May-2012 Post-History: 5-Jul-2013

Abstract

This document deals with:

It provides guidelines and recipes for distribution authors:

PEP Deferral

Further consideration of this PEP has been deferred at least until after PEP 426 (package metadata 2.0) and related updates have been resolved.

Rationale: issues related to names

For a long time, there have been no official reference on the "how to choose names" topic in the Python community. As a consequence, the Python package index (PyPI_) contains many naming patterns.

The fact is that this heterogeneity causes some issues. Some of them are described below.

.. note:: Examples were taken on July 2013.

Naming things is a hard task, and naming Python projects or packages is not an exception. The purpose of this PEP is to help project authors to avoid common traps about naming, and focus on valuable things.

Clashes

Projects names are unique on PyPI_. But names of distributed things (packages, modules) are not. And there are clashes.

As an example, "pysendfile" and "django-sendfile" projects both distribute a "sendfile" package. Users cannot use both in an environment.

Deep nested hierarchies

Deep nested namespaces mean deep nested hierarchies. It obfuscates valuable project contents.

As an example, with "plone.app.content" you get a deeply nested directory hierarchy:

.. code:: text

plone/ └── app/    └── command/ └── ... valuable code is here...

Whereas, with flat packages like "sphinx", you have valuable code near the top-level directory:

.. code:: text

sphinx/ └── ... valuable code is here...

Unrelated namespaces

When project names are made of nested namespaces, and these namespaces are not strongly related, then there is confusion.

As an example, it is not obvious that "zc.rst2" project is a general Python project, not tied to "zc" (Zope Corporation), but related to docutils' reStructuredText. As a consequence, some users discard "zc.rst2" project, because they think it is specific to "zc".

This issue occurs with branded namespaces, i.e. when top-level namespace relates to an organization and various projects are put into this namespace.

This issue also occurs when namespaces are used for categorization.

Inconsistent names

When project and distributed packages do not share a single name, users have to think when they use names (install project or import package).

As an example, which package does "django-pipeline" project distributes? Is it "djangopipeline", "django_pipeline" or "pipeline"? The answer is not obvious and the pattern varies depending on project. Users have to remember or search for the name to use.

There is no obvious bijection between project name and package/module name. It means that a user have to remember at least two names (project and package) whereas one could be enough.

This fact is a cause of clashes, because when you register a project name on PyPI_, you have no idea about package name clashes, because package names are not predictable.

Terminology

Reference of terminology used in this PEP is packaging terminology in Python documentation_.

Relationship with other PEPs

Overview

Here is a summarized list of recommendations for you to choose names:

If in doubt, ask

If you feel unsure after reading this document, ask Python community_ on IRC or on a mailing list.

Understand and respect namespace ownership

On PyPI_, all projects are put at index root. There is no owner or user level. PyPI cannot host two projects with the exact same name, even if owners are different. One name relies to one project, which relies to one ownership.

.. note:: A project's ownership can be hold by several users.

The top-level namespace relates to ownership. As an example, Django_ is owned and maintained by the Django Software Fundation.

Understand the purpose of namespace before you use it.

Do not plug into a namespace you do not own, unless explicitely authorized. If in doubt, ask_. As an example, do not plug in "django.contrib" namespace because it is managed by Django's core contributors.

Project owners may define exceptions. See Organize community contributions_ below. As an example, flask_ project explicitely invites contributors to release projects in "flask.ext" namespace.

Also, whenever possible, try to consider non-Python projects. As an example, you should not use "apache" as top-level namespace: "Apache" is the name of another (non Python) project. This is more an advice than a strict rule, but it could help identify your project on the internet or prevent some trademark issues.

Private projects may use a namespace

For internal/customer projects, feel free to use the company or main project name as the namespace. But keep in mind that, if a project is general purpose (i.e. not specific to your company or to some main project), then one level should be enough.

This rule applies to closed-source projects.

As an example, if you are creating a "climbing" project that is specific to the "Python Sport" company: you may use "pythonsport.climbing" name, even if it is closed source.

Use a single name

Distribute only one package (or only one module) per project, and use package (or module) name as project name.

Example:

.. note::

For historical reasons, PyPI_ contains many distributions where project and distributed package/module names differ.

Multiple packages/modules should be rare

Technically, Python distributions can provide multiple packages and/or modules. See setup script reference_ for details.

Some distributions actually do. As an example, setuptools_ and distribute_ are both declaring "pkg_resources", "easy_install" and "site" modules in addition to respective "setuptools" and "distribute" packages.

Consider this use case as exceptional. In most cases, you do not need this feature and distributing a single package or module is enough.

Distinct names should be rare

A notable exception to the Use a single name_ rule is when you explicitely need distinct names.

As an example, the Pillow_ project provides an alternative to the original PIL_ distribution. Both projects distribute a "PIL" package.

Consider this use case as exceptional. In most cases, you don't need this feature and naming the project after the distributed package/module is enough.

Follow PEP 8

PEP 8_ applies to names of Python packages and modules.

If you Use a single name, PEP 8 also applies to project names. The exceptions are namespace packages, where dots are required in project name.

Pick memorable names

One important thing about a project name is that it be memorable.

As an example, celery_ is not a meaningful name. At first, it is not obvious that it deals with message queuing. But it is memorable because it can be used to feed a RabbitMQ_ server.

Pick meaningful names

Ask yourself "how would I describe in one sentence what this name is for?", and then "could anyone have guessed that by looking at the name?".

As an example, DateUtils_ is a meaningful name. It is obvious that it deals with utilities for dates.

When you are using namespaces, try to make each part meaningful.

.. note::

Sometimes, you cannot find a name that is both memorable and meaningful. In such a situation, consider "memorable" feature is more important than "meaningful" one. Generally, by choosing a memorable name, you tend to make the name unique, and simplicity is a key of success. Whereas a meaningful name tend to be similar to names of other projects that deal with same concepts, and you tend make the name out of keywords/buzzwords.

Use packaging metadata

Consider that project names are unique identifiers on PyPI, i.e. their primary purpose is to identify, not to classify or describe.

Classifiers and keywords metadata are made for categorization. Summary and description metadata are meant to describe the project.

As an example, there is a "Framework :: Twisted_" classifier. Names of projects that have this classifier are quite heterogeneous. They do not follow a particular pattern to claim relation with Twisted. But we get the list using the classifier and that is fine.

In order to Organize community contributions_, conventions about names and namespaces matter, but conventions about metadata are important too.

As an example, we can find Plone portlets in many places:

Even if Plone community has conventions, using the name to categorize distributions is inapropriate. It's impossible to get the full list of distributions that provide portlets for Plone by filtering on names. But it would be possible if all these distributions used "Framework :: Plone" classifier and "portlet" keyword.

When you release a project on PyPI_, you obviously want your project to be visible, and findable. Keep in mind that the name is not the only mean to make a project discoverable. If you do care about your project's visibility, take care of package metadata: including keywords, classifiers, README... And you may also take care of project's documentation and some stuff not related to packaging.

Avoid deep nesting

The Zen of Python_ says:

Flat is better than nested.

In most cases, one level is enough. So, unless you are in a special situation mentioned below, your project name should be made of a single namespace.

Lower levels indicate strict relationship to upper levels

In nested namespaces, lower levels point out strict relationship to higher ones. It means the second level is specific to the first one.

Main use cases are community contributions related to one project and vendor specific (mostly private) projects.

Two levels is almost always enough

Don't define everything in deeply nested hierarchies: you will end up with projects and packages like "pythonsport.common.maps.forest". This type of name is both verbose and cumbersome (e.g. if you have many imports from the package).

Furthermore, big hierarchies tend to break down over time as the boundaries between different packages blur.

The consensus is that two levels of nesting are preferred.

For example, we have plone.principalsource instead of plone.source.principal or something like that. The name is shorter, the package structure is simpler, and there would be very little to gain from having three levels of nesting here. It would be impractical to try to put all "core Plone" sources (a source is kind of vocabulary) into the plone.source.* namespace, in part because some sources are part of other packages, and in part because sources already exist in other places. Had we made a new namespace, it would be inconsistently used from the start.

Yes: "pythonsport.climbing"

Yes: "pythonsport.forestmap"

No: "pythonsport.maps.forest"

Do not use namespace levels for categorization

Use packaging metadata_ instead.

Don't use more than 3 levels

Technically, you have the ability to create deeply nested hierarchies. However, it is strongly discouraged.

Document specific naming policy

A project that does not follow this PEP's recommendations should mention and explain it in documentation.

This rule is the simplest way to make an existing project comply with this PEP, without a rename.

Follow community or related project conventions, if any

Projects or related communities can have specific naming conventions, which may differ from those explained in this document. Specific conventions override this PEP.

This rule exists for backward-compatibility purpose: new projects should follow this PEP's conventions.

In such a case, they should declare specific conventions in documentation <#organize-community-contributions>_.

So, if your project belongs to another project or to a community, first look for specific conventions in main project's documentation.

If there is no specific conventions, follow the ones declared in this document.

As an example, Plone community_ releases community contributions in the "collective" namespace package. It differs from the standard namespace for contributions <#use-standard-pattern-for-community-contributions>_ proposed here. But since it is documented, there is no ambiguity and you should follow this specific convention.

Use standard pattern for community contributions

When no specific rule is defined, use the {MAINPROJECT}contrib.{PROJECT} pattern to store community contributions for any product or framework, where:

As an example:

It is the simplest way to Organize community contributions_.

.. note::

Why {MAINPROJECT}contrib.* pattern?

Organize community contributions

This is the counterpart of the follow community conventions <#follow-community-or-related-project-conventions-if-any>_ and standard pattern for contributions <#use-standard-pattern-for-community-contributions>_ rules.

Actions:

Example: "pyranha" is your project name and package name. Tell contributors that:

Register names with PyPI

PyPI_ is the central place for distributions in Python community. So, it is also the place where to register project and package names.

See Registering with the Package Index_ for details.

Check for name availability

Make sure it project name has not already been registered on PyPI_.

.. note::

PyPI_ is the only official place where to register names.

Also make sure the names of distributed packages or modules have not already been registered:

.. note::

The use a single name_ rule helps you avoid clashes with package names: if a project name is available, then the package name has good chances to be available too.

How to rename a project?

Renaming a project is possible, but it should be done with care. Pay particular attention to README and documentation, so that users understand what happened.

#. First of all, do not remove legacy distributions from PyPI. Because some users may be using them.

#. Copy the legacy project, then change names (project and package/module). Pay attention to, at least:

#. Assign obsoleted_by metadata to new distribution in setup.cfg file. See PEP 426 about obsoleted_by_ and setup.cfg specification_.

#. Release a new version of the renamed project, then publish it.

#. Edit legacy project:

So, users of the legacy package:

Users who discover the legacy project see it is inactive.

How to apply naming guidelines on existing projects?

There is no obligation for existing projects to be renamed. The choice is left to project authors and maintainers for obvious reasons.

However, project authors are invited to:

Projects that are meant to receive contributions from community should also organize community contributions_.

References

Additional background:

References and footnotes:

.. _packaging terminology in Python documentation: http://docs.python.org/dev/packaging/introduction.html#general-python-terminology .. _PEP 8: http://www.python.org/dev/peps/pep-0008/#package-and-module-names .. _PEP 426: http://www.python.org/dev/peps/pep-0426/ .. _PEP 420: http://www.python.org/dev/peps/pep-0420/ .. _PEP 3108: http://www.python.org/dev/peps/pep-3108/ .. _Python community: http://www.python.org/community/ .. _gp.fileupload: http://pypi.python.org/pypi/gp.fileupload/ .. _zest.releaser: http://pypi.python.org/pypi/zest.releaser/ .. _django: http://djangoproject.com/ .. _flask: http://flask.pocoo.org/ .. _sphinx: http://sphinx.pocoo.org .. _pypi: http://pypi.python.org .. _collective.recaptcha: http://pypi.python.org/pypi/collective.recaptcha/ .. _pipeline: http://pypi.python.org/pypi/pipeline/ .. _python-pipeline: http://pypi.python.org/pypi/python-pipeline/ .. _django-pipeline: http://pypi.python.org/pypi/django-pipeline/ .. _setup script reference: http://docs.python.org/dev/packaging/setupscript.html .. _setuptools: http://pypi.python.org/pypi/setuptools .. _distribute: http://packages.python.org/distribute/ .. _Pillow: http://pypi.python.org/pypi/Pillow/ .. _PIL: http://pypi.python.org/pypi/PIL/ .. _celery: http://pypi.python.org/pypi/celery/ .. _RabbitMQ: http://www.rabbitmq.com .. _DateUtils: http://pypi.python.org/pypi/DateUtils/ .. _Framework :: Twisted: http://pypi.python.org/pypi?:action=browse&show=all&c=525 .. _The Zen of Python: http://www.python.org/dev/peps/pep-0020/ .. _Plone community: http://plone.org/community/develop .. _Registering with the Package Index: http://docs.python.org/dev/packaging/packageindex.html .. _Python Standard Library: http://docs.python.org/library/index.html .. _PEP 426 about obsoleted_by: http://www.python.org/dev/peps/pep-0426/#obsoleted-by .. _setup.cfg specification: http://docs.python.org/dev/packaging/setupcfg.html .. _Martin Aspeli's article about names: http://www.martinaspeli.net/articles/the-naming-of-things-package-names-and-namespaces .. _in development official packaging documentation: http://docs.python.org/dev/packaging/ .. _The Hitchhiker's Guide to Packaging: http://guide.python-distribute.org/specification.html#naming-specification

Copyright

This document has been placed in the public domain.

.. Local Variables: mode: indented-text indent-tabs-mode: nil sentence-end-double-space: t fill-column: 70 coding: utf-8 End:



More information about the Python-Dev mailing list