Skip to content
Open
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
60 changes: 53 additions & 7 deletions py2pack/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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'):

Copy link
Copy Markdown
Contributor

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:

# Just the list of requires packages, without version information
require_names = [r[0] for r in data['build_requires']]
if 'setuptools' in require_names and 'wheel' not in require_names:

data['build_requires'] += [['wheel']]
install_requires = (
get_pyproject_table(data, "project.dependencies") or
get_pyproject_table(data, "tool.flit.metadata.requires") or
Expand Down Expand Up @@ -336,10 +341,51 @@ 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):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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.

req[0] = "python-" + req[0]
part1 = " ".join(req[0:3])
part2 = ""
if len(req) > 3:
req[3] = "python-" + req[3]
part2 = ", " + " ".join(req[3:])
return part1 + part2

def _parenthesize_version(req):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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.

print(req)
ret = req[0].lower()
ver = []
if len(req) > 1:
print(req[1:2])
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:
print(ver)
ret += ", ".join(ver)
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: _rpm_format_requires(s)
env.filters['sort_requires'] = \
lambda s: sorted(s, key=lambda k: k[0].lower())
env.filters['reject_pkg'] = \
lambda s, req: s if not any(s[0] in sl for sl in req) else None
return env


Expand All @@ -361,7 +407,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']))
Expand Down
18 changes: 17 additions & 1 deletion py2pack/requires.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The version in a ~= requirement could be something without dots (abc ~= 3)? In that case, this can remove the version completely and will crash in the following line. But I'm not sure if that case is something that makes sense.

v[-1] = str(int(v[-1]) + 1)
req += [req[0], '<', ".".join(v)]
out_list.append(req)

return out_list

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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.

27 changes: 9 additions & 18 deletions py2pack/templates/fedora.spec
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,15 @@ Summary: {{ summary }}
License: {{ license }}
URL: {{ home_page }}
Source: {{ source_url|replace(version, '%{version}') }}

BuildRequires: pyproject-rpm-macros
BuildRequires: python-devel
%if %{undefined python_module}
%define python_module() python3dist(%1)
%endif

