eric7/PipInterface/piplicenses.py

branch
eric7
changeset 9003
6bc210cd5726
parent 9002
31a7decd3393
child 9098
fb9351497cea
diff -r 31a7decd3393 -r 6bc210cd5726 eric7/PipInterface/piplicenses.py
--- a/eric7/PipInterface/piplicenses.py	Sun Mar 27 19:56:41 2022 +0200
+++ b/eric7/PipInterface/piplicenses.py	Mon Mar 28 18:13:15 2022 +0200
@@ -26,46 +26,47 @@
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 """
+
+#
+# Modified to be used within the eric-ide project.
+#
+# Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
 import argparse
 import codecs
 import glob
+import json
 import os
 import sys
 from collections import Counter
 from email import message_from_string
 from email.parser import FeedParser
 from enum import Enum, auto
-from functools import partial
 from typing import List, Optional, Sequence, Text
 
-try:
-    from pip._internal.utils.misc import get_installed_distributions
-except ImportError:  # pragma: no cover
+
+def get_installed_distributions(local_only=True, user_only=False):
     try:
-        from pip import get_installed_distributions
+        from pip._internal.metadata import get_environment
     except ImportError:
-        def get_installed_distributions():
-            from pip._internal.metadata import (
-                get_default_environment, get_environment,
-            )
-            from pip._internal.metadata.pkg_resources import (
-                Distribution as _Dist,
-            )
-            from pip._internal.utils.compat import stdlib_pkgs
+        # For backward compatibility with pip version 20.3.4
+        from pip._internal.utils import misc
+        return misc.get_installed_distributions(
+            local_only=local_only,
+            user_only=user_only
+        )
+    else:
+        from pip._internal.utils.compat import stdlib_pkgs
+        dists = get_environment(None).iter_installed_distributions(
+            local_only=local_only,
+            user_only=user_only,
+            skip=stdlib_pkgs,
+            include_editables=True,
+            editables_only=False,
+        )
+        return [d._dist for d in dists]
 
-            env = get_default_environment()
-            dists = env.iter_installed_distributions(
-                local_only=True,
-                skip=stdlib_pkgs,
-                include_editables=True,
-                editables_only=False,
-                user_only=False,
-            )
-            return [dist._dist for dist in dists]
-
-from prettytable import PrettyTable
-
-open = open  # allow monkey patching
 
 __pkgname__ = 'pip-licenses'
 __version__ = '3.5.3'
@@ -90,12 +91,6 @@
 )
 
 
-SUMMARY_FIELD_NAMES = (
-    'Count',
-    'License',
-)
-
-
 DEFAULT_OUTPUT_FIELDS = (
     'Name',
     'Version',
@@ -217,7 +212,10 @@
 
         return pkg_info
 
-    pkgs = get_installed_distributions()
+    pkgs = get_installed_distributions(
+        local_only=args.local_only,
+        user_only=args.user_only,
+    )
     ignore_pkgs_as_lower = [pkg.lower() for pkg in args.ignore_packages]
     pkgs_as_lower = [pkg.lower() for pkg in args.packages]
 
@@ -287,7 +285,6 @@
                     args.from_, pkg['license_classifier'], pkg['license'])
                 license_str = '; '.join(sorted(license_set))
                 row[field] = license_str
-##                row.append(license_str)
             elif field == 'License-Classifier':
                 row[field] = ('; '.join(sorted(pkg['license_classifier']))
                            or LICENSE_UNKNOWN)
@@ -300,160 +297,20 @@
     return licenses
 
 
-def create_summary_table(args: "CustomNamespace"):
+def create_summary_list(args: "CustomNamespace"):
     counts = Counter(
         '; '.join(sorted(select_license_by_source(
             args.from_, pkg['license_classifier'], pkg['license'])))
         for pkg in get_packages(args))
 
-    table = factory_styled_table_with_args(args, SUMMARY_FIELD_NAMES)
+    licenses = []
     for license, count in counts.items():
-        table.add_row([count, license])
-    return table
-
-
-class JsonTable():
-
-    def _format_row(self, row, options):
-        resrow = {}
-        for (field, value) in zip(self._field_names, row):
-            if field not in options["fields"]:
-                continue
-
-            resrow[field] = value
-
-        return resrow
-
-    def get_string(self, **kwargs):
-        # import included here in order to limit dependencies
-        # if not interested in JSON output,
-        # then the dependency is not required
-        import json
-
-        options = self._get_options(kwargs)
-        rows = self._get_rows(options)
-        formatted_rows = self._format_rows(rows, options)
-
-        lines = []
-        for row in formatted_rows:
-            lines.append(row)
-
-        return json.dumps(lines, indent=2, sort_keys=True)
-##
-##
-##class JsonLicenseFinderTable(JsonPrettyTable):
-##    def _format_row(self, row, options):
-##        resrow = {}
-##        for (field, value) in zip(self._field_names, row):
-##            if field == 'Name':
-##                resrow['name'] = value
-##
-##            if field == 'Version':
-##                resrow['version'] = value
-##
-##            if field == 'License':
-##                resrow['licenses'] = [value]
-##
-##        return resrow
-##
-##    def get_string(self, **kwargs):
-##        # import included here in order to limit dependencies
-##        # if not interested in JSON output,
-##        # then the dependency is not required
-##        import json
-##
-##        options = self._get_options(kwargs)
-##        rows = self._get_rows(options)
-##        formatted_rows = self._format_rows(rows, options)
-##
-##        lines = []
-##        for row in formatted_rows:
-##            lines.append(row)
-##
-##        return json.dumps(lines, sort_keys=True)
-##
-##
-##class CSVPrettyTable(PrettyTable):
-##    """PrettyTable-like class exporting to CSV"""
-##
-##    def get_string(self, **kwargs):
-##
-##        def esc_quotes(val):
-##            """
-##            Meta-escaping double quotes
-##            https://tools.ietf.org/html/rfc4180
-##            """
-##            try:
-##                return val.replace('"', '""')
-##            except UnicodeDecodeError:  # pragma: no cover
-##                return val.decode('utf-8').replace('"', '""')
-##            except UnicodeEncodeError:  # pragma: no cover
-##                return val.encode('unicode_escape').replace('"', '""')
-##
-##        options = self._get_options(kwargs)
-##        rows = self._get_rows(options)
-##        formatted_rows = self._format_rows(rows, options)
-##
-##        lines = []
-##        formatted_header = ','.join(['"%s"' % (esc_quotes(val), )
-##                                     for val in self._field_names])
-##        lines.append(formatted_header)
-##        for row in formatted_rows:
-##            formatted_row = ','.join(['"%s"' % (esc_quotes(val), )
-##                                      for val in row])
-##            lines.append(formatted_row)
-##
-##        return '\n'.join(lines)
-##
-##
-##class PlainVerticalTable(PrettyTable):
-##    """PrettyTable for outputting to a simple non-column based style.
-##
-##    When used with --with-license-file, this style is similar to the default
-##    style generated from Angular CLI's --extractLicenses flag.
-##    """
-##
-##    def get_string(self, **kwargs):
-##        options = self._get_options(kwargs)
-##        rows = self._get_rows(options)
-##
-##        output = ''
-##        for row in rows:
-##            for v in row:
-##                output += '{}\n'.format(v)
-##            output += '\n'
-##
-##        return output
-##
-##
-def factory_styled_table_with_args(
-        args: "CustomNamespace", output_fields=DEFAULT_OUTPUT_FIELDS):
-    table = PrettyTable()
-    table.field_names = output_fields
-    table.align = 'l'
-    table.border = args.format_ in (FormatArg.MARKDOWN, FormatArg.RST,
-                                    FormatArg.CONFLUENCE, FormatArg.JSON)
-    table.header = True
-
-    if args.format_ == FormatArg.MARKDOWN:
-        table.junction_char = '|'
-        table.hrules = RULE_HEADER
-    elif args.format_ == FormatArg.RST:
-        table.junction_char = '+'
-        table.hrules = RULE_ALL
-    elif args.format_ == FormatArg.CONFLUENCE:
-        table.junction_char = '|'
-        table.hrules = RULE_NONE
-    elif args.format_ == FormatArg.JSON:
-        table = JsonPrettyTable(table.field_names)
-    elif args.format_ == FormatArg.JSON_LICENSE_FINDER:
-        table = JsonLicenseFinderTable(table.field_names)
-    elif args.format_ == FormatArg.CSV:
-        table = CSVPrettyTable(table.field_names)
-    elif args.format_ == FormatArg.PLAIN_VERTICAL:
-        table = PlainVerticalTable(table.field_names)
-
-    return table
+        licenses.append({
+            "Count": count,
+            "License": license,
+        })
+    
+    return licenses
 
 
 def find_license_from_classifier(message):
