Skip to content
This repository was archived by the owner on Aug 7, 2025. It is now read-only.

Commit 41946d5

Browse files
author
William Douglas
committed
Add the Provide: pypi in most cases
Usually the pypi ecosystem will do the right thing and respond with a name but in cases where it does not (bad network, bad json, message without a name), still figure out a reasonable Provide to add. Signed-off-by: William Douglas <william.douglas@intel.com>
1 parent 99a7985 commit 41946d5

3 files changed

Lines changed: 110 additions & 9 deletions

File tree

autospec/buildreq.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -709,23 +709,28 @@ def get_data_from_pypi(self, name, config):
709709
"""Use pypi for getting package requires and metadata."""
710710
# First look for a local override
711711
pypi_json = ""
712+
pypi_name = pypidata.get_pypi_name(name)
712713
pypi_file = os.path.join(config.download_path, "pypi.json")
713714
if os.path.isfile(pypi_file):
714715
with open(pypi_file, "r") as pfile:
715716
pypi_json = pfile.read()
716717
else:
717718
# Try and grab the pypi details for the package
718719
if config.alias:
719-
name = config.alias
720-
pypi_name = pypidata.get_pypi_name(name)
720+
pypi_name = config.alias
721+
pypi_name = pypidata.get_pypi_name(pypi_name)
721722
pypi_json = pypidata.get_pypi_metadata(pypi_name)
722-
if pypi_json:
723+
if not pypi_json:
724+
self.pypi_provides = pypi_name
725+
else:
723726
try:
724727
package_pypi = json.loads(pypi_json)
725728
except json.JSONDecodeError:
726-
package_pypi = {}
729+
package_pypi = {"name": pypi_name}
727730
if package_pypi.get("name"):
728731
self.pypi_provides = package_pypi["name"]
732+
else:
733+
self.pypi_provides = pypi_name
729734
if package_pypi.get("requires"):
730735
for pkg in package_pypi["requires"]:
731736
self.add_requires(f"pypi({pkg})", config.os_packages, override=True, subpkg="python3")

autospec/pypidata.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ def pkg_search(name):
2727
return False
2828

2929

30+
def fixup_pypi_prefix(name):
31+
"""Try and chop off the 'pypi-' or 'python-' prefix for names"""
32+
name = name.lower().replace('-', '_')
33+
for prefix in ["pypi_", "python_"]:
34+
if name.startswith(prefix):
35+
name = name[len(prefix):]
36+
return name
37+
38+
3039
def get_pypi_name(name, miss=False):
3140
"""Try and verify the pypi name for a given package name."""
3241
# normalize the name for matching as pypi is case insensitve for search
@@ -35,11 +44,9 @@ def get_pypi_name(name, miss=False):
3544
if pkg_search(name):
3645
return name
3746
# Maybe we have a prefix
38-
for prefix in ["pypi_", "python_"]:
39-
if name.startswith(prefix):
40-
name = name[len(prefix):]
41-
if pkg_search(name):
42-
return name
47+
name = fixup_pypi_prefix(name)
48+
if pkg_search(name):
49+
return name
4350
# Some cases where search fails (Sphinx)
4451
# Just try the name we were given
4552
if miss:

tests/test_buildreq.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,95 @@ def test_scan_for_configure_pypi(self):
499499
self.assertEqual(self.reqs.requires['python3'], pypi_requires)
500500
self.assertEqual(ssummary, summary)
501501

