Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement extras_require #181

Merged
merged 19 commits into from
Jul 23, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions doc/pyproject_toml.rst
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,23 @@ requires
"configparser; python_version == '2.7'"
]

extras-require
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like the user facing name for this field to be requires-extra or requires-extras (I don't have a strong preference between these two - thoughts?). I like the symmetry between requires, requires-python and requires-extra[s].

I think of this like "the package requires these packages, this version of Python, and optionally these further packages for extra features."

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

requires-extras and requires-extra imply that the package requires the extras. However it’s the extra features that require certain dependencies. So only extras-require says the right thing, don’t you agree?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I don't. The naming extras_require has always felt unintuitive to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, requires-extra makes a little more sense, I’m going for that one then.

Lists of packages needed for every optional feature. The requirements
are specified in the same format as for ``requires``. The requirements of
the two reserved extras ``test`` and ``doc`` as well as the extra ``dev``
are installed by ``flit install``. For example:

.. code-block:: toml
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will emit sphinx warning message: WARNING: Pygments lexer name 'toml' is not known.
I'm using Sphinx 1.7.4.

Copy link
Contributor Author

@flying-sheep flying-sheep Jul 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, we could add pygments-github-lexers to the doc extra requirements


[tool.flit.metadata.extras-require]
test = ["pytest>=2.7.3", "pytest-cov"]
doc = ["sphinx"]

dev-requires
Packages that are required for development. This field is in the same format
as ``requires``.
Packages that are required for development, other than the ones belonging to
the extras ``test`` and ``doc``. This field is in the same format as ``requires``.

These are not (yet) encoded in the wheel, but are used when doing
``flit install``.
These are installed by ``flit install`` and encoded in the wheel as extra ``dev``.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would make this undocumented (or maybe leave it for now but mark it as deprecated). The canonical way will become extras-require.dev.

description-file
A path (relative to the .toml file) to a file containing a longer description
of your package to show on PyPI. This should be written in `reStructuredText
Expand Down
16 changes: 13 additions & 3 deletions flit/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,17 +227,23 @@ class Metadata:
requires_external = ()
provides_extra = ()

metadata_version="2.1"
metadata_version = "2.1"

# this is part of metadata spec 2, we are using it for installation but it
# doesn't actually get written to the metadata file
# metadata spec 2
dev_requires = ()
extras_require = {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Metadata 2.0 was dropped, and metadata 2.1 is much closer to the 1.x formats. This metadata class is meant to closely represent the metadata we actually write/upload, so I'd rather add the extra requirements to requires_dist rather than adding a dict attribute to it.

The _prep_metadata() function in flit.inifile is responsible for converting the metadata we read from the file to a dict representing the standardised Python metadata.


def __init__(self, data):
self.name = data.pop('name')
self.version = data.pop('version')
self.author_email = data.pop('author_email')
self.summary = data.pop('summary')
self.extras_require = data.pop('extras_require', {})
dev_requires = data.pop('dev_requires', None)
if dev_requires is not None:
self.extras_require['dev'] = dev_requires
explicit_extras = data.pop('provides_extra', ())
self.provides_extra = list(set(explicit_extras) | self.extras_require.keys())
for k, v in data.items():
assert hasattr(self, k), "data does not have attribute '{}'".format(k)
setattr(self, k, v)
Expand Down Expand Up @@ -280,6 +286,10 @@ def write_metadata_file(self, fp):
for req in self.requires_dist:
fp.write('Requires-Dist: {}\n'.format(req))

for extra, reqs in self.extras_require.items():
for req in reqs:
fp.write('Requires-Dist: {}; extra == "{}"\n'.format(req, extra))

for url in self.project_urls:
fp.write('Project-URL: {}\n'.format(url))

Expand Down
1 change: 1 addition & 0 deletions flit/inifile.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class ConfigError(ValueError):
'dist-name',
'entry-points-file',
'description-file',
'extras-require',
} | metadata_list_fields

metadata_required_fields = {
Expand Down
4 changes: 3 additions & 1 deletion flit/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,9 @@ def install_requirements(self):
if self.deps in ('all', 'production'):
requirements.extend(self.ini_info['metadata'].get('requires_dist', []))
if self.deps in ('all', 'develop'):
requirements.extend(self.ini_info['metadata'].get('dev_requires', []))
extra_reqs = self.ini_info['metadata'].get('extras_require', {})
for extra in ['dev', 'doc', 'test']:
requirements.extend(extra_reqs.get(extra, []))

# there aren't any requirements, so return
if len(requirements) == 0:
Expand Down