Skip to content

Commit 3ff5dd5

Browse files
authored
Merge pull request #233 from aboutcode-org/netrc-format-fix-pluplus
Netrc format fix pluplus
2 parents af339f8 + fe74b59 commit 3ff5dd5

14 files changed

+409
-300
lines changed

README.rst

Lines changed: 74 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@ python-inspector - inspect Python package dependencies and metadata
22
=====================================================================
33

44

5-
Copyright (c) nexB Inc. and others.
6-
SPDX-License-Identifier: Apache-2.0
7-
Homepage: https://github.com/aboutcode-org/python-inspector and https://www.aboutcode.org/
8-
95

106
``python-inspector`` is a collection of utilities to:
117

@@ -28,21 +24,21 @@ The goal of python-inspector is to be a comprehensive library
2824
that can handle every style of Python package layouts, manifests and lockfiles.
2925

3026

31-
Testing
32-
--------
27+
SPDX-License-Identifier: Apache-2.0
3328

34-
- Run the tests with::
29+
Copyright (c) AboutCode, nexB Inc. and others.
3530

36-
pytest -vvs
37-
38-
- There are live tests to regenerate the tests with updated data run::
31+
Homepage: https://github.com/aboutcode-org/python-inspector and https://www.aboutcode.org/
3932

40-
PYINSP_REGEN_TEST_FIXTURES=yes pytest -vvs
4133

4234
Usage
4335
--------
4436

45-
- Install with pip::
37+
- Install the stable release with pip from PyPI::
38+
39+
pip install python-inspector
40+
41+
- Or install the latest with pip::
4642

4743
pip install git+https://github.com/aboutcode-org/python-inspector
4844

@@ -51,8 +47,71 @@ Usage
5147
python-inspector --help
5248

5349

50+
Development
51+
--------------
52+
53+
Run::
54+
55+
git clone https://github.com/aboutcode-org/python-inspector
56+
57+
Create a virtual environment and install deps locally::
58+
59+
make dev
60+
source venv/bin/activate
61+
62+
63+
When in the virtual environment, run python-inspector from that clone::
64+
65+
python-inspector --help
66+
67+
68+
Run tests::
69+
70+
make test
71+
72+
Run code checks::
5473

55-
Its companion libraries are:
74+
make check
75+
76+
Run code formatting::
77+
78+
make valie
79+
80+
Check available make targets for further details
81+
82+
83+
84+
More testing
85+
------------------
86+
87+
- Run the tests with pytest::
88+
89+
pytest -vvs
90+
91+
- Or run them faster using 12 cores ::
92+
93+
pytest -vvs --numprocesses=12
94+
95+
96+
Regenerate test files
97+
-----------------------------
98+
99+
Some tests use live data from Pypi.org to run resolutions. When the package versions have
100+
changed, the resolution can change and some of the tests fail. We have an environment variable
101+
that regenerates the expected JSON result files when set.
102+
103+
To regenerate expected test result files for the failed tests, use this command::
104+
105+
PYINSP_REGEN_TEST_FIXTURES=yes pytest -vvs --lf
106+
107+
Then, carefully review the diff before committing the expected JSON test result files to validate
108+
that the changes are OK and mostly affect small changes in resolved package versions.
109+
110+
111+
Credits and dependencies
112+
---------------------------
113+
114+
For info, python-inspector embeds or depends on these libraries:
56115

57116
- ``pip-requirements-parser``, a mostly correct pip requirements parsing
58117
library extracted from pip.
@@ -72,6 +131,8 @@ Its companion libraries are:
72131

73132
- ``packageurl-python`` to use Package URL to reference Python packages
74133

134+
- ``scancode-toolkit`` for Python package manifest parsing.
135+
75136

76137

77138
Acknowledgements, Funding, Support and Sponsoring

src/python_inspector/utils.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,28 @@
1616
from typing import NamedTuple
1717
from typing import Optional
1818

