(original) (raw)

changeset: 4481:52767ab7e140 user: Guido van Rossum guido@google.com date: Tue Jun 26 10:25:12 2012 -0700 files: pep-0423.txt description: Add PEP 423 (Naming conventions and recipes related to packaging). diff -r 8673769101b0 -r 52767ab7e140 pep-0423.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pep-0423.txt Tue Jun 26 10:25:12 2012 -0700 @@ -0,0 +1,845 @@ +PEP: 423 +Title: Naming conventions and recipes related to packaging +Version: RevisionRevisionRevision +Last-Modified: DateDateDate +Author: Benoit Bryon benoit@marmelune.net +Discussion-To: distutils-sig@python.org +Status: Draft +Type: Informational +Content-Type: text/x-rst +Created: 24-May-2012 +Post-History: + + +Abstract +======== + +This document deals with: + +* names of Python projects, +* names of Python packages or modules being distributed, +* namespace packages. + +It provides guidelines and recipes for distribution authors: + +* new projects should follow the `guidelines <#overview>`_ below. + +* existing projects should be aware of these guidelines and can follow + `specific recipes for existing projects + <#how-to-apply-naming-guidelines-on-existing-projects>`_. + + +Terminology +=========== + +Reference is `packaging terminology in Python documentation`_. + + +Relationship with other PEPs +============================ + +* `PEP 8`_ deals with code style guide, including names of Python + packages and modules. It covers syntax of package/modules names. + +* `PEP 345`_ deals with packaging metadata, and defines name argument + of the ``packaging.core.setup()`` function. + +* `PEP 420`_ deals with namespace packages. It brings support of + namespace packages to Python core. Before, namespaces packages were + implemented by external libraries. + +* `PEP 3108`_ deals with transition between Python 2.x and Python 3.x + applied to standard library: some modules to be deleted, some to be + renamed. It points out that naming conventions matter and is an + example of transition plan. + + +Overview +======== + +Here is a summarized list of guidelines you should follow to choose +names: + +* `understand and respect namespace ownership <#respect-ownership>`_. + +* if your project is related to another project or community: + + * search for conventions in main project's documentation, because + `projects should organize community contributions + <#organize-community-contributions>`_. + + * `follow specific project or related community conventions + <#follow-community-or-related-project-conventions-if-any>`_, if any. + + * if there is no convention, `follow a standard naming pattern + <#use-standard-pattern-for-community-contributions>`_. + +* make sure your project name is unique, i.e. avoid duplicates: + + * `use top-level namespace for ownership + <#top-level-namespace-relates-to-code-ownership>`_, + * `check for name availability + <#how-to-check-for-name-availability>`_, + * `register names with PyPI`_. + +* make sure distributed packages and modules names are unique, unless + you explicitely want to distribute alternatives to existing packages + or modules. `Using the same value for package/module name and + project name <#use-a-single-name>`_ is the recommended way to + achieve this. + +* `distribute only one package or module at a time + <#multiple-packages-modules-should-be-rare>`_, unless you know what + you are doing. It makes it possible to apply the "`use a single + name`_" rule, and thus make names consistent. + +* make it easy to discover and remember your project: + + * `use as much memorable names as possible + <#pick-memorable-names>`_, + * `use as much meaningful names as possible + <#pick-meaningful-names>`_, + * `use other packaging metadata <#use-packaging-metadata>`_. + +* `avoid deep nesting`_. Flat things are easier to use and remember + than nested ones: + + * one or two namespace levels are recommended, because they are + almost always enough. + * even if not recommended, three levels are, de facto, a common + case. + * in most cases, you should not need more than three levels. + +* `follow PEP 8 + <#follow-pep-8-for-syntax-of-package-and-module-names>`_ for syntax + of package and module names. + +* if you followed specific conventions, or if your project is intended + to receive contributions from the community, `organize community + contributions`_. + +* `if still in doubt, ask <#if-in-doubt-ask>`_. + + +If in doubt, ask +================ + +If you feel unsure after reading this document, ask `Python +community`_ on IRC or on a mailing list. + + +Top-level namespace relates to code ownership +============================================= + +This helps avoid clashes between project names. + +Ownership could be: + +* an individual. + Example: `gp.fileupload`_ is owned and maintained by Gael + Pasgrimaud. + +* an organization. + Examples: + + * `zest.releaser`_ is owned and maintained by Zest Software. + * `Django`_ is owned and maintained by the Django Software + Fundation. + +* a group or community. + Example: `sphinx`_ is maintained by developers of the Sphinx + project, not only by its author, Georg Brandl. + +* a group or community related to another package. + Example: `collective.recaptcha`_ is owned by its author: David + Glick, Groundwire. But the "collective" namespace is owned by Plone + community. + +Respect ownership +----------------- + +Understand the purpose of namespace before you use it. + +Don't plug into a namespace you don't own, unless explicitely +authorized. + +`If in doubt, ask`_. + +As an example, don't plug in "django.contrib" namespace because it is +managed by Django's core contributors. + +Exceptions can be defined by project authors. See `Organize community +contributions`_ below. + +Also, this rule applies to non-Python projects. + +As an example, don't use "apache" as top-level namespace: "Apache" is +the name of an existing project (in the case of "Apache", it is also a +trademark). + +Private (including closed-source) projects use a namespace +---------------------------------------------------------- + +... because private projects are owned by somebody. So apply the +`ownership rule <#top-level-namespace-relates-to-code-ownership>`_. + +For internal/customer projects, use your company name as the +namespace. + +This rule applies to closed-source projects. + +As an example, if you are creating a "climbing" project for the +"Python Sport" company: use "pythonsport.climbing" name, even if it is +closed source. + +Individual projects use a namespace +----------------------------------- + +... because they are owned by individuals. So apply the +`ownership rule <#top-level-namespace-relates-to-code-ownership>`_. + +There is no shame in releasing a project as open source even if it has +an "internal" or "individual" name. + +If the project comes to a point where the author wants to change +ownership (i.e. the project no longer belongs to an individual), keep +in mind `it is easy to rename the project +<#how-to-rename-a-project>`_. + +Community-owned projects can avoid namespace packages +----------------------------------------------------- + +If your project is generic enough (i.e. it is not a contrib to another +product or framework), you can avoid namespace packages. The base +condition is generally that your project is owned by a group (i.e. the +development team) which is dedicated to this project. + +Only use a "shared" namespace if you really intend the code to be +community owned. + +As an example, `sphinx`_ project belongs to the Sphinx development +team. There is no need to have some "sphinx" namespace package with +only one "sphinx.sphinx" project inside. + +In doubt, use an individual/organization namespace +-------------------------------------------------- + +If your project is really experimental, best choice is to use an +individual or organization namespace: + +* it allows projects to be released early. + +* it won't block a name if the project is abandoned. + +* it doesn't block future changes. When a project becomes mature and + there is no reason to keep individual ownership, `it remains + possible to rename the project <#how-to-rename-a-project>`_. + + +Use a single name +================= + +Distribute only one package (or only one module) per project, and use +package (or module) name as project name. + +* It avoids possible confusion between project name and distributed + package or module name. + +* It makes the name consistent. + +* It is explicit: when one sees project name, he guesses + package/module name, and vice versa. + +* It also limits implicit clashes between package/module names. + By using a single name, when you register a project name to `PyPI`_, + you also perform a basic package/module name availability + verification. + + As an example, `pipeline`_, `python-pipeline`_ and + `django-pipeline`_ all distribute a package or module called + "pipeline". So installing two of them leads to errors. This issue + wouldn't have occurred if these distributions used a single name. + +Yes: + +* Package name: "kheops.pyramid", + i.e. ``import kheops.pyramid`` + +* Project name: "kheops.pyramid", + i.e. ``pip install kheops.pyramid`` + +No: + +* Package name: "kheops" +* Project name: "KheopsPyramid" + +.. 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 don't need +this feature. So a distribution should provide only one package or +module at a time. + +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. So a distributed package name should be equal to project +name. + + +Follow PEP 8 for syntax of package and module names +=================================================== + +`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, +partly 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. + + +Use packaging metadata +====================== + +Consider project names as unique identifiers on PyPI: + +* it is important that these identifiers remain human-readable. +* it is even better when these identifiers are meaningful. +* but the primary purpose of identifiers is not to classify or + describe projects. + +**Classifiers and keywords metadata are made for categorization of +distributions.** Summary and description metadata are meant to +describe the project. + +As an example, there is a "`Framework :: Twisted`_" classifier. Even +if names are quite heterogeneous (they don't follow a particular +pattern), we get the list. + +In order to `Organize community contributions`_, conventions about +names and namespaces matter, but conventions about metadata should be +even more important. + +As an example, we can find Plone portlets in many places: + +* plone.portlet.* +* collective.portlet.* +* collective.portlets.* +* collective.*.portlets +* some vendor-related projects such as "quintagroup.portlet.cumulus" +* and even projects where "portlet" pattern doesn't appear in the + name. + +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. + + +Avoid deep nesting +================== + +`The Zen of Python`_ says "Flat is better than nested". + +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: "pyranha" + +Yes: "pythonsport.climbing" + +Yes: "pythonsport.forestmap" + +No: "pythonsport.maps.forest" + +Use only one level for ownership +-------------------------------- + +Don't use 3 levels to set individual/organization ownership in +a community namespace. + +As an example, let's consider: + +* you are pluging into a community namespace, such as "collective". + +* and you want to add a more restrictive "ownership" level, to avoid + clashes inside the community. + +In such a case, **you'd better use the most restrictive ownership +level as first level.** + +As an example, where "collective" is a major community namespace that +"gergovie" belongs to, and "vercingetorix" it the name of "gergovie" +author: + +No: "collective.vercingetorix.gergovie" + +Yes: "vercingetorix.gergovie" + +Don't use namespace levels for categorization +--------------------------------------------- + +`Use packaging metadata`_ instead. + +Don't use more than 3 levels +---------------------------- + +Technically, you can create deeply nested hierarchies. However, in +most cases, you shouldn't need it. + +.. note:: + + Even communities where namespaces are standard don't use more than + 3 levels. + +Conventions for communities or related projects +=============================================== + +Follow community or related project conventions, if any +------------------------------------------------------- + +Projects or related communities can have specific conventions, which +may differ from those explained in this document. + +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: + +* ``${MAINPROJECT}`` is the name of the related project. "pyranha" in + the example below. + +* ``${PROJECT}`` is the name of your project. "giantteeth" in the + example below. + +As an example: + +* you are the author of "pyranha" project. You own the "pyranha" + namespace. + +* you didn't defined specific naming conventions for community + contributions. + +* a third-party developer wants to publish a "giantteeth" project + related to your "pyranha" project in a community namespace. So he + should publish it as "pyranhacontrib.giantteeth". + +It is the simplest way to `Organize community contributions`_. + +.. note:: + + Why ``${MAINPROJECT}contrib.*`` pattern? + + * ``${MAINPROJECT}c.*`` is not explicit enough. As examples, "zc" + belongs to "Zope Corporation" whereas "z3c" belongs to "Zope 3 + community". + + * ``${MAINPROJECT}community`` is too long. + + * ``${MAINPROJECT}community`` conflicts with existing namespaces + such as "iccommunity" or "PyCommunity". + + * ``${MAINPROJECT}.contrib.*`` is inside MAINPROJECTnamespace,+i.e.itisownedby{MAINPROJECT} namespace, + i.e. it is owned by MAINPROJECTnamespace,+i.e.itisownedby{MAINPROJECT} authors. It breaks the + `Top-level namespace relates to code ownership`_ rule. + + * ``${MAINPROJECT}.contrib.*`` breaks the `Avoid deep nesting`_ + rule. + + * names where ``${MAINPROJECT}`` doesn't appear are not explicit + enough, i.e. nobody can guess they are related to + ``${MAINPROJECT}``. As an example, it is not obvious that + "collective.*" belongs to Plone community. + + * ``{$DIST}contrib.*`` looks like existing ``sphinxcontrib-*`` + packages. But ``sphinxcontrib-*`` is actually about Sphinx + contrib, so this is not a real conflict... In fact, the "contrib" + suffix was inspired by "sphinxcontrib". + +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: + +* Choose a naming convention for community contributions. + +* If it is not `the default + <#use-standard-pattern-for-community-contributions>`_, then + document it. + + * if you use the `default convention + <#use-standard-pattern-for-community-contributions>`_, then this + document should be enough. Don't reapeat it. You may reference + it. + + * else, tell users about custom conventions in project's + "contribute" or "create modules" documentation. + +* Also recommend the use of additional metadata, such as + `classifiers and keywords <#use-packaging-metadata>`_. + +About convention choices: + +* New projects should choose the `default contrib pattern + <#use-standard-pattern-for-community-contributions>`_. + +* Existing projects with community contributions should start with + custom conventions. Then they can `Promote migrations`_. + + It means that existing community conventions don't have to be + changed. But, at least, they should be explicitely documented. + +Example: "pyranha" is your project name and package name. +Tell contributors that: + +* pyranha-related distributions should use the "pyranha" keyword + +* pyranha-related distributions providing templates should also use + "templates" keyword. + +* community contributions should be released under "pyranhacontrib" + namespace (i.e. use "pyranhacontrib.*" pattern). + + +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. + + +Recipes +======= + +The following recipes will help you follow the guidelines and +conventions above. + +How to check for name availability? +----------------------------------- + +Before you choose a project name, make sure it hasn't already been +registered in the following locations: + +* `PyPI`_ +* that's all. PyPI is the only official place. + +As an example, you could also check in various locations such as +popular code hosting services, but keep in mind that PyPI is the only +place you can **register** for names in Python community. + +That's why it is important you `register names with PyPI`_. + +Also make sure the names of distributed packages or modules haven't +already been registered: + +* in the `Python Standard Library`_. + +* inside projects at `PyPI`. There is currently no helper for that. + Notice that the more projects follow the `use a single name`_ rule, + the easier is the verification. + +* you may `ask the community <#if-in-doubt-ask>`_. + +The `use a single name`_ rule also 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 keep in mind that it will cause +some confusions. So, 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: + + * packaging files, + * folder name that contains source files, + * documentation, including README, + * import statements in code. + +#. Assign ``Obsoletes-Dist`` metadata to new distribution in setup.cfg + file. See `PEP 345 about Obsolete-Dist`_ and `setup.cfg + specification`_. + +#. Release a new version of the renamed project, then publish it. + +#. Edit legacy project: + + * add dependency to new project, + * drop everything except packaging stuff, + * add the ``Development Status :: 7 - Inactive`` classifier in + setup script, + * publish a new release. + +So, users of the legacy package: + +* can continue using the legacy distributions at a deprecated version, +* can upgrade to last version of legacy distribution, which is + empty... +* ... and automatically download new distribution as a dependency of + the legacy one. + +Users who discover the legacy project see it is inactive. + +Improved handling of renamed projects on PyPI +''''''''''''''''''''''''''''''''''''''''''''' + +If many projects follow `Renaming howto <#how-to-rename-a-project>`_ +recipe, then many legacy distributions will have the following +characteristics: + +* ``Development Status :: 7 - Inactive`` classifier. +* latest version is empty, except packaging stuff. +* lastest version "redirects" to another distribution. E.g. it has a + single dependency on the renamed project. +* referenced as ``Obsoletes-Dist`` in a newer distribution. + +So it will be possible to detect renamed projects and improve +readability on PyPI. So that users can focus on active distributions. +But this feature is not required now. There is no urge. It won't be +covered in this document. + +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 mainteners for obvious reasons. + +However, project authors are invited to: + +* at least, `state about current naming`_. +* then `plan and promote migration <#promote-migrations>`_. +* optionally actually `rename existing project or distributed + packages/modules <#how-to-rename-a-project>`_. + +State about current naming +'''''''''''''''''''''''''' + +The important thing, at first, is that you state about current +choices: + +* Ask yourself "why did I choose the current name?", then document it. +* If there are differences with the guidelines provided in this + document, you should tell your users. +* If possible, create issues in the project's bugtracker, at least for + record. Then you are free to resolve them later, or maybe mark them + as "wontfix". + +Projects that are meant to receive contributions from community should +also `organize community contributions`_. + +Promote migrations +'''''''''''''''''' + +Every Python developer should migrate whenever possible, or promote +the migrations in their respective communities. + +Apply these guidelines on your projects, then the community will see +it is safe. + +In particular, "leaders" such as authors of popular projects are +influential, they have power and, thus, responsability over +communities. + +Apply these guidelines on popular projects, then communities will +adopt the conventions too. + +**Projects should promote migrations when they release a new (major) +version**, particularly `if this version introduces support for +Python 3.x, new standard library's packaging or namespace packages +<#opportunity>`_. + +Opportunity +''''''''''' + +As of Python 3.3 being developed: + +* many projects are not Python 3.x compatible. It includes "big" + products or frameworks. It means that many projects will have to do + a migration to support Python 3.x. + +* packaging (aka distutils2) is on the starting blocks. When it is + released, projects will be invited to migrate and use new packaging. + +* `PEP 420`_ brings official support of namespace packages to Python. + +It means that most active projects should be about to migrate in the +next year(s) to support Python 3.x, new packaging or new namespace +packages. + +Such an opportunity is unique and won't come again soon! +So let's introduce and promote naming conventions as soon as possible +(i.e. **now**). + + +References +========== + +Additional background: + +* `Martin Aspeli's article about names`_. Some parts of this document + are quotes from this article. + +* `in development official packaging documentation`_. + +* `The Hitchhiker's Guide to Packaging`_, which has an empty + placeholder for "naming specification". + +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 345`: http://www.python.org/dev/peps/pep-0345/ +.. _`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/ +.. _`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 345 about Obsolete-Dist`: + http://www.python.org/dev/peps/pep-0345/#obsoletes-dist-multiple-use +.. _`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: /distutils-sig@python.org/benoit@marmelune.net/guido@google.com