summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/Makefile153
-rw-r--r--docs/_static/.empty0
-rw-r--r--docs/changelog.rst1
-rw-r--r--docs/conf.py111
-rw-r--r--docs/development/getting-started.rst77
-rw-r--r--docs/development/index.rst19
-rw-r--r--docs/development/release-process.rst25
-rw-r--r--docs/development/reviewing-patches.rst37
-rw-r--r--docs/development/submitting-patches.rst74
-rw-r--r--docs/index.rst38
-rw-r--r--docs/markers.rst93
-rw-r--r--docs/requirements.rst89
-rw-r--r--docs/requirements.txt1
-rw-r--r--docs/security.rst18
-rw-r--r--docs/specifiers.rst222
-rw-r--r--docs/tags.rst225
-rw-r--r--docs/utils.rst92
-rw-r--r--docs/version.rst292
18 files changed, 1567 insertions, 0 deletions
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 0000000..9d683b4
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,153 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = _build
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " texinfo to make Texinfo files"
+ @echo " info to make Texinfo files and run them through makeinfo"
+ @echo " gettext to make PO message catalogs"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ -rm -rf $(BUILDDIR)/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/packaging.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/packaging.qhc"
+
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/packaging"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/packaging"
+ @echo "# devhelp"
+
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo
+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+ @echo "Run \`make' in that directory to run these through makeinfo" \
+ "(use \`make info' here to do that automatically)."
+
+info:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo "Running Texinfo files through makeinfo..."
+ make -C $(BUILDDIR)/texinfo info
+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+ @echo
+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/docs/_static/.empty b/docs/_static/.empty
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/docs/_static/.empty
diff --git a/docs/changelog.rst b/docs/changelog.rst
new file mode 100644
index 0000000..565b052
--- /dev/null
+++ b/docs/changelog.rst
@@ -0,0 +1 @@
+.. include:: ../CHANGELOG.rst
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644
index 0000000..edd8dd5
--- /dev/null
+++ b/docs/conf.py
@@ -0,0 +1,111 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+import os
+import sys
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+sys.path.insert(0, os.path.abspath("."))
+
+# -- General configuration ----------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = [
+ "sphinx.ext.autodoc",
+ "sphinx.ext.doctest",
+ "sphinx.ext.extlinks",
+ "sphinx.ext.intersphinx",
+ "sphinx.ext.viewcode",
+]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ["_templates"]
+
+# The suffix of source filenames.
+source_suffix = ".rst"
+
+# The master toctree document.
+master_doc = "index"
+
+# General information about the project.
+project = "Packaging"
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+
+base_dir = os.path.join(os.path.dirname(__file__), os.pardir)
+about = {}
+with open(os.path.join(base_dir, "packaging", "__about__.py")) as f:
+ exec(f.read(), about)
+
+version = release = about["__version__"]
+copyright = about["__copyright__"]
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ["_build"]
+
+extlinks = {
+ "issue": ("https://github.com/pypa/packaging/issues/%s", "#"),
+ "pull": ("https://github.com/pypa/packaging/pull/%s", "PR #"),
+}
+# -- Options for HTML output --------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+
+html_theme = "furo"
+html_title = "packaging"
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ["_static"]
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = "packagingdoc"
+
+
+# -- Options for LaTeX output -------------------------------------------------
+
+latex_elements = {}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual])
+latex_documents = [
+ ("index", "packaging.tex", "Packaging Documentation", "Donald Stufft", "manual")
+]
+
+# -- Options for manual page output -------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [("index", "packaging", "Packaging Documentation", ["Donald Stufft"], 1)]
+
+# -- Options for Texinfo output -----------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ (
+ "index",
+ "packaging",
+ "Packaging Documentation",
+ "Donald Stufft",
+ "packaging",
+ "Core utilities for Python packages",
+ "Miscellaneous",
+ )
+]
+
+# Example configuration for intersphinx: refer to the Python standard library.
+intersphinx_mapping = {"https://docs.python.org/": None}
+
+epub_theme = "epub"
diff --git a/docs/development/getting-started.rst b/docs/development/getting-started.rst
new file mode 100644
index 0000000..8bd42ac
--- /dev/null
+++ b/docs/development/getting-started.rst
@@ -0,0 +1,77 @@
+Getting started
+===============
+
+Working on packaging requires the installation of a small number of
+development dependencies. To see what dependencies are required to
+run the tests manually, please look at the ``noxfile.py`` file.
+
+Running tests
+~~~~~~~~~~~~~
+
+The packaging unit tests are found in the ``tests/`` directory and are
+designed to be run using `pytest`_. `pytest`_ will discover the tests
+automatically, so all you have to do is:
+
+.. code-block:: console
+
+ $ python -m pytest
+ ...
+ 29204 passed, 4 skipped, 1 xfailed in 83.98 seconds
+
+This runs the tests with the default Python interpreter. This also allows
+you to run select tests instead of the entire test suite.
+
+You can also verify that the tests pass on other supported Python interpreters.
+For this we use `nox`_, which will automatically create a `virtualenv`_ for
+each supported Python version and run the tests. For example:
+
+.. code-block:: console
+
+ $ nox -s tests
+ ...
+ nox > Ran multiple sessions:
+ nox > * tests-3.6: success
+ nox > * tests-3.7: success
+ nox > * tests-3.8: success
+ nox > * tests-3.9: success
+ nox > * tests-pypy3: skipped
+
+You may not have all the required Python versions installed, in which case you
+will see one or more ``InterpreterNotFound`` errors.
+
+Running linters
+~~~~~~~~~~~~~~~
+
+If you wish to run the linting rules, you may use `pre-commit`_ or run
+``nox -s lint``.
+
+.. code-block:: console
+
+ $ nox -s lint
+ ...
+ nox > Session lint was successful.
+
+Building documentation
+~~~~~~~~~~~~~~~~~~~~~~
+
+packaging documentation is stored in the ``docs/`` directory. It is
+written in `reStructured Text`_ and rendered using `Sphinx`_.
+
+Use `nox`_ to build the documentation. For example:
+
+.. code-block:: console
+
+ $ nox -s docs
+ ...
+ nox > Session docs was successful.
+
+The HTML documentation index can now be found at
+``docs/_build/html/index.html``.
+
+.. _`pytest`: https://pypi.org/project/pytest/
+.. _`nox`: https://pypi.org/project/nox/
+.. _`virtualenv`: https://pypi.org/project/virtualenv/
+.. _`pip`: https://pypi.org/project/pip/
+.. _`sphinx`: https://pypi.org/project/Sphinx/
+.. _`reStructured Text`: http://sphinx-doc.org/rest.html
+.. _`pre-commit`: https://pre-commit.com
diff --git a/docs/development/index.rst b/docs/development/index.rst
new file mode 100644
index 0000000..c0aea8a
--- /dev/null
+++ b/docs/development/index.rst
@@ -0,0 +1,19 @@
+Development
+===========
+
+As an open source project, packaging welcomes contributions of all
+forms. The sections below will help you get started.
+
+File bugs and feature requests on our issue tracker on `GitHub`_. If it is a
+bug check out `what to put in your bug report`_.
+
+.. toctree::
+ :maxdepth: 2
+
+ getting-started
+ submitting-patches
+ reviewing-patches
+ release-process
+
+.. _`GitHub`: https://github.com/pypa/packaging
+.. _`what to put in your bug report`: http://www.contribution-guide.org/#what-to-put-in-your-bug-report
diff --git a/docs/development/release-process.rst b/docs/development/release-process.rst
new file mode 100644
index 0000000..84e5bec
--- /dev/null
+++ b/docs/development/release-process.rst
@@ -0,0 +1,25 @@
+Release Process
+===============
+
+#. Checkout the current ``main`` branch.
+#. Install the latest ``nox``::
+
+ $ pip install nox
+
+#. Run the release automation with the required version number (YY.N)::
+
+ $ nox -s release -- YY.N
+
+ You will need the password for your GPG key as well as an API token for PyPI.
+
+#. Add a `release on GitHub <https://github.com/pypa/packaging/releases>`__.
+
+#. Notify the other project owners of the release.
+
+.. note::
+
+ Access needed for making the release are:
+
+ - PyPI maintainer (or owner) access to ``packaging``
+ - push directly to the ``main`` branch on the source repository
+ - push tags directly to the source repository
diff --git a/docs/development/reviewing-patches.rst b/docs/development/reviewing-patches.rst
new file mode 100644
index 0000000..c476c75
--- /dev/null
+++ b/docs/development/reviewing-patches.rst
@@ -0,0 +1,37 @@
+Reviewing and merging patches
+=============================
+
+Everyone is encouraged to review open pull requests. We only ask that you try
+and think carefully, ask questions and are `excellent to one another`_. Code
+review is our opportunity to share knowledge, design ideas and make friends.
+
+When reviewing a patch try to keep each of these concepts in mind:
+
+Architecture
+------------
+
+* Is the proposed change being made in the correct place?
+
+Intent
+------
+
+* What is the change being proposed?
+* Do we want this feature or is the bug they're fixing really a bug?
+
+Implementation
+--------------
+
+* Does the change do what the author claims?
+* Are there sufficient tests?
+* Has it been documented?
+* Will this change introduce new bugs?
+
+Grammar and style
+-----------------
+
+These are small things that are not caught by the automated style checkers.
+
+* Does a variable need a better name?
+* Should this be a keyword argument?
+
+.. _`excellent to one another`: https://speakerdeck.com/ohrite/better-code-review
diff --git a/docs/development/submitting-patches.rst b/docs/development/submitting-patches.rst
new file mode 100644
index 0000000..fbdb5a4
--- /dev/null
+++ b/docs/development/submitting-patches.rst
@@ -0,0 +1,74 @@
+Submitting patches
+==================
+
+* Always make a new branch for your work.
+* Patches should be small to facilitate easier review. `Studies have shown`_
+ that review quality falls off as patch size grows. Sometimes this will result
+ in many small PRs to land a single large feature.
+* Larger changes should be discussed in a ticket before submission.
+* New features and significant bug fixes should be documented in the
+ :doc:`/changelog`.
+* You must have legal permission to distribute any code you contribute and it
+ must be available under both the BSD and Apache Software License Version 2.0
+ licenses.
+
+If you believe you've identified a security issue in packaging, please
+follow the directions on the :doc:`security page </security>`.
+
+Code
+----
+
+This project's source is auto-formatted with |black|. You can check if your
+code meets our requirements by running our linters against it with ``nox -s
+lint`` or ``pre-commit run --all-files``.
+
+`Write comments as complete sentences.`_
+
+Every code file must start with the boilerplate licensing notice:
+
+.. code-block:: python
+
+ # This file is dual licensed under the terms of the Apache License, Version
+ # 2.0, and the BSD License. See the LICENSE file in the root of this repository
+ # for complete details.
+
+Tests
+-----
+
+All code changes must be accompanied by unit tests with 100% code coverage (as
+measured by the combined metrics across our build matrix).
+
+
+Documentation
+-------------
+
+All features should be documented with prose in the ``docs`` section.
+
+When referring to a hypothetical individual (such as "a person receiving an
+encrypted message") use gender neutral pronouns (they/them/their).
+
+Docstrings are typically only used when writing abstract classes, but should
+be written like this if required:
+
+.. code-block:: python
+
+ def some_function(some_arg):
+ """
+ Does some things.
+
+ :param some_arg: Some argument.
+ """
+
+So, specifically:
+
+* Always use three double quotes.
+* Put the three double quotes on their own line.
+* No blank line at the end.
+* Use Sphinx parameter/attribute documentation `syntax`_.
+
+
+.. |black| replace:: ``black``
+.. _black: https://pypi.org/project/black/
+.. _`Write comments as complete sentences.`: https://nedbatchelder.com/blog/201401/comments_should_be_sentences.html
+.. _`syntax`: http://sphinx-doc.org/domains.html#info-field-lists
+.. _`Studies have shown`: http://www.ibm.com/developerworks/rational/library/11-proven-practices-for-peer-review/
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644
index 0000000..aafdae8
--- /dev/null
+++ b/docs/index.rst
@@ -0,0 +1,38 @@
+Welcome to packaging
+====================
+
+.. include:: ../README.rst
+ :start-after: start-intro
+ :end-before: end-intro
+
+
+Installation
+------------
+
+You can install packaging with ``pip``:
+
+.. code-block:: console
+
+ $ pip install packaging
+
+
+.. toctree::
+ :maxdepth: 1
+ :caption: API Documentation
+ :hidden:
+
+ version
+ specifiers
+ markers
+ requirements
+ tags
+ utils
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Project
+ :hidden:
+
+ development/index
+ security
+ changelog
diff --git a/docs/markers.rst b/docs/markers.rst
new file mode 100644
index 0000000..ad25361
--- /dev/null
+++ b/docs/markers.rst
@@ -0,0 +1,93 @@
+Markers
+=======
+
+.. currentmodule:: packaging.markers
+
+One extra requirement of dealing with dependencies is the ability to specify
+if it is required depending on the operating system or Python version in use.
+`PEP 508`_ defines the scheme which has been implemented by this module.
+
+Usage
+-----
+
+.. doctest::
+
+ >>> from packaging.markers import Marker, UndefinedEnvironmentName
+ >>> marker = Marker("python_version>'2'")
+ >>> marker
+ <Marker('python_version > "2"')>
+ >>> # We can evaluate the marker to see if it is satisfied
+ >>> marker.evaluate()
+ True
+ >>> # We can also override the environment
+ >>> env = {'python_version': '1.5.4'}
+ >>> marker.evaluate(environment=env)
+ False
+ >>> # Multiple markers can be ANDed
+ >>> and_marker = Marker("os_name=='a' and os_name=='b'")
+ >>> and_marker
+ <Marker('os_name == "a" and os_name == "b"')>
+ >>> # Multiple markers can be ORed
+ >>> or_marker = Marker("os_name=='a' or os_name=='b'")
+ >>> or_marker
+ <Marker('os_name == "a" or os_name == "b"')>
+ >>> # Markers can be also used with extras, to pull in dependencies if
+ >>> # a certain extra is being installed
+ >>> extra = Marker('extra == "bar"')
+ >>> # Evaluating an extra marker with no environment is an error
+ >>> try:
+ ... extra.evaluate()
+ ... except UndefinedEnvironmentName:
+ ... pass
+ >>> extra_environment = {'extra': ''}
+ >>> extra.evaluate(environment=extra_environment)
+ False
+ >>> extra_environment['extra'] = 'bar'
+ >>> extra.evaluate(environment=extra_environment)
+ True
+
+
+Reference
+---------
+
+.. class:: Marker(markers)
+
+ This class abstracts handling markers for dependencies of a project. It can
+ be passed a single marker or multiple markers that are ANDed or ORed
+ together. Each marker will be parsed according to PEP 508.
+
+ :param str markers: The string representation of a marker or markers.
+ :raises InvalidMarker: If the given ``markers`` are not parseable, then
+ this exception will be raised.
+
+ .. method:: evaluate(environment=None)
+
+ Evaluate the marker given the context of the current Python process.
+
+ :param dict environment: A dictionary containing keys and values to
+ override the detected environment.
+ :raises: UndefinedComparison: If the marker uses a PEP 440 comparison on
+ strings which are not valid PEP 440 versions.
+ :raises: UndefinedEnvironmentName: If the marker accesses a value that
+ isn't present inside of the environment
+ dictionary.
+
+.. exception:: InvalidMarker
+
+ Raised when attempting to create a :class:`Marker` with a string that
+ does not conform to PEP 508.
+
+
+.. exception:: UndefinedComparison
+
+ Raised when attempting to evaluate a :class:`Marker` with a PEP 440
+ comparison operator against values that are not valid PEP 440 versions.
+
+
+.. exception:: UndefinedEnvironmentName
+
+ Raised when attempting to evaluate a :class:`Marker` with a value that is
+ missing from the evaluation environment.
+
+
+.. _`PEP 508`: https://www.python.org/dev/peps/pep-0508/
diff --git a/docs/requirements.rst b/docs/requirements.rst
new file mode 100644
index 0000000..e7c5a85
--- /dev/null
+++ b/docs/requirements.rst
@@ -0,0 +1,89 @@
+Requirements
+============
+
+.. currentmodule:: packaging.requirements
+
+Parse a given requirements line for specifying dependencies of a Python
+project, using `PEP 508`_ which defines the scheme that has been implemented
+by this module.
+
+Usage
+-----
+
+.. doctest::
+
+ >>> from packaging.requirements import Requirement
+ >>> simple_req = Requirement("name")
+ >>> simple_req
+ <Requirement('name')>
+ >>> simple_req.name
+ 'name'
+ >>> simple_req.url is None
+ True
+ >>> simple_req.extras
+ set()
+ >>> simple_req.specifier
+ <SpecifierSet('')>
+ >>> simple_req.marker is None
+ True
+ >>> # Requirements can be specified with extras, specifiers and markers
+ >>> req = Requirement('name[foo]>=2,<3; python_version>"2.0"')
+ >>> req.name
+ 'name'
+ >>> req.extras
+ {'foo'}
+ >>> req.specifier
+ <SpecifierSet('<3,>=2')>
+ >>> req.marker
+ <Marker('python_version > "2.0"')>
+ >>> # Requirements can also be specified with a URL, but may not specify
+ >>> # a version.
+ >>> url_req = Requirement('name @ https://github.com/pypa ;os_name=="a"')
+ >>> url_req.name
+ 'name'
+ >>> url_req.url
+ 'https://github.com/pypa'
+ >>> url_req.extras
+ set()
+ >>> url_req.marker
+ <Marker('os_name == "a"')>
+
+
+Reference
+---------
+
+.. class:: Requirement(requirement)
+
+ This class abstracts handling the details of a requirement for a project.
+ Each requirement will be parsed according to PEP 508.
+
+ :param str requirement: The string representation of a requirement.
+ :raises InvalidRequirement: If the given ``requirement`` is not parseable,
+ then this exception will be raised.
+
+ .. attribute:: name
+
+ The name of the requirement.
+
+ .. attribute:: url
+
+ The URL, if any where to download the requirement from. Can be None.
+
+ .. attribute:: extras
+
+ A set of extras that the requirement specifies.
+
+ .. attribute:: specifier
+
+ A :class:`~.SpecifierSet` of the version specified by the requirement.
+
+ .. attribute:: marker
+
+ A :class:`~.Marker` of the marker for the requirement. Can be None.
+
+.. exception:: InvalidRequirement
+
+ Raised when attempting to create a :class:`Requirement` with a string that
+ does not conform to PEP 508.
+
+.. _`PEP 508`: https://www.python.org/dev/peps/pep-0508/
diff --git a/docs/requirements.txt b/docs/requirements.txt
new file mode 100644
index 0000000..a95ae18
--- /dev/null
+++ b/docs/requirements.txt
@@ -0,0 +1 @@
+furo
diff --git a/docs/security.rst b/docs/security.rst
new file mode 100644
index 0000000..f7fdb00
--- /dev/null
+++ b/docs/security.rst
@@ -0,0 +1,18 @@
+Security
+========
+
+We take the security of packaging seriously. If you believe you've identified a
+security issue in it, DO NOT report the issue in any public forum, including
+(but not limited to):
+
+- GitHub issue tracker
+- Official or unofficial chat channels
+- Official or unofficial mailing lists
+
+Please report your issue to ``security@python.org``. Messages may be optionally
+encrypted with GPG using key fingerprints available at the `Python Security
+page <https://www.python.org/news/security/>`_.
+
+Once you've submitted an issue via email, you should receive an acknowledgment
+within 48 hours, and depending on the action to be taken, you may receive
+further follow-up emails.
diff --git a/docs/specifiers.rst b/docs/specifiers.rst
new file mode 100644
index 0000000..83299a8
--- /dev/null
+++ b/docs/specifiers.rst
@@ -0,0 +1,222 @@
+Specifiers
+==========
+
+.. currentmodule:: packaging.specifiers
+
+A core requirement of dealing with dependencies is the ability to specify what
+versions of a dependency are acceptable for you. `PEP 440`_ defines the
+standard specifier scheme which has been implemented by this module.
+
+Usage
+-----
+
+.. doctest::
+
+ >>> from packaging.specifiers import SpecifierSet
+ >>> from packaging.version import Version
+ >>> spec1 = SpecifierSet("~=1.0")
+ >>> spec1
+ <SpecifierSet('~=1.0')>
+ >>> spec2 = SpecifierSet(">=1.0")
+ >>> spec2
+ <SpecifierSet('>=1.0')>
+ >>> # We can combine specifiers
+ >>> combined_spec = spec1 & spec2
+ >>> combined_spec
+ <SpecifierSet('>=1.0,~=1.0')>
+ >>> # We can also implicitly combine a string specifier
+ >>> combined_spec &= "!=1.1"
+ >>> combined_spec
+ <SpecifierSet('!=1.1,>=1.0,~=1.0')>
+ >>> # Create a few versions to check for contains.
+ >>> v1 = Version("1.0a5")
+ >>> v2 = Version("1.0")
+ >>> # We can check a version object to see if it falls within a specifier
+ >>> v1 in combined_spec
+ False
+ >>> v2 in combined_spec
+ True
+ >>> # We can even do the same with a string based version
+ >>> "1.4" in combined_spec
+ True
+ >>> # Finally we can filter a list of versions to get only those which are
+ >>> # contained within our specifier.
+ >>> list(combined_spec.filter([v1, v2, "1.4"]))
+ [<Version('1.0')>, '1.4']
+
+
+Reference
+---------
+
+.. class:: SpecifierSet(specifiers="", prereleases=None)
+
+ This class abstracts handling specifying the dependencies of a project. It
+ can be passed a single specifier (``>=3.0``), a comma-separated list of
+ specifiers (``>=3.0,!=3.1``), or no specifier at all. Each individual
+ specifier will be attempted to be parsed as a PEP 440 specifier
+ (:class:`Specifier`) or as a legacy, setuptools style specifier
+ (deprecated :class:`LegacySpecifier`). You may combine
+ :class:`SpecifierSet` instances using the ``&`` operator
+ (``SpecifierSet(">2") & SpecifierSet("<4")``).
+
+ Both the membership tests and the combination support using raw strings
+ in place of already instantiated objects.
+
+ :param str specifiers: The string representation of a specifier or a
+ comma-separated list of specifiers which will
+ be parsed and normalized before use.
+ :param bool prereleases: This tells the SpecifierSet if it should accept
+ prerelease versions if applicable or not. The
+ default of ``None`` will autodetect it from the
+ given specifiers.
+ :raises InvalidSpecifier: If the given ``specifiers`` are not parseable
+ than this exception will be raised.
+
+ .. attribute:: prereleases
+
+ A boolean value indicating whether this :class:`SpecifierSet`
+ represents a specifier that includes a pre-release versions. This can be
+ set to either ``True`` or ``False`` to explicitly enable or disable
+ prereleases or it can be set to ``None`` (the default) to enable
+ autodetection.
+
+ .. method:: __contains__(version)
+
+ This is the more Pythonic version of :meth:`contains()`, but does
+ not allow you to override the ``prereleases`` argument. If you
+ need that, use :meth:`contains()`.
+
+ See :meth:`contains()`.
+
+ .. method:: contains(version, prereleases=None)
+
+ Determines if ``version``, which can be either a version string, a
+ :class:`Version`, or a deprecated :class:`LegacyVersion` object, is
+ contained within this set of specifiers.
+
+ This will either match or not match prereleases based on the
+ ``prereleases`` parameter. When ``prereleases`` is set to ``None``
+ (the default) it will use the ``Specifier().prereleases`` attribute to
+ determine if to allow them. Otherwise it will use the boolean value of
+ the passed in value to determine if to allow them or not.
+
+ .. method:: __len__()
+
+ Returns the number of specifiers in this specifier set.
+
+ .. method:: __iter__()
+
+ Returns an iterator over all the underlying :class:`Specifier` (or
+ deprecated :class:`LegacySpecifier`) instances in this specifier set.
+
+ .. method:: filter(iterable, prereleases=None)
+
+ Takes an iterable that can contain version strings, :class:`~.Version`,
+ and deprecated :class:`~.LegacyVersion` instances and will then filter
+ it, returning an iterable that contains only items which match the
+ rules of this specifier object.
+
+ This method is smarter than just
+ ``filter(Specifier().contains, [...])`` because it implements the rule
+ from PEP 440 where a prerelease item SHOULD be accepted if no other
+ versions match the given specifier.
+
+ The ``prereleases`` parameter functions similarly to that of the same
+ parameter in ``contains``. If the value is ``None`` (the default) then
+ it will intelligently decide if to allow prereleases based on the
+ specifier, the ``Specifier().prereleases`` value, and the PEP 440
+ rules. Otherwise it will act as a boolean which will enable or disable
+ all prerelease versions from being included.
+
+
+.. class:: Specifier(specifier, prereleases=None)
+
+ This class abstracts the handling of a single `PEP 440`_ compatible
+ specifier. It is generally not required to instantiate this manually,
+ preferring instead to work with :class:`SpecifierSet`.
+
+ :param str specifier: The string representation of a specifier which will
+ be parsed and normalized before use.
+ :param bool prereleases: This tells the specifier if it should accept
+ prerelease versions if applicable or not. The
+ default of ``None`` will autodetect it from the
+ given specifiers.
+ :raises InvalidSpecifier: If the ``specifier`` does not conform to PEP 440
+ in any way then this exception will be raised.
+
+ .. attribute:: operator
+
+ The string value of the operator part of this specifier.
+
+ .. attribute:: version
+
+ The string version of the version part of this specifier.
+
+ .. attribute:: prereleases
+
+ See :attr:`SpecifierSet.prereleases`.
+
+ .. method:: __contains__(version)
+
+ See :meth:`SpecifierSet.__contains__()`.
+
+ .. method:: contains(version, prereleases=None)
+
+ See :meth:`SpecifierSet.contains()`.
+
+ .. method:: filter(iterable, prereleases=None)
+
+ See :meth:`SpecifierSet.filter()`.
+
+
+.. class:: LegacySpecifier(specifier, prereleases=None)
+
+ .. deprecated:: 20.5
+
+ Use :class:`Specifier` instead.
+
+ This class abstracts the handling of a single legacy, setuptools style
+ specifier. It is generally not required to instantiate this manually,
+ preferring instead to work with :class:`SpecifierSet`.
+
+ :param str specifier: The string representation of a specifier which will
+ be parsed and normalized before use.
+ :param bool prereleases: This tells the specifier if it should accept
+ prerelease versions if applicable or not. The
+ default of ``None`` will autodetect it from the
+ given specifiers.
+ :raises InvalidSpecifier: If the ``specifier`` is not parseable then this
+ will be raised.
+
+ .. attribute:: operator
+
+ The string value of the operator part of this specifier.
+
+ .. attribute:: version
+
+ The string version of the version part of this specifier.
+
+ .. attribute:: prereleases
+
+ See :attr:`SpecifierSet.prereleases`.
+
+ .. method:: __contains__(version)
+
+ See :meth:`SpecifierSet.__contains__()`.
+
+ .. method:: contains(version, prereleases=None)
+
+ See :meth:`SpecifierSet.contains()`.
+
+ .. method:: filter(iterable, prereleases=None)
+
+ See :meth:`SpecifierSet.filter()`.
+
+
+.. exception:: InvalidSpecifier
+
+ Raised when attempting to create a :class:`Specifier` with a specifier
+ string that does not conform to `PEP 440`_.
+
+
+.. _`PEP 440`: https://www.python.org/dev/peps/pep-0440/
diff --git a/docs/tags.rst b/docs/tags.rst
new file mode 100644
index 0000000..ecd613b
--- /dev/null
+++ b/docs/tags.rst
@@ -0,0 +1,225 @@
+Tags
+====
+
+.. currentmodule:: packaging.tags
+
+Wheels encode the Python interpreter, ABI, and platform that they support in
+their filenames using `platform compatibility tags`_. This module provides
+support for both parsing these tags as well as discovering what tags the
+running Python interpreter supports.
+
+Usage
+-----
+
+.. doctest::
+
+ >>> from packaging.tags import Tag, sys_tags
+ >>> import sys
+ >>> looking_for = Tag("py{major}".format(major=sys.version_info.major), "none", "any")
+ >>> supported_tags = list(sys_tags())
+ >>> looking_for in supported_tags
+ True
+ >>> really_old = Tag("py1", "none", "any")
+ >>> wheels = {really_old, looking_for}
+ >>> best_wheel = None
+ >>> for supported_tag in supported_tags:
+ ... for wheel_tag in wheels:
+ ... if supported_tag == wheel_tag:
+ ... best_wheel = wheel_tag
+ ... break
+ >>> best_wheel == looking_for
+ True
+
+Reference
+---------
+
+High Level Interface
+''''''''''''''''''''
+
+The following functions are the main interface to the library, and are typically the only
+items that applications should need to reference, in order to parse and check tags.
+
+.. class:: Tag(interpreter, abi, platform)
+
+ A representation of the tag triple for a wheel. Instances are considered
+ immutable and thus are hashable. Equality checking is also supported.
+
+ :param str interpreter: The interpreter name, e.g. ``"py"``
+ (see :attr:`INTERPRETER_SHORT_NAMES` for mapping
+ well-known interpreter names to their short names).
+ :param str abi: The ABI that a wheel supports, e.g. ``"cp37m"``.
+ :param str platform: The OS/platform the wheel supports,
+ e.g. ``"win_amd64"``.
+
+ .. attribute:: interpreter
+
+ The interpreter name.
+
+ .. attribute:: abi
+
+ The supported ABI.
+
+ .. attribute:: platform
+
+ The OS/platform.
+
+
+.. function:: parse_tag(tag)
+
+ Parses the provided ``tag`` into a set of :class:`Tag` instances.
+
+ Returning a set is required due to the possibility that the tag is a
+ `compressed tag set`_, e.g. ``"py2.py3-none-any"`` which supports both
+ Python 2 and Python 3.
+
+ :param str tag: The tag to parse, e.g. ``"py3-none-any"``.
+
+
+.. function:: sys_tags(*, warn=False)
+
+ Yields the tags that the running interpreter supports.
+
+ The iterable is ordered so that the best-matching tag is first in the
+ sequence. The exact preferential order to tags is interpreter-specific, but
+ in general the tag importance is in the order of:
+
+ 1. Interpreter
+ 2. Platform
+ 3. ABI
+
+ This order is due to the fact that an ABI is inherently tied to the
+ platform, but platform-specific code is not necessarily tied to the ABI. The
+ interpreter is the most important tag as it dictates basic support for any
+ wheel.
+
+ The function returns an iterable in order to allow for the possible
+ short-circuiting of tag generation if the entire sequence is not necessary
+ and tag calculation happens to be expensive.
+
+ :param bool warn: Whether warnings should be logged. Defaults to ``False``.
+
+
+Low Level Interface
+'''''''''''''''''''
+
+The following functions are low-level implementation details. They should typically not
+be needed in application code, unless the application has specialised requirements (for
+example, constructing sets of supported tags for environments other than the running
+interpreter).
+
+These functions capture the precise details of which environments support which tags. That
+information is not defined in the compatibility tag standards but is noted as being up
+to the implementation to provide.
+
+
+.. attribute:: INTERPRETER_SHORT_NAMES
+
+ A dictionary mapping interpreter names to their `abbreviation codes`_
+ (e.g. ``"cpython"`` is ``"cp"``). All interpreter names are lower-case.
+
+
+.. function:: interpreter_name()
+
+ Returns the running interpreter's name.
+
+ This typically acts as the prefix to the :attr:`~Tag.interpreter` tag.
+
+
+.. function:: interpreter_version(*, warn=False)
+
+ Returns the running interpreter's version.
+
+ This typically acts as the suffix to the :attr:`~Tag.interpreter` tag.
+
+
+.. function:: mac_platforms(version=None, arch=None)
+
+ Yields the :attr:`~Tag.platform` tags for macOS.
+
+ :param tuple version: A two-item tuple presenting the version of macOS.
+ Defaults to the current system's version.
+ :param str arch: The CPU architecture. Defaults to the architecture of the
+ current system, e.g. ``"x86_64"``.
+
+ .. note::
+ Equivalent support for the other major platforms is purposefully not
+ provided:
+
+ - On Windows, platform compatibility is statically specified
+ - On Linux, code must be run on the system itself to determine
+ compatibility
+
+
+.. function:: platform_tags(version=None, arch=None)
+
+ Yields the :attr:`~Tag.platform` tags for the running interpreter.
+
+
+.. function:: compatible_tags(python_version=None, interpreter=None, platforms=None)
+
+ Yields the tags for an interpreter compatible with the Python version
+ specified by ``python_version``.
+
+ The specific tags generated are:
+
+ - ``py*-none-<platform>``
+ - ``<interpreter>-none-any`` if ``interpreter`` is provided
+ - ``py*-none-any``
+
+ :param Sequence python_version: A one- or two-item sequence representing the
+ compatible version of Python. Defaults to
+ ``sys.version_info[:2]``.
+ :param str interpreter: The name of the interpreter (if known), e.g.
+ ``"cp38"``. Defaults to the current interpreter.
+ :param Iterable platforms: Iterable of compatible platforms. Defaults to the
+ platforms compatible with the current system.
+
+.. function:: cpython_tags(python_version=None, abis=None, platforms=None, *, warn=False)
+
+ Yields the tags for the CPython interpreter.
+
+ The specific tags generated are:
+
+ - ``cp<python_version>-<abi>-<platform>``
+ - ``cp<python_version>-abi3-<platform>``
+ - ``cp<python_version>-none-<platform>``
+ - ``cp<older version>-abi3-<platform>`` where "older version" is all older
+ minor versions down to Python 3.2 (when ``abi3`` was introduced)
+
+ If ``python_version`` only provides a major-only version then only
+ user-provided ABIs via ``abis`` and the ``none`` ABI will be used.
+
+ :param Sequence python_version: A one- or two-item sequence representing the
+ targeted Python version. Defaults to
+ ``sys.version_info[:2]``.
+ :param Iterable abis: Iterable of compatible ABIs. Defaults to the ABIs
+ compatible with the current system.
+ :param Iterable platforms: Iterable of compatible platforms. Defaults to the
+ platforms compatible with the current system.
+ :param bool warn: Whether warnings should be logged. Defaults to ``False``.
+
+.. function:: generic_tags(interpreter=None, abis=None, platforms=None, *, warn=False)
+
+ Yields the tags for an interpreter which requires no specialization.
+
+ This function should be used if one of the other interpreter-specific
+ functions provided by this module is not appropriate (i.e. not calculating
+ tags for a CPython interpreter).
+
+ The specific tags generated are:
+
+ - ``<interpreter>-<abi>-<platform>``
+
+ The ``"none"`` ABI will be added if it was not explicitly provided.
+
+ :param str interpreter: The name of the interpreter. Defaults to being
+ calculated.
+ :param Iterable abis: Iterable of compatible ABIs. Defaults to the ABIs
+ compatible with the current system.
+ :param Iterable platforms: Iterable of compatible platforms. Defaults to the
+ platforms compatible with the current system.
+ :param bool warn: Whether warnings should be logged. Defaults to ``False``.
+
+.. _`abbreviation codes`: https://www.python.org/dev/peps/pep-0425/#python-tag
+.. _`compressed tag set`: https://www.python.org/dev/peps/pep-0425/#compressed-tag-sets
+.. _`platform compatibility tags`: https://packaging.python.org/specifications/platform-compatibility-tags/
diff --git a/docs/utils.rst b/docs/utils.rst
new file mode 100644
index 0000000..8fbb025
--- /dev/null
+++ b/docs/utils.rst
@@ -0,0 +1,92 @@
+Utilities
+=========
+
+.. currentmodule:: packaging.utils
+
+
+A set of small, helper utilities for dealing with Python packages.
+
+
+Reference
+---------
+
+.. function:: canonicalize_name(name)
+
+ This function takes a valid Python package name, and returns the normalized
+ form of it.
+
+ :param str name: The name to normalize.
+
+ .. doctest::
+
+ >>> from packaging.utils import canonicalize_name
+ >>> canonicalize_name("Django")
+ 'django'
+ >>> canonicalize_name("oslo.concurrency")
+ 'oslo-concurrency'
+ >>> canonicalize_name("requests")
+ 'requests'
+
+.. function:: canonicalize_version(version)
+
+ This function takes a string representing a package version (or a
+ :class:`~packaging.version.Version` instance), and returns the
+ normalized form of it.
+
+ :param str version: The version to normalize.
+
+ .. doctest::
+
+ >>> from packaging.utils import canonicalize_version
+ >>> canonicalize_version('1.4.0.0.0')
+ '1.4'
+
+.. function:: parse_wheel_filename(filename)
+
+ This function takes the filename of a wheel file, and parses it,
+ returning a tuple of name, version, build number, and tags.
+
+ The name part of the tuple is normalized. The version portion is an
+ instance of :class:`~packaging.version.Version`. The build number
+ is ``()`` if there is no build number in the wheel filename,
+ otherwise a two-item tuple of an integer for the leading digits and
+ a string for the rest of the build number. The tags portion is an
+ instance of :class:`~packaging.tags.Tag`.
+
+ :param str filename: The name of the wheel file.
+
+ .. doctest::
+
+ >>> from packaging.utils import parse_wheel_filename
+ >>> from packaging.tags import Tag
+ >>> from packaging.version import Version
+ >>> name, ver, build, tags = parse_wheel_filename("foo-1.0-py3-none-any.whl")
+ >>> name
+ 'foo'
+ >>> ver == Version('1.0')
+ True
+ >>> tags == {Tag("py3", "none", "any")}
+ True
+ >>> not build
+ True
+
+.. function:: parse_sdist_filename(filename)
+
+ This function takes the filename of a sdist file (as specified
+ in the `Source distribution format`_ documentation), and parses
+ it, returning a tuple of the normalized name and version as
+ represented by an instance of :class:`~packaging.version.Version`.
+
+ :param str filename: The name of the sdist file.
+
+ .. doctest::
+
+ >>> from packaging.utils import parse_sdist_filename
+ >>> from packaging.version import Version
+ >>> name, ver = parse_sdist_filename("foo-1.0.tar.gz")
+ >>> name
+ 'foo'
+ >>> ver == Version('1.0')
+ True
+
+.. _Source distribution format: https://packaging.python.org/specifications/source-distribution-format/#source-distribution-file-name
diff --git a/docs/version.rst b/docs/version.rst
new file mode 100644
index 0000000..a43cf78
--- /dev/null
+++ b/docs/version.rst
@@ -0,0 +1,292 @@
+Version Handling
+================
+
+.. currentmodule:: packaging.version
+
+A core requirement of dealing with packages is the ability to work with
+versions. `PEP 440`_ defines the standard version scheme for Python packages
+which has been implemented by this module.
+
+Usage
+-----
+
+.. doctest::
+
+ >>> from packaging.version import Version, parse
+ >>> v1 = parse("1.0a5")
+ >>> v2 = Version("1.0")
+ >>> v1
+ <Version('1.0a5')>
+ >>> v2
+ <Version('1.0')>
+ >>> v1 < v2
+ True
+ >>> v1.epoch
+ 0
+ >>> v1.release
+ (1, 0)
+ >>> v1.pre
+ ('a', 5)
+ >>> v1.is_prerelease
+ True
+ >>> v2.is_prerelease
+ False
+ >>> Version("french toast")
+ Traceback (most recent call last):
+ ...
+ InvalidVersion: Invalid version: 'french toast'
+ >>> Version("1.0").post
+ >>> Version("1.0").is_postrelease
+ False
+ >>> Version("1.0.post0").post
+ 0
+ >>> Version("1.0.post0").is_postrelease
+ True
+
+
+Reference
+---------
+
+.. function:: parse(version)
+
+ This function takes a version string and will parse it as a
+ :class:`Version` if the version is a valid PEP 440 version, otherwise it
+ will parse it as a deprecated :class:`LegacyVersion`.
+
+
+.. class:: Version(version)
+
+ This class abstracts handling of a project's versions. It implements the
+ scheme defined in `PEP 440`_. A :class:`Version` instance is comparison
+ aware and can be compared and sorted using the standard Python interfaces.
+
+ :param str version: The string representation of a version which will be
+ parsed and normalized before use.
+ :raises InvalidVersion: If the ``version`` does not conform to PEP 440 in
+ any way then this exception will be raised.
+
+ .. attribute:: public
+
+ A string representing the public version portion of this ``Version()``.
+
+ .. attribute:: base_version
+
+ A string representing the base version of this :class:`Version`
+ instance. The base version is the public version of the project without
+ any pre or post release markers.
+
+ .. attribute:: epoch
+
+ An integer giving the version epoch of this :class:`Version` instance
+
+ .. attribute:: release
+
+ A tuple of integers giving the components of the release segment of
+ this :class:`Version` instance; that is, the ``1.2.3`` part of the
+ version number, including trailing zeroes but not including the epoch
+ or any prerelease/development/postrelease suffixes
+
+ .. attribute:: major
+
+ An integer representing the first item of :attr:`release` or ``0`` if unavailable.
+
+ .. attribute:: minor
+
+ An integer representing the second item of :attr:`release` or ``0`` if unavailable.
+
+ .. attribute:: micro
+
+ An integer representing the third item of :attr:`release` or ``0`` if unavailable.
+
+ .. attribute:: local
+
+ A string representing the local version portion of this ``Version()``
+ if it has one, or ``None`` otherwise.
+
+ .. attribute:: pre
+
+ If this :class:`Version` instance represents a prerelease, this
+ attribute will be a pair of the prerelease phase (the string ``"a"``,
+ ``"b"``, or ``"rc"``) and the prerelease number (an integer). If this
+ instance is not a prerelease, the attribute will be `None`.
+
+ .. attribute:: is_prerelease
+
+ A boolean value indicating whether this :class:`Version` instance
+ represents a prerelease and/or development release.
+
+ .. attribute:: dev
+
+ If this :class:`Version` instance represents a development release,
+ this attribute will be the development release number (an integer);
+ otherwise, it will be `None`.
+
+ .. attribute:: is_devrelease
+
+ A boolean value indicating whether this :class:`Version` instance
+ represents a development release.
+
+ .. attribute:: post
+
+ If this :class:`Version` instance represents a postrelease, this
+ attribute will be the postrelease number (an integer); otherwise, it
+ will be `None`.
+
+ .. attribute:: is_postrelease
+
+ A boolean value indicating whether this :class:`Version` instance
+ represents a post-release.
+
+
+.. class:: LegacyVersion(version)
+
+ .. deprecated:: 20.5
+
+ Use :class:`Version` instead.
+
+ This class abstracts handling of a project's versions if they are not
+ compatible with the scheme defined in `PEP 440`_. It implements a similar
+ interface to that of :class:`Version`.
+
+ This class implements the previous de facto sorting algorithm used by
+ setuptools, however it will always sort as less than a :class:`Version`
+ instance.
+
+ :param str version: The string representation of a version which will be
+ used as is.
+
+ .. note::
+
+ :class:`LegacyVersion` instances are always ordered lower than :class:`Version` instances.
+
+ >>> from packaging.version import Version, LegacyVersion
+ >>> v1 = Version("1.0")
+ >>> v2 = LegacyVersion("1.0")
+ >>> v1 > v2
+ True
+ >>> v3 = LegacyVersion("1.3")
+ >>> v1 > v3
+ True
+
+ Also note that some strings are still valid PEP 440 strings (:class:`Version`), even if they look very similar to
+ other versions that are not (:class:`LegacyVersion`). Examples include versions with `Pre-release spelling`_ and
+ `Post-release spelling`_.
+
+ >>> from packaging.version import parse
+ >>> v1 = parse('0.9.8a')
+ >>> v2 = parse('0.9.8beta')
+ >>> v3 = parse('0.9.8r')
+ >>> v4 = parse('0.9.8rev')
+ >>> v5 = parse('0.9.8t')
+ >>> v1
+ <Version('0.9.8a0')>
+ >>> v1.is_prerelease
+ True
+ >>> v2
+ <Version('0.9.8b0')>
+ >>> v2.is_prerelease
+ True
+ >>> v3
+ <Version('0.9.8.post0')>
+ >>> v3.is_postrelease
+ True
+ >>> v4
+ <Version('0.9.8.post0')>
+ >>> v4.is_postrelease
+ True
+ >>> v5
+ <LegacyVersion('0.9.8t')>
+ >>> v5.is_prerelease
+ False
+ >>> v5.is_postrelease
+ False
+
+ .. attribute:: public
+
+ A string representing the public version portion of this
+ :class:`LegacyVersion`. This will always be the entire version string.
+
+ .. attribute:: base_version
+
+ A string representing the base version portion of this
+ :class:`LegacyVersion` instance. This will always be the entire version
+ string.
+
+ .. attribute:: epoch
+
+ This will always be ``-1`` since without `PEP 440`_ we do not have the
+ concept of version epochs. The value reflects the fact that
+ :class:`LegacyVersion` instances always compare less than
+ :class:`Version` instances.
+
+ .. attribute:: release
+
+ This will always be ``None`` since without `PEP 440`_ we do not have
+ the concept of a release segment or its components. It exists
+ primarily to allow a :class:`LegacyVersion` to be used as a stand in
+ for a :class:`Version`.
+
+ .. attribute:: local
+
+ This will always be ``None`` since without `PEP 440`_ we do not have
+ the concept of a local version. It exists primarily to allow a
+ :class:`LegacyVersion` to be used as a stand in for a :class:`Version`.
+
+ .. attribute:: pre
+
+ This will always be ``None`` since without `PEP 440`_ we do not have
+ the concept of a prerelease. It exists primarily to allow a
+ :class:`LegacyVersion` to be used as a stand in for a :class:`Version`.
+
+ .. attribute:: is_prerelease
+
+ A boolean value indicating whether this :class:`LegacyVersion`
+ represents a prerelease and/or development release. Since without
+ `PEP 440`_ there is no concept of pre or dev releases this will
+ always be `False` and exists for compatibility with :class:`Version`.
+
+ .. attribute:: dev
+
+ This will always be ``None`` since without `PEP 440`_ we do not have
+ the concept of a development release. It exists primarily to allow a
+ :class:`LegacyVersion` to be used as a stand in for a :class:`Version`.
+
+ .. attribute:: is_devrelease
+
+ A boolean value indicating whether this :class:`LegacyVersion`
+ represents a development release. Since without `PEP 440`_ there is
+ no concept of dev releases this will always be `False` and exists for
+ compatibility with :class:`Version`.
+
+ .. attribute:: post
+
+ This will always be ``None`` since without `PEP 440`_ we do not have
+ the concept of a postrelease. It exists primarily to allow a
+ :class:`LegacyVersion` to be used as a stand in for a :class:`Version`.
+
+ .. attribute:: is_postrelease
+
+ A boolean value indicating whether this :class:`LegacyVersion`
+ represents a post-release. Since without `PEP 440`_ there is no concept
+ of post-releases this will always be ``False`` and exists for
+ compatibility with :class:`Version`.
+
+
+.. exception:: InvalidVersion
+
+ Raised when attempting to create a :class:`Version` with a version string
+ that does not conform to `PEP 440`_.
+
+
+.. data:: VERSION_PATTERN
+
+ A string containing the regular expression used to match a valid version.
+ The pattern is not anchored at either end, and is intended for embedding
+ in larger expressions (for example, matching a version number as part of
+ a file name). The regular expression should be compiled with the
+ ``re.VERBOSE`` and ``re.IGNORECASE`` flags set.
+
+
+.. _PEP 440: https://www.python.org/dev/peps/pep-0440/
+.. _Pre-release spelling : https://www.python.org/dev/peps/pep-0440/#pre-release-spelling
+.. _Post-release spelling : https://www.python.org/dev/peps/pep-0440/#post-release-spelling