@@ -513,56 +370,15 @@
     return output_fields
 
 
-def get_sortby(args: "CustomNamespace"):
-    if args.summary and args.order == OrderArg.COUNT:
-        return 'Count'
-    elif args.summary or args.order == OrderArg.LICENSE:
-        return 'License'
-    elif args.order == OrderArg.NAME:
-        return 'Name'
-    elif args.order == OrderArg.AUTHOR and args.with_authors:
-        return 'Author'
-    elif args.order == OrderArg.URL and args.with_urls:
-        return 'URL'
-
-    return 'Name'
-
-
 def create_output_string(args: "CustomNamespace"):
     output_fields = get_output_fields(args)
 
     if args.summary:
-        table = create_summary_table(args)
+        licenses = create_summary_list(args)
     else:
-        table = create_licenses_list(args, output_fields)
+        licenses = create_licenses_list(args, output_fields)
     
-    return json.dumps(table)
-##
-##    sortby = get_sortby(args)
-##
-##    if args.format_ == FormatArg.HTML:
-##        return table.get_html_string(fields=output_fields, sortby=sortby)
-##    else:
-##        return table.get_string(fields=output_fields, sortby=sortby)
-##
-##
-##def create_warn_string(args: "CustomNamespace"):
-##    warn_messages = []
-##    warn = partial(output_colored, '33')
-##
-##    if args.with_license_file and not args.format_ == FormatArg.JSON:
-##        message = warn(('Due to the length of these fields, this option is '
-##                        'best paired with --format=json.'))
-##        warn_messages.append(message)
-##
-##    if args.summary and (args.with_authors or args.with_urls):
-##        message = warn(('When using this option, only --order=count or '
-##                        '--order=license has an effect for the --order '
-##                        'option. And using --with-authors and --with-urls '
-##                        'will be ignored.'))
-##        warn_messages.append(message)
-##
-##    return '\n'.join(warn_messages)
+    return json.dumps(licenses)
 
 
 class CustomHelpFormatter(argparse.HelpFormatter):  # pragma: no cover