{%- set build_requires_plus_pip = ((build_requires if build_requires and build_requires is not none else []) +
['pip']) %}
{%- for req in build_requires_plus_pip |sort %}
BuildRequires: %{python_module {{ req }}}
BuildRoot: %{_tmppath}/%{name}-%{version}-build
BuildRequires: python-devel {%- if requires_python %} {{ requires_python }} {% endif %}
{%- for req in requires %}
BuildRequires: {{ req|rpm_format_requires }}
Requires: {{ req|rpm_format_requires }}
{%- endfor %}
{%- if (install_requires and install_requires is not none) or (tests_require and tests_require is not none) %}
# SECTION test requirements
%if %{with test}
{%- if install_requires and install_requires is not none %}
{%- for req in install_requires|reject("in",build_requires)|sort %}
BuildRequires: %{python_module {{ req }}}
{%- for req in install_requires %}
BuildRequires: {{ req|rpm_format_requires }}
Requires: {{ req|rpm_format_requires }} }}
{%- endfor %}
{%- endif %}
{%- if tests_require and tests_require is not none %}
Expand All @@ -50,7 +41,7 @@ Requires: %{python_module {{ req }}}
{%- if extras_require and extras_require is not none %}
{%- for reqlist in extras_require.values() %}
{%- for req in reqlist %}
Suggests: %{python_module {{ req }}}
Suggests: {{ req|rpm_format_requires }}
{%- endfor %}
{%- endfor %}
{%- endif %}
Expand Down
12 changes: 7 additions & 5 deletions py2pack/templates/mageia.spec
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ Source: {{ source_url|replace(version, '%{version}') }}
BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot
BuildRequires: python-devel
{%- for req in requires %}
BuildRequires: python-{{ req|lower }}
Requires: pyhton-{{ req|lower }}
BuildRequires: {{ req|rpm_format_requires|lower }}
Requires: {{ req|rpm_format_requires|lower }}
{%- endfor %}
{%- for req in install_requires %}
BuildRequires: python-{{ req|lower }}
Requires: python-{{ req|lower }}
BuildRequires: {{ req|rpm_format_requires|lower }}
Requires: {{ req|rpm_format_requires|lower }}
{%- endfor %}
{%- if extras_require %}
{%- for reqlist in extras_require.values() %}
{%- for req in reqlist %}
Suggests: python-{{ req|lower }}
Suggests: {{ req|rpm_format_requires|lower }}
{%- endfor %}
{%- endfor %}
{%- endif %}
Expand Down Expand Up @@ -51,8 +51,10 @@ rm -rf %{buildroot}
{%- if doc_files %}
%doc {{ doc_files|join(" ") }}
{%- endif %}
{%- if scripts %}
{%- for script in scripts %}
%{_bindir}/{{ script }}
{%- endfor %}
{%- endif %}
%{python_sitelib}/*

8 changes: 4 additions & 4 deletions py2pack/templates/opensuse-legacy.spec
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,27 @@ Source: {{ source_url|replace(version, '%{version}') }}
BuildRequires: python-setuptools
{%- if install_requires and install_requires is not none %}
{%- for req in install_requires|sort %}
BuildRequires: python-{{ req }}
BuildRequires: {{ req|rpm_format_requires}}
{%- endfor %}
{%- endif %}
{%- if tests_require and tests_require is not none %}
# test requirements
{%- for req in tests_require|sort %}
BuildRequires: python-{{ req }}
BuildRequires: {{ req|rpm_format_requires}}
{%- endfor %}
{%- endif %}
{%- if source_url.endswith('.zip') %}
BuildRequires: unzip
{%- endif %}
{%- if install_requires and install_requires is not none %}
{%- for req in install_requires|sort %}
Requires: python-{{ req }}
Requires: {{ req|rpm_format_requires}}
{%- endfor %}
{%- endif %}
{%- if extras_require and extras_require is not none %}
{%- for reqlist in extras_require.values() %}
{%- for req in reqlist %}
Suggests: python-{{ req }}
Suggests: {{ req|rpm_format_requires}}
{%- endfor %}
{%- endfor %}
{%- endif %}
Expand Down
6 changes: 3 additions & 3 deletions py2pack/templates/opensuse.dsc
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ Binary: python-{{ name|lower }}
Maintainer: {{ user_name }}
Architecture: any
Standards-Version: 3.7.1
Build-Depends: debhelper (>= 4.0.0), python-dev{% for req in requires %}, python-{{ req|lower|parenthesize_version }}{% endfor %}{% for req in install_requires %}, python-{{ req|lower|parenthesize_version }}{% endfor %}
Build-Depends: debhelper (>= 4.0.0), python-dev{% for req in requires %}, python-{{ req|parenthesize_version }}{% endfor %}{% for req in install_requires %}, python-{{ req|parenthesize_version }}{% endfor %}
{%- if requires or install_requires %}
Depends: {% for req in requires %}python-{{ req|lower|parenthesize_version }}{{ ', ' if not loop.last or install_requires }}{% endfor %}{% for req in install_requires %}python-{{ req|lower|parenthesize_version }}{{ ', ' if not loop.last }}{% endfor %}
Depends: {% for req in requires %}python-{{ req|parenthesize_version }}{{ ', ' if not loop.last or install_requires }}{% endfor %}{% for req in install_requires %}python-{{ req|parenthesize_version }}{{ ', ' if not loop.last }}{% endfor %}
{%- endif %}
{%- if extras_require %}
Suggests: {% for reqlist in extras_require.values() %}{% for req in reqlist %}python-{{ req|lower|parenthesize_version }}{{ ', ' if not loop.last }}{%- endfor %}{{ ', ' if not loop.last }}{%- endfor %}
Suggests: {% for reqlist in extras_require.values() %}{% for req in reqlist %}python-{{ req|parenthesize_version }}{{ ', ' if not loop.last }}{%- endfor %}{{ ', ' if not loop.last }}{%- endfor %}
{%- endif %}

20 changes: 10 additions & 10 deletions py2pack/templates/opensuse.spec
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,20 @@ URL: {{ home_page }}
Source: {{ source_url|replace(version, '%{version}') }}
BuildRequires: python-rpm-macros
{%- set build_requires_plus_pip = ((build_requires if build_requires and build_requires is not none else []) +
['pip']) %}
{%- for req in build_requires_plus_pip |sort %}
BuildRequires: %{python_module {{ req }}}
[['pip']]) %}
{%- for req in build_requires_plus_pip|sort_requires %}
BuildRequires: %{python_module {{ req|rpm_format_buildrequires }}}
{%- endfor %}
{%- if (install_requires and install_requires is not none) or (tests_require and tests_require is not none) %}
# SECTION test requirements
{%- if install_requires and install_requires is not none %}
{%- for req in install_requires|reject("in",build_requires)|sort %}
BuildRequires: %{python_module {{ req }}}
{%- for req in install_requires|reject("in",build_requires)|sort_requires %}
BuildRequires: %{python_module {{ req|rpm_format_buildrequires }}}
{%- endfor %}
{%- endif %}
{%- if tests_require and tests_require is not none %}
{%- for req in tests_require|sort|reject("in",build_requires|sort) %}
BuildRequires: %{python_module {{ req }}}
{%- for req in tests_require|sort_requires|reject_pkg(build_requires) %}
BuildRequires: %{python_module {{ req|rpm_format_buildrequires }}}
{%- endfor %}
{%- endif %}
# /SECTION
Expand All @@ -48,14 +48,14 @@ BuildRequires: unzip
{%- endif %}
BuildRequires: fdupes
{%- if install_requires and install_requires is not none %}
{%- for req in install_requires|sort %}
Requires: python-{{ req }}
{%- for req in install_requires|sort_requires %}
Requires: {{ req|rpm_format_requires }}
{%- endfor %}
{%- endif %}
{%- if extras_require and extras_require is not none %}
{%- for reqlist in extras_require.values() %}
{%- for req in reqlist %}
Suggests: python-{{ req }}
Suggests: {{ req|rpm_format_requires }}
{%- endfor %}
{%- endfor %}
{%- endif %}
Expand Down
1 change: 1 addition & 0 deletions py2pack/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@

from backports.entry_points_selectable import EntryPoint, EntryPoints


def _get_archive_filelist(filename):
# type: (str) -> List[str]
"""Extract the list of files from a tar or zip archive.
Expand Down
48 changes: 24 additions & 24 deletions test/test_py2pack.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,39 +114,39 @@ def test__prepare_template_env(self):
@data(
(
{'install_requires': ["pywin32>=1.0;sys_platform=='win32'", 'monotonic>=0.1 #comment']},
{'build_requires': ['setuptools', 'wheel'],
'install_requires': ['monotonic >= 0.1']},
{'build_requires': [['setuptools'], ['wheel']],
'install_requires': [['monotonic', '>=', '0.1']]},
),
(
{'install_requires': 'six >=1.9,!=1.0 # comment\nfoobar>=0.1,>=0.5'},
{'build_requires': ['setuptools', 'wheel'],
'install_requires': ['six >= 1.9', 'foobar >= 0.1']}
{'build_requires': [['setuptools'], ['wheel']],
'install_requires': [['six', '>=', '1.9'], ['foobar', '>=', '0.1']]}
),
(
{'setup_requires': 'six >=1.9,!=1.0 # comment\nfoobar>=0.1,>=0.5'},
{'build_requires': ['setuptools', 'wheel', 'six >= 1.9', 'foobar >= 0.1']}
{'build_requires': [['setuptools'], ['wheel'], ['six', '>=', '1.9'], ['foobar', '>=', '0.1']]}
),
(
{'tests_require': ['six >=1.9', 'foobar>=0.1,>=0.5']},
{'build_requires': ['setuptools', 'wheel'],
'tests_require': ['six >= 1.9', 'foobar >= 0.1']}
{'build_requires': [['setuptools'], ['wheel']],
'tests_require': [['six', '>=', '1.9'], ['foobar', '>=', '0.1']]}
),
(
{'tests_require': 'six >=1.9\nfoobar>=0.1,>=0.5'},
{'build_requires': ['setuptools', 'wheel'],
'tests_require': ['six >= 1.9', 'foobar >= 0.1']}
{'build_requires': [['setuptools'], ['wheel']],
'tests_require': [['six', '>=', '1.9'], ['foobar', '>=', '0.1']]}
),
(
{'extras_require': {'extra1': ['foobar<=3.0, >= 2.1']}},
{'build_requires': ['setuptools', 'wheel'],
'extras_require': {'extra1': ['foobar >= 2.1']}}
{'build_requires': [['setuptools'], ['wheel']],
'extras_require': {'extra1': [['foobar', '>=', '2.1']]}}
),
(
{'extras_require': {'extra1': 'foobar<=3.0, >= 2.1\ntest1 # comment',
'extra2': ['test2']}},
{'build_requires': ['setuptools', 'wheel'],
'extras_require': {'extra1': ['foobar >= 2.1', 'test1'],
'extra2': ['test2']}}
{'build_requires': [['setuptools'], ['wheel']],
'extras_require': {'extra1': [['foobar', '>=', '2.1'], ['test1']],
'extra2': [['test2']]}}
),
(
{'build-system': {'requires': ['setuptools']},
Expand All @@ -155,10 +155,10 @@ def test__prepare_template_env(self):
'test': ['pytest']},
'scripts': {'cmd1': 'foo:main', 'cmd2': 'bar:cmd2'},
'gui-scripts': {'gui': 'foo:mainview'}}},
{'build_requires': ['setuptools', 'wheel'],
'install_requires': ['foo', 'bar >= 1', 'foobar > 2'],
'extras_require': {'extra': ['extra1', 'extra2 > 2']},
'tests_require': ['pytest'],
{'build_requires': [['setuptools'], ['wheel']],
'install_requires': [['foo'], ['bar', '>=', '1'], ['foobar', '>', '2']],
'extras_require': {'extra': [['extra1'], ['extra2', '>', '2']]},
'tests_require': [['pytest']],
'console_scripts': ['cmd1', 'cmd2', 'gui']}
),
(
Expand All @@ -169,17 +169,17 @@ def test__prepare_template_env(self):
'requires-extra': {'extra': ['extra1', 'extra2>2'],
'test': ['pytest']}},
'scripts': {'cmd': 'foo:main'}}}},
{'build_requires': ['flit_core'],
'install_requires': ['foo', 'bar >= 1', 'foobar > 2'],
'extras_require': {'extra': ['extra1', 'extra2 > 2']},
'tests_require': ['pytest'],
{'build_requires': [['flit_core']],
'install_requires': [['foo'], ['bar', '>=', '1'], ['foobar', '>', '2']],
'extras_require': {'extra': [['extra1'], ['extra2', '>', '2']]},
'tests_require': [['pytest']],
'console_scripts': ['cmd']}
),
(
{'build-system': {'requires': ['hatchling']},
'project': {'dependencies': ['foo', 'bar>=1', 'foobar>2,<3']}},
{'build_requires': ['hatchling'],
'install_requires': ['foo', 'bar >= 1', 'foobar > 2']}
{'build_requires': [['hatchling']],
'install_requires': [['foo'], ['bar', '>=', '1'], ['foobar', '>', '2']]}
),
)
@unpack
Expand Down
6 changes: 3 additions & 3 deletions test/test_requires.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ def test__requirement_find_lowest_possible(self, req, expected):
self.assertEqual(list(py2pack.requires._requirement_find_lowest_possible(pkg)), expected)

@data(
(["six", "monotonic>=0.1"], ["six", "monotonic >= 0.1"]),
(["monotonic>=1.0,>0.1"], ["monotonic > 0.1"]),
(["pywin32>=1.0;sys_platform=='win32' # PSF", "foobar>3"], ["foobar > 3"])
(["six", "monotonic>=0.1"], [["six"], ['monotonic', '>=', '0.1']]),
(["monotonic>=1.0,>0.1"], [['monotonic', '>', '0.1']]),
(["pywin32>=1.0;sys_platform=='win32' # PSF", "foobar>3"], [['foobar', '>', '3']])
)
@unpack
def test__requirements_sanitize(self, req_list, expected):
Expand Down