502+
def test_scan_for_configure_pypi_no_name_in_json(self):
503+
"""
504+
Test scan_for_configure when distutils is being used for the build
505+
pattern to test connecting to pypi but not getting a name back.
506+
"""
507+
orig_summary = buildreq.specdescription.default_summary
508+
orig_sscore = buildreq.specdescription.default_summary_score
509+
orig_pypi_name = buildreq.pypidata.get_pypi_name
510+
orig_pypi_meta = buildreq.pypidata.get_pypi_metadata
511+
name = "pypi-name"
512+
content = json.dumps({})
513+
buildreq.pypidata.pkg_search = MagicMock(return_value=False)
514+
buildreq.pypidata.get_pypi_metadata = MagicMock(return_value=content)
515+
with tempfile.TemporaryDirectory() as tmpd:
516+
conf = config.Config(tmpd)
517+
conf.config_opts['use_ninja'] = False
518+
os.mkdir(os.path.join(tmpd, 'subdir'))
519+
open(os.path.join(tmpd, 'subdir', 'pyproject.toml'), 'w').close()
520+
self.reqs.scan_for_configure(os.path.join(tmpd, 'subdir'), name, conf)
521+
522+
post_summary = buildreq.specdescription.default_summary
523+
buildreq.specdescription.default_summary = orig_summary
524+
buildreq.specdescription.default_summary_score = orig_sscore
525+
buildreq.pypidata.get_pypi_name = orig_pypi_name
526+
buildreq.pypidata.get_pypi_metadata = orig_pypi_meta
527+
528+
self.assertEqual(self.reqs.pypi_provides, "name")
529+
self.assertEqual(post_summary, orig_summary)
530+
531+
def test_scan_for_configure_pypi_no_json(self):
532+
"""
533+
Test scan_for_configure when distutils is being used for the build
534+
pattern to test being unable to connect to pypi.
535+
"""
536+
orig_summary = buildreq.specdescription.default_summary
537+
orig_sscore = buildreq.specdescription.default_summary_score
538+
orig_pypi_name = buildreq.pypidata.get_pypi_name
539+
orig_pypi_meta = buildreq.pypidata.get_pypi_metadata
540+
name = "pypi-name"
541+
buildreq.pypidata.pkg_search = MagicMock(return_value=False)
542+
buildreq.pypidata.get_pypi_metadata = MagicMock(return_value="")
543+
with tempfile.TemporaryDirectory() as tmpd:
544+
conf = config.Config(tmpd)
545+
conf.config_opts['use_ninja'] = False
546+
os.mkdir(os.path.join(tmpd, 'subdir'))
547+
open(os.path.join(tmpd, 'subdir', 'pyproject.toml'), 'w').close()
548+
self.reqs.scan_for_configure(os.path.join(tmpd, 'subdir'), name, conf)
549+
550+
post_summary = buildreq.specdescription.default_summary
551+
buildreq.specdescription.default_summary = orig_summary
552+
buildreq.specdescription.default_summary_score = orig_sscore
553+
buildreq.pypidata.get_pypi_name = orig_pypi_name
554+
buildreq.pypidata.get_pypi_metadata = orig_pypi_meta
555+
556+
self.assertEqual(self.reqs.pypi_provides, "name")
557+
self.assertEqual(post_summary, orig_summary)
558+
559+
def test_scan_for_configure_pypi_bad_json(self):
560+
"""
561+
Test scan_for_configure when distutils is being used for the build
562+
pattern to test being given bad json data.
563+
"""
564+
orig_summary = buildreq.specdescription.default_summary
565+
orig_sscore = buildreq.specdescription.default_summary_score
566+
orig_pypi_name = buildreq.pypidata.get_pypi_name
567+
orig_pypi_meta = buildreq.pypidata.get_pypi_metadata
568+
orig_json_loads = buildreq.json.loads
569+
name = "pypi-name"
570+
content = json.dumps({})
571+
buildreq.pypidata.pkg_search = MagicMock(return_value=False)
572+
buildreq.pypidata.get_pypi_metadata = MagicMock(return_value=content)
573+
buildreq.json.loads = MagicMock(side_effect=json.JSONDecodeError("", "", 0))
574+
with tempfile.TemporaryDirectory() as tmpd:
575+
conf = config.Config(tmpd)
576+
conf.config_opts['use_ninja'] = False
577+
os.mkdir(os.path.join(tmpd, 'subdir'))
578+
open(os.path.join(tmpd, 'subdir', 'pyproject.toml'), 'w').close()
579+
self.reqs.scan_for_configure(os.path.join(tmpd, 'subdir'), name, conf)
580+
581+
post_summary = buildreq.specdescription.default_summary
582+
buildreq.specdescription.default_summary = orig_summary
583+
buildreq.specdescription.default_summary_score = orig_sscore
584+
buildreq.pypidata.get_pypi_name = orig_pypi_name
585+
buildreq.pypidata.get_pypi_metadata = orig_pypi_meta
586+
buildreq.json.loads = orig_json_loads
587+
588+
self.assertEqual(self.reqs.pypi_provides, "name")
589+
self.assertEqual(post_summary, orig_summary)
590+
502591
def test_scan_for_configure_pypi_override(self):
503592
"""
504593
Test scan_for_configure when distutils is being used for the build

0 commit comments

Comments
 (0)