From 46ba1a714b2176266b2b33fdcb61e1b2ed40cfc4 Mon Sep 17 00:00:00 2001 From: Damien Accorsi Date: Thu, 11 Oct 2018 15:16:45 +0200 Subject: [PATCH 1/9] implement --format-json JSON option. It's usefull for post-processing pip-licenses result --- README.md | 27 +++++++++++++++++++++++++++ piplicenses.py | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c0cf11c..09094b5 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ Dump the software license list of Python packages installed with pip. * [Option: format\-rst](#option-format-rst) * [Option: format\-confluence](#option-format-confluence) * [Option: format\-html](#option-format-html) + * [Option: format\-json](#option-format-json) * [More Information](#more-information) * [License](#license) * [Dependencies](#dependencies) @@ -230,6 +231,32 @@ When executed with the `--format-html` option, you can output list in HTML table ``` +### Option: format-json + +When executed with the `--format-json` option, you can output list in JSON format +easily allowing post-processing + +```json +[ + { + "License": "UNKNOWN", + "Version": "0.24", + "Author": "Armin Ronacher", + "Name": "itsdangerous", + "URL": "http://github.com/mitsuhiko/itsdangerous" + }, + { + "License": "MIT", + "Version": "2018.5", + "Author": "Stuart Bishop", + "Name": "pytz", + "URL": "http://pythonhosted.org/pytz" + } +] + +``` + + ### More Information Other, please make sure to execute the `--help` option. diff --git a/piplicenses.py b/piplicenses.py index 6928d34..97d2489 100644 --- a/piplicenses.py +++ b/piplicenses.py @@ -140,12 +140,39 @@ def get_pkg_info(pkg): return table +class JsonPrettyTable(PrettyTable): + """PrettyTable-like class exporting to JSON""" + + def _format_row(self, row, options): + resrow = {} + for (field, value) in zip(self._field_names, row): + 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) + + def factory_styled_table_with_args(args): table = PrettyTable() table.field_names = FIELD_NAMES table.align = 'l' table.border = (args.format_markdown or args.format_rst or - args.format_confluence) + args.format_confluence or args.format_json) table.header = True if args.format_markdown: @@ -157,6 +184,9 @@ def factory_styled_table_with_args(args): elif args.format_confluence: table.junction_char = '|' table.hrules = RULE_NONE + elif args.format_json: + table = JsonPrettyTable(table.field_names) + return table @@ -260,6 +290,10 @@ def create_parser(): action='store_true', default=False, help='dump as html style') + parser.add_argument('--format-json', + action='store_true', + default=False, + help='dump as json') return parser From 8e0ada8214e60ea9b29ab6def0c8bc66ee313f27 Mon Sep 17 00:00:00 2001 From: Damien Accorsi Date: Thu, 11 Oct 2018 16:27:07 +0200 Subject: [PATCH 2/9] fixes pep8 --- piplicenses.py | 1 - 1 file changed, 1 deletion(-) diff --git a/piplicenses.py b/piplicenses.py index 97d2489..8496ada 100644 --- a/piplicenses.py +++ b/piplicenses.py @@ -187,7 +187,6 @@ def factory_styled_table_with_args(args): elif args.format_json: table = JsonPrettyTable(table.field_names) - return table From 74b8a7db59dd96bee550c8e0a1f844f050836f94 Mon Sep 17 00:00:00 2001 From: raimon Date: Fri, 12 Oct 2018 22:42:50 +0900 Subject: [PATCH 3/9] Activate inherited "fields" option --- piplicenses.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/piplicenses.py b/piplicenses.py index 8496ada..ec38b5c 100644 --- a/piplicenses.py +++ b/piplicenses.py @@ -146,6 +146,9 @@ class JsonPrettyTable(PrettyTable): 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 From 962444741a0f1f1d901e72177d330824763ec9f7 Mon Sep 17 00:00:00 2001 From: raimon Date: Fri, 12 Oct 2018 22:53:13 +0900 Subject: [PATCH 4/9] Keep sorted keys on output with JSON --- piplicenses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/piplicenses.py b/piplicenses.py index ec38b5c..79e3c01 100644 --- a/piplicenses.py +++ b/piplicenses.py @@ -167,7 +167,7 @@ def get_string(self, **kwargs): for row in formatted_rows: lines.append(row) - return json.dumps(lines, indent=2) + return json.dumps(lines, indent=2, sort_keys=True) def factory_styled_table_with_args(args): From 9202f506ab0b190be92a576a22c36dc55b328d2e Mon Sep 17 00:00:00 2001 From: raimon Date: Fri, 12 Oct 2018 23:02:14 +0900 Subject: [PATCH 5/9] Cover new code with test --- test_piplicenses.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test_piplicenses.py b/test_piplicenses.py index ff9bbe7..8bd03b6 100644 --- a/test_piplicenses.py +++ b/test_piplicenses.py @@ -224,5 +224,13 @@ def test_format_html(self): self.assertIn('', output_string) + def test_format_json(self): + format_json_args = ['--format-json', '--with-authors'] + args = self.parser.parse_args(format_json_args) + output_string = create_output_string(args) + + self.assertIn('"Author":', output_string) + self.assertNotIn('"URL":', output_string) + def tearDown(self): pass From d14663461920cf96edea1669f0425e030fa3bada Mon Sep 17 00:00:00 2001 From: raimon Date: Fri, 12 Oct 2018 23:02:32 +0900 Subject: [PATCH 6/9] Follow the latest implementation of the document --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 09094b5..19658c1 100644 --- a/README.md +++ b/README.md @@ -239,18 +239,18 @@ easily allowing post-processing ```json [ { - "License": "UNKNOWN", - "Version": "0.24", - "Author": "Armin Ronacher", - "Name": "itsdangerous", - "URL": "http://github.com/mitsuhiko/itsdangerous" + "Author": "Django Software Foundation", + "License": "BSD", + "Name": "Django", + "URL": "https://www.djangoproject.com/", + "Version": "2.0.2" }, { - "License": "MIT", - "Version": "2018.5", "Author": "Stuart Bishop", + "License": "MIT", "Name": "pytz", - "URL": "http://pythonhosted.org/pytz" + "URL": "http://pythonhosted.org/pytz", + "Version": "2017.3" } ] From d4d8d3f421403bbb1b9ff1a4f26b119e52380262 Mon Sep 17 00:00:00 2001 From: raimon Date: Fri, 12 Oct 2018 23:05:09 +0900 Subject: [PATCH 7/9] Dropped support Python 3.3 Supported platforms: * PY27 * PY34 * PY35 * PY36 * PY37 --- .travis.yml | 2 +- setup.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index c2d232d..b61a527 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,10 @@ language: python python: - "2.7" - - "3.3" - "3.4" - "3.5" - "3.6" + - "3.7-dev" install: - pip install -r dev-requirements.txt script: diff --git a/setup.py b/setup.py index 432a973..90d2d03 100644 --- a/setup.py +++ b/setup.py @@ -81,16 +81,17 @@ def read_file(filename): 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', 'Topic :: System :: Systems Administration', 'Topic :: System :: System Shells', ], keywords='pip pypi package license check', py_modules=['piplicenses'], license=LICENSE, + python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*', install_requires=['PTable'], setup_requires=[ 'pytest-runner', From 718e25566f5bc758ce7f3e490e9b3f9b21bf1b24 Mon Sep 17 00:00:00 2001 From: raimon Date: Fri, 12 Oct 2018 23:20:16 +0900 Subject: [PATCH 8/9] Bump version to 1.8.0 --- CHANGELOG.md | 5 +++++ piplicenses.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 99ecb62..b4fabd5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ## CHANGELOG +### 1.8.0 + +* Implement new option `--format-json` +* Dropped support Python 3.3 + ### 1.7.1 * Fix bug diff --git a/piplicenses.py b/piplicenses.py index 79e3c01..4d8d988 100644 --- a/piplicenses.py +++ b/piplicenses.py @@ -42,7 +42,7 @@ HEADER as RULE_HEADER, NONE as RULE_NONE) __pkgname__ = 'pip-licenses' -__version__ = '1.7.1' +__version__ = '1.8.0' __author__ = 'raimon' __license__ = 'MIT License' __summary__ = ('Dump the software license list of ' From 98055b95734f5eda6d2a8e76ddbae7143debcfa9 Mon Sep 17 00:00:00 2001 From: raimon Date: Fri, 12 Oct 2018 23:30:59 +0900 Subject: [PATCH 9/9] Update dependencies for development --- dev-requirements.txt | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/dev-requirements.txt b/dev-requirements.txt index ef355f7..88d005f 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -4,37 +4,46 @@ # # pip-compile --output-file dev-requirements.txt dev-requirements.in # -apipkg==1.4 # via execnet -atomicwrites==1.1.5 # via pytest -attrs==18.1.0 # via pytest -autopep8==1.3.5 -certifi==2018.4.16 # via requests +apipkg==1.5 # via execnet +atomicwrites==1.2.1 # via pytest +attrs==18.2.0 # via pytest +autopep8==1.4 +bleach==3.0.2 # via readme-renderer +certifi==2018.8.24 # via requests +cffi==1.11.5 # via cmarkgfm chardet==3.0.4 # via requests -click==6.7 # via pip-tools +click==7.0 # via pip-tools +cmarkgfm==0.4.2 # via readme-renderer codecov==2.0.15 coverage==4.5.1 # via codecov, pytest-cov docutils==0.14 execnet==1.5.0 # via pytest-cache -first==2.0.1 # via pip-tools funcsigs==1.0.2 # via pytest +future==0.16.0 # via readme-renderer idna==2.7 # via requests -more-itertools==4.2.0 # via pytest -pip-tools==2.0.2 +more-itertools==4.3.0 # via pytest +pathlib2==2.3.2 # via pytest +pip-tools==3.1.0 pkginfo==1.4.2 # via twine -pluggy==0.6.0 # via pytest +pluggy==0.7.1 # via pytest ptable==0.9.2 -py==1.5.4 # via pytest +py==1.7.0 # via pytest pycodestyle==2.4.0 # via autopep8, pytest-pycodestyle +pycparser==2.19 # via cffi +pygments==2.2.0 # via readme-renderer pypandoc==1.4 pytest-cache==1.0 # via pytest-pycodestyle -pytest-cov==2.5.1 +pytest-cov==2.6.0 pytest-pycodestyle==1.0.6 pytest-runner==4.2 -pytest==3.6.2 # via pytest-cache, pytest-cov, pytest-pycodestyle +pytest==3.8.2 # via pytest-cache, pytest-cov, pytest-pycodestyle +readme-renderer==22.0 # via twine requests-toolbelt==0.8.0 # via twine requests==2.19.1 # via codecov, requests-toolbelt, twine -six==1.11.0 # via more-itertools, pip-tools, pytest -tqdm==4.23.4 # via twine -twine==1.11.0 +scandir==1.9.0 # via pathlib2 +six==1.11.0 # via bleach, more-itertools, pathlib2, pip-tools, pytest, readme-renderer +tqdm==4.26.0 # via twine +twine==1.12.1 urllib3==1.23 # via requests -wheel==0.31.1 +webencodings==0.5.1 # via bleach +wheel==0.32.1