From 263528102e9a282adddbc17a22ed2c4e3df2de75 Mon Sep 17 00:00:00 2001 From: Corey Hickey Date: Wed, 28 Jul 2021 15:58:49 -0700 Subject: [PATCH] fix inconsistent naming between packages and dependencies This works around: https://github.com/pypa/setuptools/issues/2522 For example, when building a module which depends on 'backports_abc', fpm will currently translate that into a dependency on 'backports-abc'. When building the 'backports_abc' module, fpm will currently retain the original name. Thus, it is not possible to use fpm to meet some dependencies. Underscores should be allowed in package names, but the most important thing is to be internally consistent. Monkey-patch pkg_resources.safe_name() in order to allow underscores (default for fpm) or disallow underscores, according to user specification. If and when pkg_resources fixes safe_name(), then the behavior of fpm will remain the same. Note that this change matches both methods of loading requirements: * for setup.py, setuptools internally calls pkg_resources.safe_name() * for requirements.txt, pkg_resources uses its own safe_name() --- lib/fpm/package/pyfpm/get_metadata.py | 7 +++++-- lib/fpm/package/python.rb | 6 ++++++ lib/fpm/package/python_patch.py | 23 +++++++++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/lib/fpm/package/pyfpm/get_metadata.py b/lib/fpm/package/pyfpm/get_metadata.py index 89a803a502..c91ef95877 100644 --- a/lib/fpm/package/pyfpm/get_metadata.py +++ b/lib/fpm/package/pyfpm/get_metadata.py @@ -32,13 +32,16 @@ def u(s): class get_metadata(Command): description = "get package metadata" user_options = [ + ('allow-underscores', 'a', 'allow underscores in package names/deps'), ('load-requirements-txt', 'l', "load dependencies from requirements.txt"), ("output=", "o", "output destination for metadata json") ] - boolean_options = ['load-requirements-txt'] + boolean_options = ['allow-underscores', 'load-requirements-txt'] def initialize_options(self): + # allow-underscores is handled in python_patch.py; this is ignored here + self.allow_underscores = False self.load_requirements_txt = False self.cwd = None self.output = None @@ -68,7 +71,7 @@ def process_dep(self, dep): def run(self): data = { - "name": self.distribution.get_name(), + "name": pkg_resources.safe_name(self.distribution.get_name()), "version": self.distribution.get_version(), "author": u("%s <%s>") % ( u(self.distribution.get_author()), diff --git a/lib/fpm/package/python.rb b/lib/fpm/package/python.rb index 2f603e5066..f79de266ed 100644 --- a/lib/fpm/package/python.rb +++ b/lib/fpm/package/python.rb @@ -19,6 +19,8 @@ # class FPM::Package::Python < FPM::Package # Flags '--foo' will be accessable as attributes[:python_foo] + option "--allow-underscores", :flag, "Should underscores be allowed in " \ + " package names and dependencies?", :default => true option "--bin", "PYTHON_EXECUTABLE", "The path to the python executable you wish to run.", :default => "python" option "--easyinstall", "EASYINSTALL_EXECUTABLE", @@ -213,6 +215,10 @@ def load_package_info(setup_py) setup_cmd = "env PYTHONPATH=#{pylib}:$PYTHONPATH #{attributes[:python_bin]} " \ "#{pylib}/python_patch.py --command-packages=pyfpm get_metadata --output=#{tmp}" + if attributes[:python_allow_underscores?] + setup_cmd += " --allow-underscores" + end + if attributes[:python_obey_requirements_txt?] setup_cmd += " --load-requirements-txt" end diff --git a/lib/fpm/package/python_patch.py b/lib/fpm/package/python_patch.py index a8f3e39013..134ea05389 100755 --- a/lib/fpm/package/python_patch.py +++ b/lib/fpm/package/python_patch.py @@ -1,4 +1,27 @@ +import pkg_resources +import re +import sys from setuptools.dist import Distribution + + +def gen_safe_name(allow_underscores): + if allow_underscores: + regex = '[^A-Za-z0-9_.]+' + else: + # This matches the original verion in pkg_resources. + regex = '[^A-Za-z0-9.]+' + + def safe_name(name): + return re.sub(regex, '-', name) + + return safe_name + + +# Use simple argument parsing--older python lacks argparse and optparse has no +# good way to ignore unrecognized options (which need to be passed through). +pkg_resources.safe_name = gen_safe_name('--allow-underscores' in sys.argv) + + try: # Many older modules include a setup.py that uses distutils.core, which # does not support the install_requires attribute. Monkey-patch