diff --git a/pkg/python/packaging/parse.go b/pkg/python/packaging/parse.go index 09889e29..6219e751 100644 --- a/pkg/python/packaging/parse.go +++ b/pkg/python/packaging/parse.go @@ -4,6 +4,7 @@ import ( "bufio" "io" "net/textproto" + "strings" "golang.org/x/xerrors" @@ -26,11 +27,31 @@ func (*Parser) Parse(r dio.ReadSeekerAt) ([]types.Library, []types.Dependency, e return nil, nil, xerrors.Errorf("read MIME error: %w", err) } + // "License-Expression" takes precedence as "License" is deprecated. + // cf. https://peps.python.org/pep-0639/#deprecate-license-field + var license string + if l := h.Get("License-Expression"); l != "" { + license = l + } else if l := h.Get("License"); l != "" { + license = l + } else { + for _, classifier := range h.Values("Classifier") { + if strings.HasPrefix(classifier, "License :: ") { + values := strings.Split(classifier, " :: ") + license = values[len(values)-1] + break + } + } + } + if license == "" && h.Get("License-File") != "" { + license = "file://" + h.Get("License-File") + } + return []types.Library{ { Name: h.Get("Name"), Version: h.Get("Version"), - License: h.Get("License"), + License: license, }, }, nil, nil } diff --git a/pkg/python/packaging/parse_test.go b/pkg/python/packaging/parse_test.go index 7eda24dd..50cb1abc 100644 --- a/pkg/python/packaging/parse_test.go +++ b/pkg/python/packaging/parse_test.go @@ -72,6 +72,39 @@ func TestParse(t *testing.T) { input: "testdata/invalid.json", wantErr: true, }, + { + name: "with License-Expression field", + input: "testdata/iniconfig-2.0.0.METADATA", + want: []types.Library{ + { + Name: "iniconfig", + Version: "2.0.0", + License: "MIT", + }, + }, + }, + { + name: "with an empty license field but with license in Classifier", + input: "testdata/zipp-3.12.1.METADATA", + want: []types.Library{ + { + Name: "zipp", + Version: "3.12.1", + License: "MIT License", + }, + }, + }, + { + name: "without licenses, but with a license file (a license in Classifier was removed)", + input: "testdata/networkx-3.0.METADATA", + want: []types.Library{ + { + Name: "networkx", + Version: "3.0", + License: "file://LICENSE.txt", + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/python/packaging/testdata/iniconfig-2.0.0.METADATA b/pkg/python/packaging/testdata/iniconfig-2.0.0.METADATA new file mode 100644 index 00000000..3ea1e01c --- /dev/null +++ b/pkg/python/packaging/testdata/iniconfig-2.0.0.METADATA @@ -0,0 +1,80 @@ +Metadata-Version: 2.1 +Name: iniconfig +Version: 2.0.0 +Summary: brain-dead simple config-ini parsing +Project-URL: Homepage, https://github.com/pytest-dev/iniconfig +Author-email: Ronny Pfannschmidt , Holger Krekel +License-Expression: MIT +License-File: LICENSE +Classifier: Development Status :: 4 - Beta +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Operating System :: Microsoft :: Windows +Classifier: Operating System :: POSIX +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Topic :: Software Development :: Libraries +Classifier: Topic :: Utilities +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst + +iniconfig: brain-dead simple parsing of ini files +======================================================= + +iniconfig is a small and simple INI-file parser module +having a unique set of features: + +* maintains order of sections and entries +* supports multi-line values with or without line-continuations +* supports "#" comments everywhere +* raises errors with proper line-numbers +* no bells and whistles like automatic substitutions +* iniconfig raises an Error if two sections have the same name. + +If you encounter issues or have feature wishes please report them to: + + https://github.com/RonnyPfannschmidt/iniconfig/issues + +Basic Example +=================================== + +If you have an ini file like this: + +.. code-block:: ini + + # content of example.ini + [section1] # comment + name1=value1 # comment + name1b=value1,value2 # comment + + [section2] + name2= + line1 + line2 + +then you can do: + +.. code-block:: pycon + + >>> import iniconfig + >>> ini = iniconfig.IniConfig("example.ini") + >>> ini['section1']['name1'] # raises KeyError if not exists + 'value1' + >>> ini.get('section1', 'name1b', [], lambda x: x.split(",")) + ['value1', 'value2'] + >>> ini.get('section1', 'notexist', [], lambda x: x.split(",")) + [] + >>> [x.name for x in list(ini)] + ['section1', 'section2'] + >>> list(list(ini)[0].items()) + [('name1', 'value1'), ('name1b', 'value1,value2')] + >>> 'section1' in ini + True + >>> 'inexistendsection' in ini + False diff --git a/pkg/python/packaging/testdata/networkx-3.0.METADATA b/pkg/python/packaging/testdata/networkx-3.0.METADATA new file mode 100644 index 00000000..ad434a20 --- /dev/null +++ b/pkg/python/packaging/testdata/networkx-3.0.METADATA @@ -0,0 +1,132 @@ +Metadata-Version: 2.1 +Name: networkx +Version: 3.0 +Summary: Python package for creating and manipulating graphs and networks +Home-page: https://networkx.org/ +Author: Aric Hagberg +Author-email: hagberg@lanl.gov +Maintainer: NetworkX Developers +Maintainer-email: networkx-discuss@googlegroups.com +Project-URL: Bug Tracker, https://github.com/networkx/networkx/issues +Project-URL: Documentation, https://networkx.org/documentation/stable/ +Project-URL: Source Code, https://github.com/networkx/networkx +Keywords: Networks,Graph Theory,Mathematics,network,graph,discrete mathematics,math +Platform: Linux +Platform: Mac OSX +Platform: Windows +Platform: Unix +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Intended Audience :: Science/Research +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Scientific/Engineering :: Bio-Informatics +Classifier: Topic :: Scientific/Engineering :: Information Analysis +Classifier: Topic :: Scientific/Engineering :: Mathematics +Classifier: Topic :: Scientific/Engineering :: Physics +Requires-Python: >=3.8 +License-File: LICENSE.txt +Provides-Extra: default +Requires-Dist: numpy (>=1.20) ; extra == 'default' +Requires-Dist: scipy (>=1.8) ; extra == 'default' +Requires-Dist: matplotlib (>=3.4) ; extra == 'default' +Requires-Dist: pandas (>=1.3) ; extra == 'default' +Provides-Extra: developer +Requires-Dist: pre-commit (>=2.20) ; extra == 'developer' +Requires-Dist: mypy (>=0.991) ; extra == 'developer' +Provides-Extra: doc +Requires-Dist: sphinx (==5.2.3) ; extra == 'doc' +Requires-Dist: pydata-sphinx-theme (>=0.11) ; extra == 'doc' +Requires-Dist: sphinx-gallery (>=0.11) ; extra == 'doc' +Requires-Dist: numpydoc (>=1.5) ; extra == 'doc' +Requires-Dist: pillow (>=9.2) ; extra == 'doc' +Requires-Dist: nb2plots (>=0.6) ; extra == 'doc' +Requires-Dist: texext (>=0.6.7) ; extra == 'doc' +Provides-Extra: extra +Requires-Dist: lxml (>=4.6) ; extra == 'extra' +Requires-Dist: pygraphviz (>=1.10) ; extra == 'extra' +Requires-Dist: pydot (>=1.4.2) ; extra == 'extra' +Requires-Dist: sympy (>=1.10) ; extra == 'extra' +Provides-Extra: test +Requires-Dist: pytest (>=7.2) ; extra == 'test' +Requires-Dist: pytest-cov (>=4.0) ; extra == 'test' +Requires-Dist: codecov (>=2.1) ; extra == 'test' + +NetworkX +======== + +.. image:: https://github.com/networkx/networkx/workflows/test/badge.svg?tag=networkx-3.0 + :target: https://github.com/networkx/networkx/actions?query=branch%3Anetworkx-3.0 + +.. image:: https://codecov.io/gh/networkx/networkx/branch/main/graph/badge.svg + :target: https://app.codecov.io/gh/networkx/networkx/branch/main + +.. image:: https://img.shields.io/github/labels/networkx/networkx/Good%20First%20Issue?color=green&label=Contribute%20&style=flat-square + :target: https://github.com/networkx/networkx/issues?q=is%3Aopen+is%3Aissue+label%3A%22Good+First+Issue%22 + + +NetworkX is a Python package for the creation, manipulation, +and study of the structure, dynamics, and functions +of complex networks. + +- **Website (including documentation):** https://networkx.org +- **Mailing list:** https://groups.google.com/forum/#!forum/networkx-discuss +- **Source:** https://github.com/networkx/networkx +- **Bug reports:** https://github.com/networkx/networkx/issues +- **Report a security vulnerability:** https://tidelift.com/security +- **Tutorial:** https://networkx.org/documentation/latest/tutorial.html +- **GitHub Discussions:** https://github.com/networkx/networkx/discussions + +Simple example +-------------- + +Find the shortest path between two nodes in an undirected graph: + +.. code:: pycon + + >>> import networkx as nx + >>> G = nx.Graph() + >>> G.add_edge("A", "B", weight=4) + >>> G.add_edge("B", "D", weight=2) + >>> G.add_edge("A", "C", weight=3) + >>> G.add_edge("C", "D", weight=4) + >>> nx.shortest_path(G, "A", "D", weight="weight") + ['A', 'B', 'D'] + +Install +------- + +Install the latest version of NetworkX:: + + $ pip install networkx + +Install with all optional dependencies:: + + $ pip install networkx[all] + +For additional details, please see `INSTALL.rst`. + +Bugs +---- + +Please report any bugs that you find `here `_. +Or, even better, fork the repository on `GitHub `_ +and create a pull request (PR). We welcome all changes, big or small, and we +will help you make the PR if you are new to `git` (just ask on the issue and/or +see `CONTRIBUTING.rst`). + +License +------- + +Released under the 3-Clause BSD license (see `LICENSE.txt`):: + + Copyright (C) 2004-2023 NetworkX Developers + Aric Hagberg + Dan Schult + Pieter Swart diff --git a/pkg/python/packaging/testdata/zipp-3.12.1.METADATA b/pkg/python/packaging/testdata/zipp-3.12.1.METADATA new file mode 100644 index 00000000..142b8d07 --- /dev/null +++ b/pkg/python/packaging/testdata/zipp-3.12.1.METADATA @@ -0,0 +1,106 @@ +Metadata-Version: 2.1 +Name: zipp +Version: 3.12.1 +Summary: Backport of pathlib-compatible object wrapper for zip files +Home-page: https://github.com/jaraco/zipp +Author: Jason R. Coombs +Author-email: jaraco@jaraco.com +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Requires-Python: >=3.7 +License-File: LICENSE +Provides-Extra: docs +Requires-Dist: sphinx (>=3.5) ; extra == 'docs' +Requires-Dist: jaraco.packaging (>=9) ; extra == 'docs' +Requires-Dist: rst.linker (>=1.9) ; extra == 'docs' +Requires-Dist: furo ; extra == 'docs' +Requires-Dist: sphinx-lint ; extra == 'docs' +Requires-Dist: jaraco.tidelift (>=1.4) ; extra == 'docs' +Provides-Extra: testing +Requires-Dist: pytest (>=6) ; extra == 'testing' +Requires-Dist: pytest-checkdocs (>=2.4) ; extra == 'testing' +Requires-Dist: flake8 (<5) ; extra == 'testing' +Requires-Dist: pytest-cov ; extra == 'testing' +Requires-Dist: pytest-enabler (>=1.3) ; extra == 'testing' +Requires-Dist: jaraco.itertools ; extra == 'testing' +Requires-Dist: func-timeout ; extra == 'testing' +Requires-Dist: jaraco.functools ; extra == 'testing' +Requires-Dist: more-itertools ; extra == 'testing' +Requires-Dist: pytest-black (>=0.3.7) ; (platform_python_implementation != "PyPy") and extra == 'testing' +Requires-Dist: pytest-mypy (>=0.9.1) ; (platform_python_implementation != "PyPy") and extra == 'testing' +Requires-Dist: pytest-flake8 ; (python_version < "3.12") and extra == 'testing' + +.. image:: https://img.shields.io/pypi/v/zipp.svg + :target: https://pypi.org/project/zipp + +.. image:: https://img.shields.io/pypi/pyversions/zipp.svg + +.. image:: https://github.com/jaraco/zipp/workflows/tests/badge.svg + :target: https://github.com/jaraco/zipp/actions?query=workflow%3A%22tests%22 + :alt: tests + +.. image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/psf/black + :alt: Code style: Black + +.. .. image:: https://readthedocs.org/projects/skeleton/badge/?version=latest +.. :target: https://skeleton.readthedocs.io/en/latest/?badge=latest + +.. image:: https://img.shields.io/badge/skeleton-2023-informational + :target: https://blog.jaraco.com/skeleton + +.. image:: https://tidelift.com/badges/package/pypi/zipp + :target: https://tidelift.com/subscription/pkg/pypi-zipp?utm_source=pypi-zipp&utm_medium=readme + + +A pathlib-compatible Zipfile object wrapper. Official backport of the standard library +`Path object `_. + + +Compatibility +============= + +New features are introduced in this third-party library and later merged +into CPython. The following table indicates which versions of this library +were contributed to different versions in the standard library: + +.. list-table:: + :header-rows: 1 + + * - zipp + - stdlib + * - 3.9 + - 3.12 + * - 3.5 + - 3.11 + * - 3.2 + - 3.10 + * - 3.3 ?? + - 3.9 + * - 1.0 + - 3.8 + + +Usage +===== + +Use ``zipp.Path`` in place of ``zipfile.Path`` on any Python. + +For Enterprise +============== + +Available as part of the Tidelift Subscription. + +This project and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use. + +`Learn more `_. + +Security Contact +================ + +To report a security vulnerability, please use the +`Tidelift security contact `_. +Tidelift will coordinate the fix and disclosure. \ No newline at end of file