Question: Are the licenses of sub dependencies considered?
fhg-isi opened this issue · 6 comments
According to
https://itnext.io/how-to-detect-unwanted-licenses-in-your-python-project-c78ebdeb51df
"Let's say you want to avoid GPL, if you would just look at your requirements you might miss some. For example, Pyiotools is launched under an MIT license, but it has 4 dependencies with GPL. Meaning you will have to replace those 4 packages before you can use Pyiotools without GPL."
=> Does licensecheck consider the nested requirements or only the top level requirements?
Yes, if you have poetry installed on the host system we take the output of poetry show
, which lists transitive dependencies
I see. So poetry needs to be installed and used in pyproject.toml. If I use hatchling and PEP631 it won't work.
a) Is there a way to determine the list of licenses with another tool, e.g. license_scanner
and feed it to LicenseCheck
?
Also see wagenrace/license_scanner#9
b) An alternative could be to ask the dependencies for their sub dependencies in getPackageInfoLocal
:
pkgMetadata.get_all('Requires-Dist')
and use that to determine the requirements iteratively.
To a): Example on how to combine license_scanner with LicenseCheck:
from licensecheck import formatter, get_deps
from licensecheck import license_matrix, packageinfo
from licensecheck.types import JOINS, License, PackageInfo
from license_scanner import get_all_licenses
from sys import exit
def main():
using = 'PEP631'
ignore_packages = []
fail_packages = []
ignore_licenses = ['Apache Software License', 'Zope Public License']
fail_licenses = []
is_using_license_scanner = True
if is_using_license_scanner:
licenses_from_license_scanner = get_all_licenses()
requirements = sum(licenses_from_license_scanner.values(), [])
else:
requirements = get_deps.getReqs(using)
project_license, dependencies = _license_and_dependencies(
using,
ignore_packages,
fail_packages,
ignore_licenses,
fail_licenses,
requirements
)
simple_format = formatter.formatMap['simple']
output = simple_format(project_license, sorted(dependencies))
print(output)
is_incompatible = any(not dependency.licenseCompat for dependency in dependencies)
exit_code = 1 if is_incompatible else 0
exit(exit_code)
def _license_and_dependencies(
using: str,
ignore_packages: list[str],
fail_packages: list[str],
ignore_licenses: list[str],
fail_licenses: list[str],
requirements: set[str] = None
) -> tuple[License, set[PackageInfo]]:
if requirements is None:
requirements = get_deps.getReqs(using)
project_license = _project_license()
packages = packageinfo.getPackages(requirements)
for package in packages:
_check_and_update_compatibility(
package,
project_license,
fail_licenses,
fail_packages,
ignore_licenses,
ignore_packages,
)
return project_license, packages
def _check_and_update_compatibility(
package,
project_license,
fail_licenses,
fail_packages,
ignore_licenses,
ignore_packages,
):
package_name = package.name.lower()
is_ignored_package = package_name in [package_name.lower() for package_name in ignore_packages]
is_failing_package = package_name in [package_name.lower() for package_name in fail_packages]
if is_ignored_package:
package.licenseCompat = True
elif is_failing_package:
package.licenseCompat = False
else:
package.licenseCompat = license_matrix.depCompatWMyLice(
project_license,
license_matrix.licenseType(package.license),
license_matrix.licenseType(JOINS.join(ignore_licenses)),
license_matrix.licenseType(JOINS.join(fail_licenses)),
)
return package
def _project_license():
project_license_text = packageinfo.getMyPackageLicense()
project_license = license_matrix.licenseType(project_license_text)[0]
return project_license
if __name__ == '__main__':
main()
fixed in 2023.2
Could you please comment on how you fixed this?
https://github.com/FHPythonUtils/LicenseCheck/blob/master/licensecheck/get_deps.py Line 97 provides implementation details
Hope this helps