Passed
Push — master ( 5284e2...04dd9d )
by Vinicius
01:31 queued 13s
created

setup.Linter.run()   A

Complexity

Conditions 2

Size

Total Lines 9
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 8
nop 1
dl 0
loc 9
rs 10
c 0
b 0
f 0
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