@@ -606,8 +422,9 @@
 class CustomNamespace(argparse.Namespace):
     from_: "FromArg"
     order: "OrderArg"
-    format_: "FormatArg"
     summary: bool
+    local_only: bool
+    user_only:bool
     output_file: str
     ignore_packages: List[str]
     packages: List[str]
@@ -673,18 +490,6 @@
     URL = U = auto()
 
 
-class FormatArg(NoValueEnum):
-    PLAIN = P = auto()
-    PLAIN_VERTICAL = auto()
-    MARKDOWN = MD = M = auto()
-    RST = REST = R = auto()
-    CONFLUENCE = C = auto()
-    HTML = H = auto()
-    JSON = J = auto()
-    JSON_LICENSE_FINDER = JLF = auto()
-    CSV = auto()
-
-
 def value_to_enum_key(value: str) -> str:
     return value.replace('-', '_').upper()
 
@@ -701,7 +506,6 @@
 MAP_DEST_TO_ENUM = {
     'from_': FromArg,
     'order': OrderArg,
-    'format_': FormatArg,
 }
 
 
@@ -749,17 +553,6 @@
              '"name", "license", "author", "url"\n'
              '(default: %(default)s)')
     common_options.add_argument(
-        '-f', '--format',
-        dest='format_',
-        action=SelectAction, type=str,
-        default=FormatArg.PLAIN, metavar='STYLE',
-        choices=choices_from_enum(FormatArg),
-        help='R|dump as set format style\n'
-             '"plain", "plain-vertical" "markdown", "rst", \n'
-             '"confluence", "html", "json", \n'
-             '"json-license-finder",  "csv"\n'
-             '(default: %(default)s)')
-    common_options.add_argument(
         '--summary',
         action='store_true',
         default=False,
@@ -780,6 +573,17 @@
         nargs='+', metavar='PKG',
         default=[],
         help='only include selected packages in output')
+    common_options.add_argument(
+        '--local-only',
+        action='store_true',
+        default=False,
+        help='include only local packages')
+    common_options.add_argument(
+        '--user-only',
+        action='store_true',
+        default=False,
+        help='include only packages of the user site dir')
+    
     format_options.add_argument(
         '-s', '--with-system',
         action='store_true',
@@ -845,33 +649,6 @@
              'of the licenses not in the semicolon-separated list')
 
     return parser
-##
-##
-##def output_colored(code, text, is_bold=False):
-##    """
-##    Create function to output with color sequence
-##    """
-##    if is_bold:
-##        code = '1;%s' % code
-##
-##    return '\033[%sm%s\033[0m' % (code, text)
-##
-##
-##def save_if_needs(output_file, output_string):
-##    """
-##    Save to path given by args
-##    """
-##    if output_file is None:
-##        return
-##
-##    try:
-##        with open(output_file, 'w', encoding='utf-8') as f:
-##            f.write(output_string)
-##        sys.stdout.write('created path: ' + output_file + '\n')
-##        sys.exit(0)
-##    except IOError:
-##        sys.stderr.write('check path: --output-file\n')
-##        sys.exit(1)
 
 
 def main():  # pragma: no cover
@@ -880,13 +657,7 @@
 
     output_string = create_output_string(args)
 
-##    output_file = args.output_file
-##    save_if_needs(output_file, output_string)
-##
     print(output_string)
-##    warn_string = create_warn_string(args)
-##    if warn_string:
-##        print(warn_string, file=sys.stderr)
 
 
 if __name__ == '__main__':  # pragma: no cover

eric ide

mercurial