1
|
|
|
"""Setup script. |
2
|
|
|
|
3
|
|
|
Run "python3 setup --help-commands" to list all available commands and their |
4
|
|
|
descriptions. |
5
|
|
|
""" |
6
|
|
|
import re |
7
|
|
|
import sys |
8
|
|
|
from abc import abstractmethod |
9
|
|
|
# Disabling checks due to https://github.com/PyCQA/pylint/issues/73 |
10
|
|
|
from distutils.command.clean import clean # pylint: disable=E0401,E0611 |
11
|
|
|
from subprocess import CalledProcessError, call, check_call |
12
|
|
|
|
13
|
|
|
from setuptools import Command, find_packages, setup |
14
|
|
|
|
15
|
|
|
|
16
|
|
|
class SimpleCommand(Command): |
17
|
|
|
"""Make Command implementation simpler.""" |
18
|
|
|
|
19
|
|
|
user_options = [] |
20
|
|
|
|
21
|
|
|
def __init__(self, *args, **kwargs): |
22
|
|
|
"""Store arguments so it's possible to call other commands later.""" |
23
|
|
|
super().__init__(*args, **kwargs) |
24
|
|
|
self._args = args |
25
|
|
|
self._kwargs = kwargs |
26
|
|
|
|
27
|
|
|
@abstractmethod |
28
|
|
|
def run(self): |
29
|
|
|
"""Run when command is invoked. |
30
|
|
|
|
31
|
|
|
Use *call* instead of *check_call* to ignore failures. |
32
|
|
|
""" |
33
|
|
|
|
34
|
|
|
def initialize_options(self): |
35
|
|
|
"""Set default values for options.""" |
36
|
|
|
|
37
|
|
|
def finalize_options(self): |
38
|
|
|
"""Post-process options.""" |
39
|
|
|
|
40
|
|
|
|
41
|
|
|
# pylint: disable=attribute-defined-outside-init, abstract-method |
42
|
|
|
class TestCommand(Command): |
43
|
|
|
"""Test tags decorators.""" |
44
|
|
|
|
45
|
|
|
user_options = [ |
46
|
|
|
("k=", None, "Specify a pytest -k expression."), |
47
|
|
|
] |
48
|
|
|
|
49
|
|
|
def get_args(self): |
50
|
|
|
"""Return args to be used in test command.""" |
51
|
|
|
if self.k: |
52
|
|
|
return f"-k '{self.k}'" |
53
|
|
|
return "" |
54
|
|
|
|
55
|
|
|
def initialize_options(self): |
56
|
|
|
"""Set default size and type args.""" |
57
|
|
|
self.k = "" |
58
|
|
|
|
59
|
|
|
def finalize_options(self): |
60
|
|
|
"""Post-process.""" |
61
|
|
|
pass |
62
|
|
|
|
63
|
|
|
|
64
|
|
|
class Cleaner(clean): |
65
|
|
|
"""Custom clean command to tidy up the project root.""" |
66
|
|
|
|
67
|
|
|
description = 'clean build, dist, pyc and egg from package and docs' |
68
|
|
|
|
69
|
|
|
def run(self): |
70
|
|
|
"""Clean build, dist, pyc and egg from package and docs.""" |
71
|
|
|
super().run() |
72
|
|
|
call('rm -vrf ./build ./dist ./*.egg-info', shell=True) |
73
|
|
|
call('find . -name __pycache__ -type d | xargs rm -rf', shell=True) |
74
|
|
|
call('test -d docs && make -C docs/ clean', shell=True) |
75
|
|
|
|
76
|
|
|
|
77
|
|
|
class Test(TestCommand): |
78
|
|
|
"""Run all tests.""" |
79
|
|
|
|
80
|
|
|
description = "run tests and display results" |
81
|
|
|
|
82
|
|
|
def run(self): |
83
|
|
|
"""Run tests.""" |
84
|
|
|
cmd = f"python3 -m pytest tests/ {self.get_args()}" |
85
|
|
|
try: |
86
|
|
|
check_call(cmd, shell=True) |
87
|
|
|
except CalledProcessError as exc: |
88
|
|
|
print(exc) |
89
|
|
|
print('Unit tests failed. Fix the errors above and try again.') |
90
|
|
|
sys.exit(-1) |
91
|
|
|
|
92
|
|
|
|
93
|
|
|
class TestCoverage(Test): |
94
|
|
|
"""Display test coverage.""" |
95
|
|
|
|
96
|
|
|
description = "run tests and display code coverage" |
97
|
|
|
|
98
|
|
|
def run(self): |
99
|
|
|
"""Run tests quietly and display coverage report.""" |
100
|
|
|
cmd = f"python3 -m pytest --cov=. tests/ {self.get_args()}" |
101
|
|
|
try: |
102
|
|
|
check_call(cmd, shell=True) |
103
|
|
|
except CalledProcessError as exc: |
104
|
|
|
print(exc) |
105
|
|
|
print('Coverage tests failed. Fix the errors above and try again.') |
106
|
|
|
sys.exit(-1) |
107
|
|
|
|
108
|
|
|
|
109
|
|
|
class Linter(SimpleCommand): |
110
|
|
|
"""Code linters.""" |
111
|
|
|
|
112
|
|
|
description = 'lint Python source code' |
113
|
|
|
|
114
|
|
|
def run(self): |
115
|
|
|
"""Run yala.""" |
116
|
|
|
print('Yala is running. It may take several seconds...') |
117
|
|
|
try: |
118
|
|
|
check_call('yala setup.py tests kytos', shell=True) |
119
|
|
|
print('No linter error found.') |
120
|
|
|
except CalledProcessError: |
121
|
|
|
print('Linter check failed. Fix the error(s) above and try again.') |
122
|
|
|
sys.exit(-1) |
123
|
|
|
|
124
|
|
|
|
125
|
|
|
# We are parsing the metadata file as if it was a text file because if we |
126
|
|
|
# import it as a python module, necessarily the kytos.utils module would be |
127
|
|
|
# initialized. |
128
|
|
|
META_FILE = open("kytos/utils/metadata.py").read() |
129
|
|
|
METADATA = dict(re.findall(r"(__[a-z]+__)\s*=\s*'([^']+)'", META_FILE)) |
130
|
|
|
|
131
|
|
|
setup(name='kytos-utils', |
132
|
|
|
version=METADATA.get('__version__'), |
133
|
|
|
description=METADATA.get('__description__'), |
134
|
|
|
long_description=open("README.rst", "r").read(), |
135
|
|
|
url=METADATA.get('__url__'), |
136
|
|
|
author=METADATA.get('__author__'), |
137
|
|
|
author_email=METADATA.get('__author_email__'), |
138
|
|
|
license=METADATA.get('__license__'), |
139
|
|
|
test_suite='tests', |
140
|
|
|
include_package_data=True, |
141
|
|
|
scripts=['bin/kytos'], |
142
|
|
|
install_requires=[line.strip() |
143
|
|
|
for line in open("requirements/run.txt").readlines() |
144
|
|
|
if not line.startswith('#')], |
145
|
|
|
extras_require={'dev': ['pip-tools', 'pytest==7.0.0', |
146
|
|
|
'pytest-cov==3.0.0', 'coverage', 'yala', 'tox']}, |
147
|
|
|
packages=find_packages(exclude=['tests']), |
148
|
|
|
cmdclass={ |
149
|
|
|
'clean': Cleaner, |
150
|
|
|
'coverage': TestCoverage, |
151
|
|
|
'lint': Linter, |
152
|
|
|
'test': Test |
153
|
|
|
}, |
154
|
|
|
zip_safe=False) |
155
|
|
|
|