-
Notifications
You must be signed in to change notification settings - Fork 40
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
convert '~=' requirements specifier #184
base: master
Are you sure you want to change the base?
Changes from all commits
c73c5bf
05ea1af
8480b03
b6ddbfa
c453612
664f317
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -149,6 +149,12 @@ def fetch(args): | |
|
||
def _canonicalize_setup_data(data): | ||
|
||
def _search_requires(req, pat): | ||
for arr in req: | ||
if arr[0] == pat: | ||
return 1 | ||
return 0 | ||
|
||
if data.get('build-system', None): | ||
# PEP 518: 'requires' field is mandatory | ||
data['build_requires'] = py2pack.requires._requirements_sanitize( | ||
|
@@ -160,14 +166,13 @@ def _canonicalize_setup_data(data): | |
if isinstance(setup_requires, str): | ||
setup_requires = setup_requires.splitlines() | ||
# canonicalize to build_requires | ||
data["build_requires"] = ['setuptools', 'wheel'] + \ | ||
data["build_requires"] = [['setuptools'], ['wheel']] + \ | ||
py2pack.requires._requirements_sanitize(setup_requires) | ||
else: | ||
# no build_requires means most probably legacy setuptools | ||
data["build_requires"] = ['setuptools'] | ||
if 'setuptools' in data['build_requires'] and 'wheel' not in data['build_requires']: | ||
data['build_requires'] += ['wheel'] | ||
|
||
data["build_requires"] = [['setuptools']] | ||
if _search_requires(data['build_requires'], 'setuptools') and not _search_requires(data['build_requires'], 'wheel'): | ||
data['build_requires'] += [['wheel']] | ||
install_requires = ( | ||
get_pyproject_table(data, "project.dependencies") or | ||
get_pyproject_table(data, "tool.flit.metadata.requires") or | ||
|
@@ -336,10 +341,56 @@ def _normalize_license(data): | |
def _prepare_template_env(template_dir): | ||
# setup jinja2 environment with custom filters | ||
env = jinja2.Environment(loader=jinja2.FileSystemLoader(template_dir)) | ||
|
||
def _rpm_format_requires(req, pfx): | ||
req[0] = pfx + req[0] | ||
part1 = " ".join(req[0:3]) | ||
part2 = "" | ||
if len(req) > 3: | ||
req[3] = pfx + req[3] | ||
part2 = ", " + " ".join(req[3:]) | ||
return part1 + part2 | ||
|
||
def _parenthesize_version(req): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nitpick: This function does complex require formatting, it could be great to have some comment with examples of what it does, input -> output so it will be easier to understand in the future. |
||
ret = req[0].lower() | ||
ver = [] | ||
if len(req) > 1: | ||
if req[1] == '<': | ||
req[1] = '<<' | ||
if req[1] == '>': | ||
req[1] = '>>' | ||
ver.append(" (" + " ".join(req[1:3]) + ")") | ||
if len(req) > 3: | ||
if req[4] == '<': | ||
req[4] = '<<' | ||
if req[4] == '>': | ||
req[4] = '>>' | ||
ver.append(req[3].lower() + " (" + " ".join(req[4:6]) + ")") | ||
|
||
if ver: | ||
ret += ", ".join(ver) | ||
return ret | ||
|
||
def reject_pkg(s, req): | ||
nms = list(map(lambda n: n[0], req)) | ||
ret = [] | ||
for n in s: | ||
if n[0] not in nms: | ||
ret.append(n) | ||
return ret | ||
|
||
env.filters['parenthesize_version'] = \ | ||
lambda s: re.sub('([=<>]+)(.+)', r' (\1 \2)', s) | ||
lambda s: _parenthesize_version(s) | ||
env.filters['basename'] = \ | ||
lambda s: s[s.rfind('/') + 1:] | ||
env.filters['rpm_format_buildrequires'] = \ | ||
lambda s: " ".join(s[0:3]) | ||
env.filters['rpm_format_requires'] = \ | ||
lambda s, p: _rpm_format_requires(s, p) | ||
env.filters['sort_requires'] = \ | ||
lambda s: sorted(s, key=lambda k: k[0].lower()) | ||
env.filters['reject_pkg'] = reject_pkg | ||
|
||
return env | ||
|
||
|
||
|
@@ -361,7 +412,7 @@ def generate(args): | |
args.template = file_template_list()[0] | ||
if not args.filename: | ||
args.filename = "python-" + args.name + '.' + args.template.rsplit('.', 1)[1] # take template file ending | ||
print('generating spec file for {0}...'.format(args.name)) | ||
print('generating spec file for {0} using {1}...'.format(args.name, args.template)) | ||
data = args.fetched_data['info'] | ||
durl = newest_download_url(args) | ||
source_url = data['source_url'] = (args.source_url or (durl and durl['url'])) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -102,4 +102,20 @@ def _requirements_sanitize(req_list): | |
(Requirement(s.split("#", maxsplit=1)[0]) for s in req_list) | ||
if _requirement_filter_by_marker(req) | ||
) | ||
return [" ".join(req) for req in filtered_req_list] | ||
out_list = [] | ||
for req in filtered_req_list: | ||
# Convert '~=' operator to something rpm and deb can understand | ||
# abc ~= 1.1.1 | ||
# should be converted into something like (for rpm) | ||
# | ||
# Requires: python-abc >= 1.1.1, python-abc < 1.2 | ||
# BuildRequires: %{python_module abc >= 1.1.1} | ||
if len(req) > 1 and req[1] == '~=': | ||
req[1] = '>=' | ||
v = req[2].split('.') | ||
v.pop() | ||
Comment on lines
+115
to
+116
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The version in a |
||
v[-1] = str(int(v[-1]) + 1) | ||
req += [req[0], '<', ".".join(v)] | ||
out_list.append(req) | ||
|
||
return out_list | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I'm understanding this code correctly, the return now is a list of lists, so we should update the documentation of this method to match the new way of producing the output. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -129,10 +129,11 @@ def get_setuptools_scripts(data): | |
Returns: | ||
list of script names | ||
""" | ||
entry_points = data.get('entry_points', None) | ||
if isinstance(entry_points, str): | ||
eps = EntryPoints(EntryPoints._from_text(entry_points)) | ||
elif isinstance(entry_points, dict): | ||
if "entry_points" not in data or not data['entry_points']: | ||
return [] | ||
if isinstance(data["entry_points"], str): | ||
eps = EntryPoints(EntryPoints._from_text(data["entry_points"])) | ||
elif isinstance(data["entry_points"], dict): | ||
Comment on lines
+132
to
+136
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This change break the following code, because And I think this change is not needed, it's doing the same. If |
||
eps = EntryPoints([EntryPoint(*map(str.strip, entry.split("=", 1)), groupname) | ||
for groupname, group in entry_points.items() | ||
for entry in group | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
# | ||
# spec file for package python-sampleproject | ||
# | ||
# Copyright (c) __YEAR__ __USER__. | ||
# | ||
|
||
Name: python-sampleproject | ||
Version: 3.0.0 | ||
Release: 0 | ||
Summary: A sample Python project | ||
License: Copyright (c) 2016 The Python Packaging Authority (PyPA) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. (FIXME:No SPDX) | ||
URL: | ||
Source: https://files.pythonhosted.org/packages/source/s/sampleproject/sampleproject-%{version}.tar.gz | ||
BuildRoot: %{_tmppath}/%{name}-%{version}-build | ||
BuildRequires: python-devel >=3.7 | ||
|
||
%description | ||
# A sample Python project | ||
|
||
 | ||
|
||
A sample project that exists as an aid to the [Python Packaging User | ||
Guide][packaging guide]'s [Tutorial on Packaging and Distributing | ||
Projects][distribution tutorial]. | ||
|
||
This project does not aim to cover best practices for Python project | ||
development as a whole. For example, it does not provide guidance or tool | ||
recommendations for version control, documentation, or testing. | ||
|
||
[The source for this project is available here][src]. | ||
|
||
The metadata for a Python project is defined in the `pyproject.toml` file, | ||
an example of which is included in this project. You should edit this file | ||
accordingly to adapt this sample project to your needs. | ||
|
||
---- | ||
|
||
This is the README file for the project. | ||
|
||
The file should use UTF-8 encoding and can be written using | ||
[reStructuredText][rst] or [markdown][md use] with the appropriate [key set][md | ||
use]. It will be used to generate the project webpage on PyPI and will be | ||
displayed as the project homepage on common code-hosting services, and should be | ||
written for that purpose. | ||
|
||
Typical contents for this file would include an overview of the project, basic | ||
usage examples, etc. Generally, including the project changelog in here is not a | ||
good idea, although a simple “What's New” section for the most recent version | ||
may be appropriate. | ||
|
||
[packaging guide]: https://packaging.python.org | ||
[distribution tutorial]: https://packaging.python.org/tutorials/packaging-projects/ | ||
[src]: https://github.com/pypa/sampleproject | ||
[rst]: http://docutils.sourceforge.net/rst.html | ||
[md]: https://tools.ietf.org/html/rfc7764#section-3.5 "CommonMark variant" | ||
[md use]: https://packaging.python.org/specifications/core-metadata/#description-content-type-optional | ||
|
||
|
||
%prep | ||
%setup -q -n sampleproject-%{version} | ||
|
||
%build | ||
python setup.py build | ||
|
||
%install | ||
python setup.py install --prefix=%{_prefix} --root=%{buildroot} | ||
|
||
%clean | ||
rm -rf %{buildroot} | ||
|
||
%files | ||
%defattr(-,root,root,-) | ||
%{python_sitelib}/* | ||
|
||
%changelog |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
search_requires
function is not needed, this can be done with a list comprehension in a more pythonic way: