Codebase list pyct / ff5d119
Added version reporting console command (#82) * Add a script `report.py` for generating reports to the pyct repo * Add a console command `report` for generating reports * Adding tests for version reporting kbowen authored 3 years ago GitHub committed 3 years ago
7 changed file(s) with 171 addition(s) and 5 deletion(s). Raw diff Collapse all Expand all
141141 setup.py is run. The way this works is likely to change in the near
142142 future, but is provided here as the first step towards
143143 unifying/simplifying the maintenance of a number of pyviz projects.
144
145 ## pyct report
146
147 Provides a way to check the package versions in the current environment using:
148 1. A console script (entry point): `pyct report [packages]`, or
149 2. A python function: `import pyct; pyct.report(packages)`
150
151 The python function can be particularly useful for e.g. jupyter notebook users, since it is the packages in the current kernel that we usually care about (not those in the environment from which jupyter notebook server/lab was launched).
152
153 Note that `packages` above can include the name of any Python package (returning the `__version__`), along with the special cases `python` or `conda` (returning the version of the command-line tool) or `system` (returning the OS version).
2929 {% for dep in sdata['extras_require']['tests'] %}
3030 - "{{ dep }}"
3131 {% endfor %}
32 commands:
33 - pytest pyct
34 - pyct --help
35 - pyct --version
36 - pyct report --help
37 - pyct report pyct python
3238
3339 about:
3440 home: {{ sdata['url'] }}
22 # -*- coding: utf-8 -*-
33
44 from __future__ import print_function, absolute_import, division
5 from . import __version__
6 from .report import report
57
68 import os
79 import importlib
7678 import zipfile
7779
7880 import yaml
81
7982 try:
8083 import requests
8184 except ImportError:
450453 args = parser.parse_args()
451454 args.func(args) if hasattr(args,'func') else parser.error("must supply command to run")
452455
456 def main():
457 parser = argparse.ArgumentParser(description="Commands relating to versioning")
458 parser.add_argument('--version', action='version', version='%(prog)s '+__version__)
459
460 subparsers = parser.add_subparsers(title='available commands')
461
462 report_parser = subparsers.add_parser('report', help=inspect.getdoc(report))
463 report_parser.set_defaults(func=report)
464 report_parser.add_argument('packages',metavar='package',type=str,nargs='+',
465 help='name of package')
466
467 args = parser.parse_args()
468
469 if hasattr(args,'func'):
470 args.func(*args.packages)
471 else:
472 parser.error("must supply command to run")
0 #!/usr/bin/env python
1 # Import and print the library version and filesystem location for each Python package or shell command specified
2 #
3 # bash usage: $ report numpy pandas python conda
4 # python usage: >>> from report import report; report("numpy","pandas","python","conda")
5
6 from __future__ import print_function
7 import os.path, importlib, subprocess, platform, sys
8
9 def report(*packages):
10 """Import and print location and version information for specified Python packages"""
11 accepted_commands = ['python','conda']
12 for package in packages:
13 loc = "not installed in this environment"
14 ver = "unknown"
15
16 try:
17 module = importlib.import_module(package)
18 loc = os.path.dirname(module.__file__)
19
20 try:
21 ver = str(module.__version__)
22 except Exception:
23 pass
24
25 except (ImportError, ModuleNotFoundError):
26 if package in accepted_commands:
27 try:
28 # See if there is a command by that name and check its --version if so
29 try:
30 loc = subprocess.check_output(['command','-v', package]).decode().splitlines()[0].strip()
31 except:
32 # .exe in case powershell (otherwise wouldn't need it)
33 loc = subprocess.check_output(['where.exe', package]).decode().splitlines()[0].strip()
34 out = ""
35 try:
36 out = subprocess.check_output([package, '--version'], stderr=subprocess.STDOUT)
37 except subprocess.CalledProcessError as e:
38 out = e.output
39
40 # Assume first word in output with a period and digits is the version
41 for s in out.decode().split():
42 if '.' in s and str.isdigit(s[0]) and sum(str.isdigit(c) for c in s)>=2:
43 ver=s.strip()
44 break
45 except:
46 pass
47 elif package == 'system':
48 try:
49 ver = platform.platform(terse=True)
50 loc = "OS: " + platform.platform()
51 except Exception:
52 pass
53 else:
54 pass
55
56 print("{0:30} # {1}".format(package + "=" + ver,loc))
57
58
59 def main():
60 report(*(sys.argv[1:]))
61
62 if __name__ == "__main__":
63 main()
64
0 from unittest.mock import patch
1 from pyct.report import report
2
3 class TestModule:
4 __version__ = "1.9.3"
5 __file__ = "/mock/opt/anaconda3/envs/pyct/lib/python3.7/site-packages/param/__init__.py"
6
7 @patch("builtins.print")
8 @patch("importlib.import_module")
9 def test_report_gives_package_version(mock_import_module, mock_print):
10 module = TestModule()
11 mock_import_module.return_value = module
12
13 report("param")
14
15 mock_print.assert_called_with('param=1.9.3 # /mock/opt/anaconda3/envs/pyct/lib/python3.7/site-packages/param')
16
17 @patch("builtins.print")
18 @patch("subprocess.check_output")
19 def test_report_gives_conda_version(mock_check_output, mock_print):
20 mock_check_output.side_effect = [b'/mock/opt/anaconda3/condabin/conda\n', b'conda 4.8.3\n']
21
22 report("conda")
23
24 mock_print.assert_called_with("conda=4.8.3 # /mock/opt/anaconda3/condabin/conda")
25
26
27 @patch("builtins.print")
28 @patch("subprocess.check_output")
29 def test_report_gives_python_version(mock_check_output, mock_print):
30 mock_check_output.side_effect = [b'/mock/opt/anaconda3/envs/pyct/bin/python\n', b'Python 3.7.7\n']
31
32 report("python")
33
34 mock_print.assert_called_with("python=3.7.7 # /mock/opt/anaconda3/envs/pyct/bin/python")
35
36 @patch("builtins.print")
37 @patch("platform.platform")
38 def test_report_gives_system_version(mock_platform, mock_print):
39 mock_platform.side_effect = ["Darwin-19.2.0", "Darwin-19.2.0-x86_64-i386-64bit"]
40
41 report("system")
42
43 mock_print.assert_called_with("system=Darwin-19.2.0 # OS: Darwin-19.2.0-x86_64-i386-64bit")
44
45 @patch("builtins.print")
46 def test_unknown_package_output(mock_print):
47 report("fake_package")
48
49 mock_print.assert_called_with("fake_package=unknown # not installed in this environment")
7878 "setuptools",
7979 "param >=1.7.0",
8080 ]
81 },
82 entry_points = {
83 'console_scripts': [
84 'pyct=pyct.cmd:main',
85 ],
8186 }
8287 )
8388
00 [tox]
1 envlist = {py27,py37}-{flakes,cmd_examples,build_examples,all}-{default}-{dev,pkg}
1 envlist = {py27,py37}-{flakes,unit,cmd_examples,build_examples,all}-{default}-{dev,pkg}
22 build = wheel
33
44 [_flakes]
1616
1717 [_all]
1818 commands = {[_flakes]commands}
19 {[_unit]commands}
1920 {[_cmd_examples]commands}
2021 {[_build_examples]commands}
2122 deps = .[examples, tests]
2223
24 [_unit]
25 description = Run unit tests
26 deps = .[tests]
27 commands = pytest pyct
28 pyct --help
29 pyct --version
30 pyct report --help
31 pyct report pyct python
32
2333 [testenv]
2434 changedir = {envtmpdir}
2535
26 commands = cmd_examples: {[_cmd_examples]commands}
36 commands = unit: {[_unit]commands}
37 cmd_examples: {[_cmd_examples]commands}
2738 build_examples: {[_build_examples]commands}
2839 flakes: {[_flakes]commands}
2940 all: {[_all]commands}
3041
31 deps = cmd_examples: {[_cmd_examples]deps}
42 deps = unit: {[_unit]deps}
43 cmd_examples: {[_cmd_examples]deps}
3244 build_examples: {[_build_examples]deps}
3345 flakes: {[_flakes]deps}
3446 all: {[_all]deps}
4153 ignore = E,W
4254 include = *.py
4355 exclude = .git,__pycache__,.tox,.eggs,*.egg,doc,dist,build,_build,.ipynb_checkpoints,run_test.py
44
45