19+
from urllib.parse import urlparse
20+
1921
import aiohttp
2022
import requests
2123

2224

2325
def get_netrc_auth(url, netrc):
2426
"""
25-
Return login and password if url is in netrc
27+
Return login and password if either the hostname is in netrc or a default is set in netrc
2628
else return login and password as None
2729
"""
30+
hostname = urlparse(url).hostname
2831
hosts = netrc.hosts
29-
if url in hosts:
30-
url_auth = hosts.get(url)
32+
if hostname in hosts:
33+
url_auth = hosts.get(hostname)
3134
# netrc returns a tuple of (login, account, password)
3235
return (url_auth[0], url_auth[2])
36+
37+
if "default" in hosts:
38+
default_auth = hosts.get("default")
39+
return (default_auth[0], default_auth[2])
40+
3341
return (None, None)
3442

3543

src/python_inspector/utils_pypi.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1598,6 +1598,10 @@ async def fetch_links(
15981598
name using the `index_url` of this repository.
15991599
"""
16001600
package_url = f"{self.index_url}/{normalized_name}"
1601+
1602+
if not package_url.endswith("/"):
1603+
package_url += "/"
1604+
16011605
text, _ = await CACHE.get(
16021606
path_or_url=package_url,
16031607
credentials=self.credentials,
@@ -1797,7 +1801,10 @@ async def get_remote_file_content(
17971801

17981802
auth = None
17991803
if credentials:
1800-
auth = (credentials.get("login"), credentials.get("password"))
1804+
login = credentials.get("login")
1805+
password = credentials.get("password")
1806+
if login and password:
1807+
auth = aiohttp.BasicAuth(login, password)
18011808

18021809
async with aiohttp.ClientSession() as session:
18031810
async with session.get(url, allow_redirects=True, headers=headers, auth=auth) as response:

tests/data/azure-devops.req-310-expected.json

Lines changed: 62 additions & 66 deletions
Large diffs are not rendered by default.

tests/data/azure-devops.req-312-expected.json

Lines changed: 62 additions & 66 deletions
Large diffs are not rendered by default.

tests/data/azure-devops.req-313-expected.json

Lines changed: 62 additions & 66 deletions
Large diffs are not rendered by default.

tests/data/azure-devops.req-38-expected.json

Lines changed: 52 additions & 56 deletions
Large diffs are not rendered by default.

tests/data/example-requirements-ignore-errors-expected.json

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
"headers": {
33
"tool_name": "python-inspector",
44
"tool_homepageurl": "https://github.com/aboutcode-org/python-inspector",
5-
"tool_version": "0.13.0",
65
"options": [
76
"--ignore-errors",
87
"--index-url https://pypi.org/simple",
@@ -356,12 +355,12 @@
356355
"type": "pypi",
357356
"namespace": null,
358357
"name": "pygments",
359-
"version": "2.19.1",
358+
"version": "2.19.2",
360359
"qualifiers": {},
361360
"subpath": null,
362361
"primary_language": "Python",
363362
"description": "Pygments\n~~~~~~~~\n\nPygments is a syntax highlighting package written in Python.\n\nIt is a generic syntax highlighter suitable for use in code hosting, forums,\nwikis or other applications that need to prettify source code. Highlights\nare:\n\n* a wide range of over 500 languages and other text formats is supported\n* special attention is paid to details, increasing quality by a fair amount\n* support for new languages and formats are added easily\n* a number of output formats, presently HTML, LaTeX, RTF, SVG, all image\n formats that PIL supports and ANSI sequences\n* it is usable as a command-line tool and as a library\n\nCopyright 2006-2025 by the Pygments team, see ``AUTHORS``.\nLicensed under the BSD, see ``LICENSE`` for details.",
364-
"release_date": "2025-01-06T17:26:25",
363+
"release_date": "2025-06-21T13:39:07",
365364
"parties": [
366365
{
367366
"type": "person",
@@ -399,11 +398,11 @@
399398
"Topic :: Utilities"
400399
],
401400
"homepage_url": null,
402-
"download_url": "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl",
403-
"size": 1225293,
401+
"download_url": "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl",
402+
"size": 1225217,
404403
"sha1": null,
405-
"md5": "794747e68f6a2c85e86a8a49e4abb285",
406-
"sha256": "9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c",
404+
"md5": "c6f882e4a4ffd8543f245d4f7ce0d7fa",
405+
"sha256": "86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b",
407406
"sha512": null,
408407
"bug_tracking_url": "https://github.com/pygments/pygments/issues",
409408
"code_view_url": "https://github.com/pygments/pygments",
@@ -423,20 +422,20 @@
423422
"dependencies": [],
424423
"repository_homepage_url": null,
425424
"repository_download_url": null,
426-
"api_data_url": "https://pypi.org/pypi/pygments/2.19.1/json",
425+
"api_data_url": "https://pypi.org/pypi/pygments/2.19.2/json",
427426
"datasource_id": null,
428-
"purl": "pkg:pypi/[email protected].1"
427+
"purl": "pkg:pypi/[email protected].2"
429428
},
430429
{
431430
"type": "pypi",
432431
"namespace": null,
433432
"name": "pytest",
434-
"version": "8.4.0",
433+
"version": "8.4.1",
435434
"qualifiers": {},
436435
"subpath": null,
437436
"primary_language": "Python",
438437
"description": "pytest: simple powerful testing with Python\n.. image:: https://github.com/pytest-dev/pytest/raw/main/doc/en/img/pytest_logo_curves.svg\n :target: https://docs.pytest.org/en/stable/\n :align: center\n :height: 200\n :alt: pytest\n\n\n------\n\n.. image:: https://img.shields.io/pypi/v/pytest.svg\n :target: https://pypi.org/project/pytest/\n\n.. image:: https://img.shields.io/conda/vn/conda-forge/pytest.svg\n :target: https://anaconda.org/conda-forge/pytest\n\n.. image:: https://img.shields.io/pypi/pyversions/pytest.svg\n :target: https://pypi.org/project/pytest/\n\n.. image:: https://codecov.io/gh/pytest-dev/pytest/branch/main/graph/badge.svg\n :target: https://codecov.io/gh/pytest-dev/pytest\n :alt: Code coverage Status\n\n.. image:: https://github.com/pytest-dev/pytest/actions/workflows/test.yml/badge.svg\n :target: https://github.com/pytest-dev/pytest/actions?query=workflow%3Atest\n\n.. image:: https://results.pre-commit.ci/badge/github/pytest-dev/pytest/main.svg\n :target: https://results.pre-commit.ci/latest/github/pytest-dev/pytest/main\n :alt: pre-commit.ci status\n\n.. image:: https://www.codetriage.com/pytest-dev/pytest/badges/users.svg\n :target: https://www.codetriage.com/pytest-dev/pytest\n\n.. image:: https://readthedocs.org/projects/pytest/badge/?version=latest\n :target: https://pytest.readthedocs.io/en/latest/?badge=latest\n :alt: Documentation Status\n\n.. image:: https://img.shields.io/badge/Discord-pytest--dev-blue\n :target: https://discord.com/invite/pytest-dev\n :alt: Discord\n\n.. image:: https://img.shields.io/badge/Libera%20chat-%23pytest-orange\n :target: https://web.libera.chat/#pytest\n :alt: Libera chat\n\n\nThe ``pytest`` framework makes it easy to write small tests, yet\nscales to support complex functional testing for applications and libraries.\n\nAn example of a simple test:\n\n.. code-block:: python\n\n # content of test_sample.py\n def inc(x):\n return x + 1\n\n\n def test_answer():\n assert inc(3) == 5\n\n\nTo execute it::\n\n $ pytest\n ============================= test session starts =============================\n collected 1 items\n\n test_sample.py F\n\n ================================== FAILURES ===================================\n _________________________________ test_answer _________________________________\n\n def test_answer():\n > assert inc(3) == 5\n E assert 4 == 5\n E + where 4 = inc(3)\n\n test_sample.py:5: AssertionError\n ========================== 1 failed in 0.04 seconds ===========================\n\n\nDue to ``pytest``'s detailed assertion introspection, only plain ``assert`` statements are used. See `getting-started <https://docs.pytest.org/en/stable/getting-started.html#our-first-test-run>`_ for more examples.\n\n\nFeatures\n--------\n\n- Detailed info on failing `assert statements <https://docs.pytest.org/en/stable/how-to/assert.html>`_ (no need to remember ``self.assert*`` names)\n\n- `Auto-discovery\n <https://docs.pytest.org/en/stable/explanation/goodpractices.html#python-test-discovery>`_\n of test modules and functions\n\n- `Modular fixtures <https://docs.pytest.org/en/stable/explanation/fixtures.html>`_ for\n managing small or parametrized long-lived test resources\n\n- Can run `unittest <https://docs.pytest.org/en/stable/how-to/unittest.html>`_ (or trial)\n test suites out of the box\n\n- Python 3.9+ or PyPy3\n\n- Rich plugin architecture, with over 1300+ `external plugins <https://docs.pytest.org/en/latest/reference/plugin_list.html>`_ and thriving community\n\n\nDocumentation\n-------------\n\nFor full documentation, including installation, tutorials and PDF documents, please see https://docs.pytest.org/en/stable/.\n\n\nBugs/Requests\n-------------\n\nPlease use the `GitHub issue tracker <https://github.com/pytest-dev/pytest/issues>`_ to submit bugs or request features.\n\n\nChangelog\n---------\n\nConsult the `Changelog <https://docs.pytest.org/en/stable/changelog.html>`__ page for fixes and enhancements of each version.\n\n\nSupport pytest\n--------------\n\n`Open Collective`_ is an online funding platform for open and transparent communities.\nIt provides tools to raise money and share your finances in full transparency.\n\nIt is the platform of choice for individuals and companies that want to make one-time or\nmonthly donations directly to the project.\n\nSee more details in the `pytest collective`_.\n\n.. _Open Collective: https://opencollective.com\n.. _pytest collective: https://opencollective.com/pytest\n\n\npytest for enterprise\n---------------------\n\nAvailable as part of the Tidelift Subscription.\n\nThe maintainers of pytest and thousands of other packages are working with Tidelift to deliver commercial support and\nmaintenance for the open source dependencies you use to build your applications.\nSave time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use.\n\n`Learn more. <https://tidelift.com/subscription/pkg/pypi-pytest?utm_source=pypi-pytest&utm_medium=referral&utm_campaign=enterprise&utm_term=repo>`_\n\nSecurity\n^^^^^^^^\n\npytest has never been associated with a security vulnerability, but in any case, to report a\nsecurity vulnerability please use the `Tidelift security contact <https://tidelift.com/security>`_.\nTidelift will coordinate the fix and disclosure.\n\n\nLicense\n-------\n\nCopyright Holger Krekel and others, 2004.\n\nDistributed under the terms of the `MIT`_ license, pytest is free and open source software.\n\n.. _`MIT`: https://github.com/pytest-dev/pytest/blob/main/LICENSE",
439-
"release_date": "2025-06-02T17:36:27",
438+
"release_date": "2025-06-18T05:48:03",
440439
"parties": [
441440
{
442441
"type": "person",
@@ -467,11 +466,11 @@
467466
"Topic :: Utilities"
468467
],
469468
"homepage_url": null,
470-
"download_url": "https://files.pythonhosted.org/packages/2f/de/afa024cbe022b1b318a3d224125aa24939e99b4ff6f22e0ba639a2eaee47/pytest-8.4.0-py3-none-any.whl",
471-
"size": 363797,
469+
"download_url": "https://files.pythonhosted.org/packages/29/16/c8a903f4c4dffe7a12843191437d7cd8e32751d5de349d45d3fe69544e87/pytest-8.4.1-py3-none-any.whl",
470+
"size": 365474,
472471
"sha1": null,
473-
"md5": "e3ae70dc3edd90a392d9061ba2c8d6e6",
474-
"sha256": "f40f825768ad76c0977cbacdf1fd37c6f7a468e460ea6a0636078f8972d4517e",
472+
"md5": "6ad4ee79caee224776d07f155d91b7e7",
473+
"sha256": "539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7",
475474
"sha512": null,
476475
"bug_tracking_url": "https://github.com/pytest-dev/pytest/issues",
477476
"code_view_url": "https://github.com/pytest-dev/pytest",
@@ -491,9 +490,9 @@
491490
"dependencies": [],
492491
"repository_homepage_url": null,
493492
"repository_download_url": null,
494-
"api_data_url": "https://pypi.org/pypi/pytest/8.4.0/json",
493+
"api_data_url": "https://pypi.org/pypi/pytest/8.4.1/json",
495494
"datasource_id": null,
496-
"purl": "pkg:pypi/[email protected].0"
495+
"purl": "pkg:pypi/[email protected].1"
497496
},
498497
{
499498
"type": "pypi",
@@ -649,17 +648,17 @@
649648
"dependencies": []
650649
},
651650
{
652-
"package": "pkg:pypi/[email protected].1",
651+
"package": "pkg:pypi/[email protected].2",
653652
"dependencies": []
654653
},
655654
{
656-
"package": "pkg:pypi/[email protected].0",
655+
"package": "pkg:pypi/[email protected].1",
657656
"dependencies": [
658657
"pkg:pypi/[email protected]",
659658
"pkg:pypi/[email protected]",
660659
"pkg:pypi/[email protected]",
661660
"pkg:pypi/[email protected]",
662-
"pkg:pypi/[email protected].1",
661+
"pkg:pypi/[email protected].2",
663662
"pkg:pypi/[email protected]"
664663
]
665664
},

tests/data/resolved_deps/autobahn-310-expected.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"pkg:pypi/[email protected]",
77
"pkg:pypi/[email protected]",
88
"pkg:pypi/[email protected]",
9-
"pkg:pypi/txaio@23.1.1"
9+
"pkg:pypi/txaio@23.6.1"
1010
]
1111
},
1212
{
@@ -40,7 +40,7 @@
4040
"dependencies": []
4141
},
4242
{
43-
"package": "pkg:pypi/txaio@23.1.1",
43+
"package": "pkg:pypi/txaio@23.6.1",
4444
"dependencies": []
4545
}
4646
],
@@ -52,6 +52,6 @@
5252
"pkg:pypi/[email protected]",
5353
"pkg:pypi/[email protected]",
5454
"pkg:pypi/[email protected]",
55-
"pkg:pypi/txaio@23.1.1"
55+
"pkg:pypi/txaio@23.6.1"
5656
]
5757
]

tests/data/resolved_deps/flask-39-expected.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
{
1818
"package": "pkg:pypi/[email protected]",
1919
"dependencies": [
20-
"pkg:pypi/zipp@3.22.0"
20+
"pkg:pypi/zipp@3.23.0"
2121
]
2222
},
2323
{
@@ -41,7 +41,7 @@
4141
]
4242
},
4343
{
44-
"package": "pkg:pypi/zipp@3.22.0",
44+
"package": "pkg:pypi/zipp@3.23.0",
4545
"dependencies": []
4646
}
4747
],
@@ -53,6 +53,6 @@
5353
"pkg:pypi/[email protected]",
5454
"pkg:pypi/[email protected]",
5555
"pkg:pypi/[email protected]",
56-
"pkg:pypi/zipp@3.22.0"
56+
"pkg:pypi/zipp@3.23.0"
5757
]
5858
]

0 commit comments

Comments
 (0)