Skip to content

Commit

Permalink
Merge pull request #150 from ClementPinard/master
Browse files Browse the repository at this point in the history
Add `--python` option
  • Loading branch information
raimon49 authored Apr 8, 2023
2 parents bd213a5 + 4129b76 commit 8b38914
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 1 deletion.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Dump the software license list of Python packages installed with pip.
* [Usage](#usage)
* [Command\-Line Options](#command-line-options)
* [Common options](#common-options)
* [Option: python](#option-python)
* [Option: from](#option-from)
* [Option: order](#option-order)
* [Option: format](#option-format)
Expand Down Expand Up @@ -97,6 +98,21 @@ Execute the command with your venv (or virtualenv) environment.

### Common options

#### Option: python

By default, this tools finds the packages from the environment pip-licenses is launched from, by searching in current python's `sys.path` folders. In the case you want to search for packages in an other environment (e.g. if you want to run pip-licenses from its own isolated environment), you can specify a path to a python executable. The packages will be searched for in the given python's `sys.path`, free of pip-licenses dependencies.

```bash
(venv) $ pip-licenses --with-system | grep pip
pip 22.3.1 MIT License
pip-licenses 4.1.0 MIT License
```

```bash
(venv) $ pip-licenses --python=</path/to/other/env>/bin/python --with-system | grep pip
pip 23.0.1 MIT License
```

#### Option: from

By default, this tool finds the license from [Trove Classifiers](https://pypi.org/classifiers/) or package Metadata. Some Python packages declare their license only in Trove Classifiers.
Expand Down
29 changes: 28 additions & 1 deletion piplicenses.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@

import argparse
import codecs
import os
import re
import subprocess
import sys
from collections import Counter
from enum import Enum, auto
Expand Down Expand Up @@ -194,7 +196,21 @@ def filter_string(item: str) -> str:

return pkg_info

pkgs = importlib_metadata.distributions()
def get_python_sys_path(executable: str) -> list[str]:
script = "import sys; print(' '.join(filter(bool, sys.path)))"
output = subprocess.run(
[executable, "-c", script],
capture_output=True,
env={**os.environ, "PYTHONPATH": "", "VIRTUAL_ENV": ""},
)
return output.stdout.decode().strip().split()

if args.python == sys.executable:
search_paths = sys.path
else:
search_paths = get_python_sys_path(args.python)

pkgs = importlib_metadata.distributions(path=search_paths)
ignore_pkgs_as_lower = [pkg.lower() for pkg in args.ignore_packages]
pkgs_as_lower = [pkg.lower() for pkg in args.packages]

Expand Down Expand Up @@ -785,6 +801,17 @@ def create_parser() -> CompatibleArgumentParser:
"-v", "--version", action="version", version="%(prog)s " + __version__
)

common_options.add_argument(
"--python",
type=str,
default=sys.executable,
metavar="PYTHON_EXEC",
help="R| path to python executable to search distributions from\n"
"Package will be searched in the selected python's sys.path\n"
"By default, will search packages for current env executable\n"
"(default: sys.executable)",
)

common_options.add_argument(
"--from",
dest="from_",
Expand Down
24 changes: 24 additions & 0 deletions test_piplicenses.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@

import copy
import email
import json
import re
import sys
import unittest
import venv
from enum import Enum, auto
from importlib.metadata import Distribution
from types import SimpleNamespace
from typing import TYPE_CHECKING, Any, List

import docutils.frontend
Expand Down Expand Up @@ -39,6 +42,7 @@
factory_styled_table_with_args,
find_license_from_classifier,
get_output_fields,
get_packages,
get_sortby,
output_colored,
save_if_needs,
Expand Down Expand Up @@ -780,6 +784,26 @@ def test_allow_only(monkeypatch) -> None:
)


def test_different_python() -> None:
import tempfile

class TempEnvBuild(venv.EnvBuilder):
def post_setup(self, context: SimpleNamespace) -> None:
self.context = context

with tempfile.TemporaryDirectory() as target_dir_path:
venv_builder = TempEnvBuild(with_pip=True)
venv_builder.create(str(target_dir_path))
python_exec = venv_builder.context.env_exe
python_arg = f"--python={python_exec}"
args = create_parser().parse_args([python_arg, "-s", "-f=json"])
pkgs = get_packages(args)
package_names = sorted(p["name"] for p in pkgs)
print(package_names)

assert package_names == ["pip", "setuptools"]


def test_fail_on(monkeypatch) -> None:
licenses = ("MIT license",)
allow_only_args = ["--fail-on={}".format(";".join(licenses))]
Expand Down

0 comments on commit 8b38914

Please sign in to comment.